[ONOS-5750] Improve MappingEntryBuilder to convert LCAF to ext addr

Change-Id: I0353575633bbe1073413b61ad134634716ad75b4
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 90052c28..7d45745 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,15 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onosproject.drivers.lisp.extensions.LispGcAddress;
+import org.onosproject.drivers.lisp.extensions.LispNatAddress;
+import org.onosproject.drivers.lisp.extensions.LispSrcDstAddress;
+import org.onosproject.drivers.lisp.extensions.LispAppDataAddress;
+import org.onosproject.drivers.lisp.extensions.LispListAddress;
+import org.onosproject.drivers.lisp.extensions.LispMulticastAddress;
+import org.onosproject.drivers.lisp.extensions.LispNonceAddress;
+import org.onosproject.drivers.lisp.extensions.LispSegmentAddress;
+import org.onosproject.drivers.lisp.extensions.LispTeAddress;
 import org.onosproject.lisp.msg.protocols.LispLocator;
 import org.onosproject.lisp.msg.protocols.LispMapRecord;
 import org.onosproject.lisp.msg.types.LispAfiAddress;
@@ -27,6 +36,17 @@
 import org.onosproject.lisp.msg.types.LispIpv4Address;
 import org.onosproject.lisp.msg.types.LispIpv6Address;
 import org.onosproject.lisp.msg.types.LispMacAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispMulticastLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispNonceLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispNatLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispGeoCoordinateLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispAsLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispSegmentLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispAppDataLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispListLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispSourceDestLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispTeLcafAddress;
 import org.onosproject.mapping.DefaultMapping;
 import org.onosproject.mapping.DefaultMappingEntry;
 import org.onosproject.mapping.DefaultMappingKey;
@@ -40,6 +60,7 @@
 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.DeviceId;
@@ -49,9 +70,6 @@
 import java.util.List;
 import java.util.UUID;
 
-import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP4;
-import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP6;
-
 /**
  * Mapping entry builder class.
  */
@@ -172,17 +190,16 @@
     private MappingAddress buildAddress(LispMapRecord record) {
 
         return record == null ? null :
-                getAddress(record.getEidPrefixAfi(), record.getMaskLength());
+                getAddress(record.getEidPrefixAfi());
     }
 
     /**
      * Converts LispAfiAddress into abstracted mapping address.
      *
      * @param address LispAfiAddress
-     * @param length  mask length
      * @return abstracted mapping address
      */
-    private MappingAddress getAddress(LispAfiAddress address, int length) {
+    private MappingAddress getAddress(LispAfiAddress address) {
 
         if (address == null) {
             log.warn("Address is not specified.");
@@ -191,13 +208,9 @@
 
         switch (address.getAfi()) {
             case IP4:
-                IpAddress ipv4Address = ((LispIpv4Address) address).getAddress();
-                IpPrefix ipv4Prefix = IpPrefix.valueOf(ipv4Address, length);
-                return MappingAddresses.ipv4MappingAddress(ipv4Prefix);
+                return afi2MappingAddress(address);
             case IP6:
-                IpAddress ipv6Address = ((LispIpv6Address) address).getAddress();
-                IpPrefix ipv6Prefix = IpPrefix.valueOf(ipv6Address, length);
-                return MappingAddresses.ipv6MappingAddress(ipv6Prefix);
+                return afi2MappingAddress(address);
             case AS:
                 int asNum = ((LispAsAddress) address).getASNum();
                 return MappingAddresses.asMappingAddress(String.valueOf(asNum));
@@ -209,8 +222,8 @@
                 MacAddress macAddress = ((LispMacAddress) address).getAddress();
                 return MappingAddresses.ethMappingAddress(macAddress);
             case LCAF:
-                // TODO: need to use extension address to abstract LCAF address
-                break;
+                LispLcafAddress lcafAddress = (LispLcafAddress) address;
+                return lcaf2Extension(lcafAddress);
             default:
                 log.warn("Unsupported address type {}", address.getAfi());
                 break;
@@ -220,6 +233,204 @@
     }
 
     /**
+     * Converts LCAF address to extension mapping address.
+     *
+     * @param lcaf LCAF address
+     * @return extension mapping address
+     */
+    private MappingAddress lcaf2Extension(LispLcafAddress lcaf) {
+
+        ExtensionMappingAddress ema;
+
+        switch (lcaf.getType()) {
+            case LIST:
+                LispListLcafAddress lcafListAddress = (LispListLcafAddress) lcaf;
+                MappingAddress ipv4Ma =
+                        afi2MappingAddress(lcafListAddress.getAddresses().get(0));
+                MappingAddress ipv6Ma =
+                        afi2MappingAddress(lcafListAddress.getAddresses().get(1));
+
+                ema = new LispListAddress.Builder()
+                        .withIpv4(ipv4Ma)
+                        .withIpv6(ipv6Ma)
+                        .build();
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case SEGMENT:
+                LispSegmentLcafAddress segmentLcafAddress = (LispSegmentLcafAddress) lcaf;
+
+                ema = new LispSegmentAddress.Builder()
+                        .withInstanceId(segmentLcafAddress.getInstanceId())
+                        .withAddress(getAddress(segmentLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case AS:
+                LispAsLcafAddress asLcafAddress = (LispAsLcafAddress) lcaf;
+
+                ema = new org.onosproject.drivers.lisp.extensions.LispAsAddress.Builder()
+                        .withAsNumber(asLcafAddress.getAsNumber())
+                        .withAddress(getAddress(asLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case APPLICATION_DATA:
+
+                LispAppDataLcafAddress appLcafAddress = (LispAppDataLcafAddress) lcaf;
+
+                ema = new LispAppDataAddress.Builder()
+                        .withProtocol(appLcafAddress.getProtocol())
+                        .withIpTos(appLcafAddress.getIpTos())
+                        .withLocalPortLow(appLcafAddress.getLocalPortLow())
+                        .withLocalPortHigh(appLcafAddress.getLocalPortHigh())
+                        .withRemotePortLow(appLcafAddress.getRemotePortLow())
+                        .withRemotePortHigh(appLcafAddress.getRemotePortHigh())
+                        .withAddress(getAddress(appLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case GEO_COORDINATE:
+
+                LispGeoCoordinateLcafAddress gcLcafAddress = (LispGeoCoordinateLcafAddress) lcaf;
+
+                ema = new LispGcAddress.Builder()
+                        .withIsNorth(gcLcafAddress.isNorth())
+                        .withLatitudeDegree(gcLcafAddress.getLatitudeDegree())
+                        .withLatitudeMinute(gcLcafAddress.getLatitudeMinute())
+                        .withLatitudeSecond(gcLcafAddress.getLatitudeSecond())
+                        .withIsEast(gcLcafAddress.isEast())
+                        .withLongitudeDegree(gcLcafAddress.getLongitudeDegree())
+                        .withLongitudeMinute(gcLcafAddress.getLongitudeMinute())
+                        .withLongitudeSecond(gcLcafAddress.getLongitudeSecond())
+                        .withAltitude(gcLcafAddress.getAltitude())
+                        .withAddress(getAddress(gcLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case NAT:
+
+                LispNatLcafAddress natLcafAddress = (LispNatLcafAddress) lcaf;
+
+                List<MappingAddress> mas = Lists.newArrayList();
+
+                natLcafAddress.getRtrRlocAddresses().forEach(rtr -> mas.add(getAddress(rtr)));
+
+                ema = new LispNatAddress.Builder()
+                        .withMsUdpPortNumber(natLcafAddress.getMsUdpPortNumber())
+                        .withEtrUdpPortNumber(natLcafAddress.getEtrUdpPortNumber())
+                        .withMsRlocAddress(getAddress(natLcafAddress.getMsRlocAddress()))
+                        .withGlobalEtrRlocAddress(getAddress(natLcafAddress.getGlobalEtrRlocAddress()))
+                        .withPrivateEtrRlocAddress(getAddress(natLcafAddress.getPrivateEtrRlocAddress()))
+                        .withRtrRlocAddresses(mas)
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case NONCE:
+
+                LispNonceLcafAddress nonceLcafAddress = (LispNonceLcafAddress) lcaf;
+
+                ema = new LispNonceAddress.Builder()
+                        .withNonce(nonceLcafAddress.getNonce())
+                        .withAddress(getAddress(nonceLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case MULTICAST:
+
+                LispMulticastLcafAddress multiLcafAddress = (LispMulticastLcafAddress) lcaf;
+
+                ema = new LispMulticastAddress.Builder()
+                        .withInstanceId(multiLcafAddress.getInstanceId())
+                        .withSrcAddress(getAddress(multiLcafAddress.getSrcAddress()))
+                        .withSrcMaskLength(multiLcafAddress.getSrcMaskLength())
+                        .withGrpAddress(getAddress(multiLcafAddress.getGrpAddress()))
+                        .withGrpMaskLength(multiLcafAddress.getGrpMaskLength())
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case TRAFFIC_ENGINEERING:
+
+                LispTeLcafAddress teLcafAddress = (LispTeLcafAddress) lcaf;
+
+                List<LispTeAddress.TeRecord> records = Lists.newArrayList();
+
+                teLcafAddress.getTeRecords().forEach(record -> {
+                    LispTeAddress.TeRecord teRecord =
+                            new LispTeAddress.TeRecord.Builder()
+                                    .withIsLookup(record.isLookup())
+                                    .withIsRlocProbe(record.isRlocProbe())
+                                    .withIsStrict(record.isStrict())
+                                    .withRtrRlocAddress(getAddress(record.getRtrRlocAddress()))
+                                    .build();
+                    records.add(teRecord);
+                });
+
+                ema = new LispTeAddress.Builder()
+                        .withTeRecords(records)
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case SECURITY:
+
+                // TODO: need to implement security type later
+                log.warn("security type will be implemented later");
+
+                return null;
+
+            case SOURCE_DEST:
+
+                LispSourceDestLcafAddress srcDstLcafAddress = (LispSourceDestLcafAddress) lcaf;
+
+
+                ema = new LispSrcDstAddress.Builder()
+                        .withSrcPrefix(getAddress(srcDstLcafAddress.getSrcPrefix()))
+                        .withSrcMaskLength(srcDstLcafAddress.getSrcMaskLength())
+                        .withDstPrefix(getAddress(srcDstLcafAddress.getDstPrefix()))
+                        .withDstMaskLength(srcDstLcafAddress.getDstMaskLength())
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case UNSPECIFIED:
+            case UNKNOWN:
+            default:
+                log.error("Unsupported LCAF type {}", lcaf.getType());
+                return null;
+        }
+    }
+
+    /**
+     * Converts AFI address to generalized mapping address.
+     *
+     * @param afiAddress IP typed AFI address
+     * @return generalized mapping address
+     */
+    private MappingAddress afi2MappingAddress(LispAfiAddress afiAddress) {
+        switch (afiAddress.getAfi()) {
+            case IP4:
+                IpAddress ipv4Address = ((LispIpv4Address) afiAddress).getAddress();
+                IpPrefix ipv4Prefix = IpPrefix.valueOf(ipv4Address, IPV4_PREFIX_LENGTH);
+                return MappingAddresses.ipv4MappingAddress(ipv4Prefix);
+            case IP6:
+                IpAddress ipv6Address = ((LispIpv6Address) afiAddress).getAddress();
+                IpPrefix ipv6Prefix = IpPrefix.valueOf(ipv6Address, IPV6_PREFIX_LENGTH);
+                return MappingAddresses.ipv6MappingAddress(ipv6Prefix);
+            default:
+                log.warn("Only support to convert IP address type");
+                break;
+        }
+        return null;
+    }
+
+    /**
      * Builds a collection of mapping treatments.
      *
      * @param record LISP map record
@@ -232,14 +443,8 @@
         for (LispLocator locator : locators) {
             MappingTreatment.Builder builder = DefaultMappingTreatment.builder();
             LispAfiAddress address = locator.getLocatorAfi();
-            int addressLength = 0;
-            if (address.getAfi() == IP4) {
-                addressLength = IPV4_PREFIX_LENGTH;
-            } else if (address.getAfi() == IP6) {
-                addressLength = IPV6_PREFIX_LENGTH;
-            }
 
-            final MappingAddress mappingAddress = getAddress(address, addressLength);
+            final MappingAddress mappingAddress = getAddress(address);
             if (mappingAddress != null) {
                 builder.withAddress(mappingAddress);
             }