Improve MappingEntryBuilder to convert LCAF to extension address

Change-Id: I88e5c7d898f3fe2e55406a7af30979e95b90e654
diff --git a/drivers/lisp/src/main/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreter.java b/drivers/lisp/src/main/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreter.java
index e29d8ef..c4040a7 100644
--- a/drivers/lisp/src/main/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreter.java
+++ b/drivers/lisp/src/main/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreter.java
@@ -110,9 +110,11 @@
             LispAfiAddress ipv4 = mapping2afi(listAddress.getIpv4());
             LispAfiAddress ipv6 = mapping2afi(listAddress.getIpv6());
 
-            List<LispAfiAddress> addresses = ImmutableList.of(ipv4, ipv6);
-
-            return new LispListLcafAddress(addresses);
+            if (ipv4 != null && ipv6 != null) {
+                return new LispListLcafAddress(ImmutableList.of(ipv4, ipv6));
+            } else {
+                return new LispListLcafAddress(ImmutableList.of());
+            }
         }
 
         if (type.equals(SEGMENT_ADDRESS.type())) {
diff --git a/drivers/lisp/src/main/resources/lisp-drivers.xml b/drivers/lisp/src/main/resources/lisp-drivers.xml
index 3595071..0e66038 100644
--- a/drivers/lisp/src/main/resources/lisp-drivers.xml
+++ b/drivers/lisp/src/main/resources/lisp-drivers.xml
@@ -15,7 +15,18 @@
   ~ limitations under the License.
   -->
 <drivers>
-    <driver name="lisp-sdn" manufacturer="LISP" hwVersion="LISP" swVersion="1.0">
+    <driver name="default"
+            manufacturer="IETF" hwVersion="LISP Reference Router" swVersion=".*">
+        <behaviour api="org.onosproject.lisp.ctl.ExtensionMappingAddressInterpreter"
+                   impl="org.onosproject.drivers.lisp.extensions.LispExtensionMappingAddressInterpreter"/>
+        <behaviour api="org.onosproject.lisp.ctl.ExtensionMappingAddressResolver"
+                   impl="org.onosproject.drivers.lisp.extensions.LispExtensionMappingAddressInterpreter"/>
+    </driver>
+
+    <!-- OpenLISP software router
+         https://github.com/lip6-lisp/data-plane -->
+    <driver name="openlisp" extends="default"
+            manufacturer="LIP6" hwVersion="OpenLISP Router" swVersion=".*">
     </driver>
 </drivers>
 
diff --git a/providers/lisp/device/src/main/java/org/onosproject/provider/lisp/device/impl/LispDeviceProvider.java b/providers/lisp/device/src/main/java/org/onosproject/provider/lisp/device/impl/LispDeviceProvider.java
index fa032cc..bcab1bd 100644
--- a/providers/lisp/device/src/main/java/org/onosproject/provider/lisp/device/impl/LispDeviceProvider.java
+++ b/providers/lisp/device/src/main/java/org/onosproject/provider/lisp/device/impl/LispDeviceProvider.java
@@ -73,7 +73,10 @@
     private static final String SCHEME_NAME = "lisp";
     private static final String DEVICE_PROVIDER_PACKAGE = "org.onosproject.lisp.provider.device";
 
-    private static final String UNKNOWN = "unknown";
+    private static final String MANUFACTURER = "IETF";
+    private static final String HARDWARE_VERSION = "LISP Reference Router";
+    private static final String SOFTWARE_VERSION = "1.0";
+    private static final String SERIAL_NUMBER = "unknown";
     private static final String IS_NULL_MSG = "LISP device info is null";
     private static final String IPADDRESS = "ipaddress";
     private static final String LISP = "lisp";
@@ -147,8 +150,8 @@
         DeviceDescription deviceDescription = new DefaultDeviceDescription(
                 deviceId.uri(),
                 Device.Type.ROUTER,
-                UNKNOWN, UNKNOWN,
-                UNKNOWN, UNKNOWN,
+                MANUFACTURER, HARDWARE_VERSION,
+                SOFTWARE_VERSION, SERIAL_NUMBER,
                 cid, false,
                 annotations);
         if (deviceService.getDevice(deviceId) == null) {
diff --git a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/impl/LispMappingProvider.java b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/impl/LispMappingProvider.java
index 3cf1e3b..0eacc60 100644
--- a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/impl/LispMappingProvider.java
+++ b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/impl/LispMappingProvider.java
@@ -34,6 +34,7 @@
 import org.onosproject.mapping.MappingProviderService;
 import org.onosproject.mapping.MappingStore;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.provider.lisp.mapping.util.MappingEntryBuilder;
@@ -59,6 +60,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected MappingProviderRegistry providerRegistry;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
     protected MappingProviderService providerService;
 
     private static final String SCHEME_NAME = "lisp";
@@ -166,7 +170,8 @@
                                      List<LispMapRecord> records,
                                      MappingStore.Type type) {
             records.forEach(r -> {
-                MappingEntry me = new MappingEntryBuilder(deviceId, r).build();
+                MappingEntry me =
+                        new MappingEntryBuilder(deviceId, r, deviceService).build();
                 providerService.mappingAdded(me, type);
             });
         }
diff --git a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
index 1a0ed09..9f78e80 100644
--- a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
+++ b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
@@ -19,6 +19,7 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onosproject.lisp.ctl.ExtensionMappingAddressInterpreter;
 import org.onosproject.lisp.msg.protocols.LispLocator;
 import org.onosproject.lisp.msg.protocols.LispMapRecord;
 import org.onosproject.lisp.msg.types.LispAfiAddress;
@@ -41,21 +42,26 @@
 import org.onosproject.mapping.MappingValue;
 import org.onosproject.mapping.actions.MappingAction;
 import org.onosproject.mapping.actions.MappingActions;
+import org.onosproject.mapping.addresses.ExtensionMappingAddress;
 import org.onosproject.mapping.addresses.MappingAddress;
 import org.onosproject.mapping.addresses.MappingAddresses;
+import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.List;
 import java.util.UUID;
 
+import static org.onosproject.mapping.addresses.ExtensionMappingAddressType.ExtensionMappingAddressTypes.*;
+
 /**
  * Mapping entry builder class.
  */
 public class MappingEntryBuilder {
     private static final Logger log =
-                            LoggerFactory.getLogger(MappingEntryBuilder.class);
+            LoggerFactory.getLogger(MappingEntryBuilder.class);
 
     private static final int IPV4_PREFIX_LENGTH = 32;
     private static final int IPV6_PREFIX_LENGTH = 128;
@@ -66,17 +72,36 @@
     private final MappingAction action;
     private final List<MappingTreatment> treatments;
 
+    private final DeviceService deviceService;
+
     /**
      * Default constructor for MappingEntryBuilder.
      *
-     * @param deviceId device identifier
-     * @param record   LISP map record
+     * @param deviceId      device identifier
+     * @param record        LISP map record
+     * @param deviceService device service
+     */
+    public MappingEntryBuilder(DeviceId deviceId, LispMapRecord record,
+                               DeviceService deviceService) {
+        this.deviceId = deviceId;
+        this.address = buildAddress(record);
+        this.action = buildAction(record);
+        this.treatments = buildTreatments(record);
+        this.deviceService = deviceService;
+    }
+
+    /**
+     * Default constructor for MappingEntryBuilder.
+     *
+     * @param deviceId      device identifier
+     * @param record        LISP map record
      */
     public MappingEntryBuilder(DeviceId deviceId, LispMapRecord record) {
         this.deviceId = deviceId;
         this.address = buildAddress(record);
         this.action = buildAction(record);
         this.treatments = buildTreatments(record);
+        this.deviceService = null;
     }
 
     /**
@@ -169,8 +194,7 @@
      */
     private MappingAddress buildAddress(LispMapRecord record) {
 
-        return record == null ? null :
-                getAddress(record.getEidPrefixAfi());
+        return record == null ? null : getAddress(record.getEidPrefixAfi());
     }
 
     /**
@@ -188,22 +212,22 @@
 
         switch (address.getAfi()) {
             case IP4:
-                return afi2MappingAddress(address);
+                return afi2mapping(address);
             case IP6:
-                return afi2MappingAddress(address);
+                return afi2mapping(address);
             case AS:
                 int asNum = ((LispAsAddress) address).getASNum();
                 return MappingAddresses.asMappingAddress(String.valueOf(asNum));
             case DISTINGUISHED_NAME:
                 String dn = ((LispDistinguishedNameAddress)
-                                                address).getDistinguishedName();
+                        address).getDistinguishedName();
                 return MappingAddresses.dnMappingAddress(dn);
             case MAC:
                 MacAddress macAddress = ((LispMacAddress) address).getAddress();
                 return MappingAddresses.ethMappingAddress(macAddress);
             case LCAF:
-                LispLcafAddress lcafAddress = (LispLcafAddress) address;
-                return lcaf2Extension(lcafAddress);
+                return deviceService == null ? null :
+                                     lcaf2extension((LispLcafAddress) address);
             default:
                 log.warn("Unsupported address type {}", address.getAfi());
                 break;
@@ -215,13 +239,89 @@
     /**
      * Converts LCAF address to extension mapping address.
      *
-     * @param lcaf LCAF address
+     * @param lcaf          LCAF address
      * @return extension mapping address
      */
-    private MappingAddress lcaf2Extension(LispLcafAddress lcaf) {
+    private MappingAddress lcaf2extension(LispLcafAddress lcaf) {
 
-        // TODO: move LCAF to extension mapping to LISP Extension Interpreter
-        return null;
+        Device device = deviceService.getDevice(deviceId);
+
+        ExtensionMappingAddressInterpreter addressInterpreter;
+        ExtensionMappingAddress mappingAddress = null;
+        if (device.is(ExtensionMappingAddressInterpreter.class)) {
+            addressInterpreter = device.as(ExtensionMappingAddressInterpreter.class);
+        } else {
+            addressInterpreter = null;
+        }
+
+        switch (lcaf.getType()) {
+            case LIST:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(LIST_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case SEGMENT:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(SEGMENT_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case AS:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(AS_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case APPLICATION_DATA:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(APPLICATION_DATA_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case GEO_COORDINATE:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(GEO_COORDINATE_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case NAT:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(NAT_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case NONCE:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(NONCE_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case MULTICAST:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(MULTICAST_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case TRAFFIC_ENGINEERING:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(TRAFFIC_ENGINEERING_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            case SOURCE_DEST:
+                if (addressInterpreter != null &&
+                        addressInterpreter.supported(SOURCE_DEST_ADDRESS.type())) {
+                    mappingAddress = addressInterpreter.mapLcafAddress(lcaf);
+                }
+                break;
+            default:
+                log.warn("Unsupported extension mapping address type {}", lcaf.getType());
+                break;
+        }
+
+        return mappingAddress != null ?
+                MappingAddresses.extensionMappingAddressWrapper(mappingAddress, deviceId) : null;
     }
 
     /**
@@ -230,7 +330,7 @@
      * @param afiAddress IP typed AFI address
      * @return generalized mapping address
      */
-    private MappingAddress afi2MappingAddress(LispAfiAddress afiAddress) {
+    private MappingAddress afi2mapping(LispAfiAddress afiAddress) {
         switch (afiAddress.getAfi()) {
             case IP4:
                 IpAddress ipv4Address = ((LispIpv4Address) afiAddress).getAddress();
diff --git a/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java b/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java
index ad6d36a..ac7d84f 100644
--- a/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java
+++ b/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java
@@ -74,16 +74,7 @@
 import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.DISTINGUISHED_NAME;
 import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP4;
 import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP6;
-import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.LCAF;
 import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.MAC;
-import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.APPLICATION_DATA;
-import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.GEO_COORDINATE;
-import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.LIST;
-import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.MULTICAST;
-import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.NAT;
-import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.NONCE;
-import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.SEGMENT;
-import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.SOURCE_DEST;
 import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.UNKNOWN;
 
 /**