Bug 8112: IT: send SMR-invoked Map-Request on SMR
[lispflowmapping.git] / integrationtest / src / test / java / org / opendaylight / lispflowmapping / integrationtest / MultiSiteScenario.java
index c50a4a028c2d4ee311be33126296cec44aff6da2..6b6ddbd0badfa8a8fddc27b6433e50a4c4c78ec9 100644 (file)
@@ -15,6 +15,7 @@ import static org.opendaylight.lispflowmapping.integrationtest.MappingServiceInt
 import static org.opendaylight.lispflowmapping.integrationtest.MultiSiteScenarioUtil.SITE_A;
 import static org.opendaylight.lispflowmapping.integrationtest.MultiSiteScenarioUtil.SITE_D5;
 
+import com.google.common.net.InetAddresses;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -22,21 +23,22 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import org.apache.commons.lang3.ArrayUtils;
 import org.opendaylight.lispflowmapping.integrationtest.MultiSiteScenarioUtil.Site;
 import org.opendaylight.lispflowmapping.interfaces.lisp.IFlowMapping;
 import org.opendaylight.lispflowmapping.interfaces.mappingservice.IMappingService;
 import org.opendaylight.lispflowmapping.lisp.serializer.MapRequestSerializer;
+import org.opendaylight.lispflowmapping.lisp.type.MappingData;
 import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier;
 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
+import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.InstanceIdType;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.inet.binary.types.rev160303.Ipv4AddressBinary;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4Binary;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6Binary;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapReply;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapRequest;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.SiteId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItem;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItemBuilder;
@@ -58,7 +60,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.rl
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import com.google.common.net.InetAddresses;
 
 /**
  * Contains methods for:
@@ -79,8 +80,7 @@ class MultiSiteScenario {
     private final Boolean DEFAULT_LOCAL_LOCATOR = true;
     private final Boolean DEFAULT_RLOC_PROBED = false;
     private final Boolean DEFAULT_ROUTED = true;
-    private final byte[] DEFAULT_XTR_ID = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
-    private final byte[] DEFAULT_SITE_ID = new byte[]{0, 1, 2, 3, 4, 5, 6, 7};
+    private final byte[] DEFAULT_SITE_ID = new byte[]{0, 0, 0, 0, 0, 0, 0, 0};
 
     private final MappingAuthkey NULL_AUTH_KEY = new MappingAuthkeyBuilder().setKeyType(0).build();
     private final IMappingService mapService;
@@ -127,7 +127,7 @@ class MultiSiteScenario {
     private void emitMapRegisterMessage(final Site dstSite, final boolean merge) {
         final MapRegisterBuilder mapRegisterBuilder = new MapRegisterBuilder();
         mapRegisterBuilder.setXtrSiteIdPresent(true);
-        mapRegisterBuilder.setXtrId(new XtrId(DEFAULT_XTR_ID));
+        mapRegisterBuilder.setXtrId(dstSite.getXtrId());
         mapRegisterBuilder.setSiteId(new SiteId(DEFAULT_SITE_ID));
         mapRegisterBuilder.setMergeEnabled(merge);
         final MappingRecordItemBuilder mappingRecordItemBuilder = new MappingRecordItemBuilder();
@@ -167,9 +167,59 @@ class MultiSiteScenario {
         mapRequestBuilder.setSourceEid(new SourceEidBuilder().setEid(srcEid).build());
         mapRequestBuilder.setEidItem(eidItem);
         mapRequestBuilder.setItrRloc(prepareDummyItrRloc());
+        mapRequestBuilder.setSmrInvoked(false);
         return lms.handleMapRequest(mapRequestBuilder.build());
     }
 
+    /**
+     * This method expects a SMR Map-Request as input, which it will turn into a SMR-invoked Map-Request and use the
+     * LISP mapping service to send it
+     *
+     * @param mapRequest the SMR Map-Request
+     */
+    private void emitSMRInvokedMapRequestMessage(MapRequest mapRequest) {
+        if (mapRequest.getEidItem().isEmpty()) {
+            fail("Empty SMR received!");
+        }
+
+        Eid srcEid = addMaximumPrefixIfNecessary(mapRequest.getSourceEid().getEid());
+        final EidItemBuilder eidItemBuilder = new EidItemBuilder();
+        eidItemBuilder.setEid(srcEid);
+        eidItemBuilder.setEidItemId(LispAddressStringifier.getString(srcEid));
+        final List<EidItem> eidItem = Collections.singletonList(eidItemBuilder.build());
+
+        final MapRequestBuilder mapRequestBuilder = new MapRequestBuilder(mapRequest);
+        mapRequestBuilder.setSmr(false);
+        mapRequestBuilder.setSmrInvoked(true);
+        mapRequestBuilder.setItrRloc(prepareDummyItrRloc());
+        mapRequestBuilder.setEidItem(eidItem);
+        for (EidItem ei : mapRequest.getEidItem()) {
+            mapRequestBuilder.setSourceEid(new SourceEidBuilder().setEid(ei.getEid()).build());
+            LOG.debug("Sending SMR-invoked Map-Reqeust for EID {}, Source EID {}",
+                    LispAddressStringifier.getString(srcEid),
+                    LispAddressStringifier.getString(ei.getEid()));
+            lms.handleMapRequest(mapRequestBuilder.build());
+        }
+    }
+
+    /*
+     * Since the Source EID field from a Map-Request packet does not have a prefix length field, IPv4 and IPv6 addresses
+     * are serialized into Ipv4Binary and Ipv6Binary objects. However, when we want to use the addresses in a
+     * SMR-invoked Map-Request, we need to use an Ipv4PrefixBinary or Ipv6PrefixBinary object respectively, since that's
+     * what the EID item field would be deserialized into.
+     */
+    private static Eid addMaximumPrefixIfNecessary(Eid eid) {
+        Address address = eid.getAddress();
+        if (address instanceof Ipv4Binary) {
+            return LispAddressUtil.asIpv4PrefixBinaryEid(
+                    eid, ((Ipv4Binary) address).getIpv4Binary().getValue(), MaskUtil.IPV4_MAX_MASK);
+        } else if (address instanceof Ipv6Binary) {
+            return LispAddressUtil.asIpv6PrefixBinaryEid(
+                    eid, ((Ipv6Binary) address).getIpv6Binary().getValue(), MaskUtil.IPV6_MAX_MASK);
+        }
+        return eid;
+    }
+
     private List<ItrRloc> prepareDummyItrRloc() {
         List<ItrRloc> itrRlocs = new ArrayList<>();
         final ItrRlocBuilder itrRlocBuilder = new ItrRlocBuilder();
@@ -187,8 +237,8 @@ class MultiSiteScenario {
         mrbNegative.setEid(eidAsIpv4Prefix);
         mrbNegative.setAction(action);
 
-        mapService.addMapping(MappingOrigin.Northbound, eidAsIpv4Prefix, dstSite.getSiteId(), mrbNegative.build(),
-                false);
+        mapService.addMapping(MappingOrigin.Northbound, eidAsIpv4Prefix, new SiteId(DEFAULT_SITE_ID),
+                new MappingData(mrbNegative.build()));
     }
 
     void deleteNorthMappingNegative(final Site dstSite) {
@@ -201,12 +251,14 @@ class MultiSiteScenario {
     void storeNorthMappingSrcDst(final Site srcSite, final Site ... dstSite) {
         final MappingRecordBuilder mrb = prepareMappingRecord(EidType.EID_SRC_DST, srcSite,
                 dstSite);
-        mapService.addMapping(MappingOrigin.Northbound, mrb.getEid(), dstSite[0].getSiteId(), mrb.build(), false);
+        mapService.addMapping(MappingOrigin.Northbound, mrb.getEid(), new SiteId(DEFAULT_SITE_ID),
+                new MappingData(mrb.build()));
     }
 
     void storeNorthMappingIpPrefix(final Site... dstSite) {
         final MappingRecordBuilder mrb = prepareMappingRecord(EidType.EID_WITH_PREFIX, null, dstSite);
-        mapService.addMapping(MappingOrigin.Northbound, mrb.getEid(), dstSite[0].getSiteId(), mrb.build(), false);
+        mapService.addMapping(MappingOrigin.Northbound, mrb.getEid(),  new SiteId(DEFAULT_SITE_ID),
+                new MappingData(mrb.build()));
     }
 
     private void storeDestinationSiteMappingViaSouthbound(final Site dstSite, final boolean merge) {
@@ -216,7 +268,7 @@ class MultiSiteScenario {
     private MappingRecordBuilder prepareMappingRecordGeneral(final EidType eidType,
                                                              final Site srcSite, final Site dstSite) {
         final MappingRecordBuilder mrb = provideCommonMapRecordBuilder();
-        mrb.setXtrId(new XtrId(ArrayUtils.addAll(dstSite.getSiteId().getValue(), dstSite.getSiteId().getValue())));
+        mrb.setXtrId(dstSite.getXtrId());
 
         Eid eid = null;
         if (EidType.EID_SRC_DST.equals(eidType)) {
@@ -442,7 +494,11 @@ class MultiSiteScenario {
     private List<MapRequest> translateBuffersToMapRequest(byte[][] buffers) {
         final List<MapRequest> mapRequests = new ArrayList<>();
         for (byte[] buffer : buffers) {
-            final MapRequest mapRequest = MapRequestSerializer.getInstance().deserialize(ByteBuffer.wrap(buffer));
+            if (isBufferEmpty(buffer)) {
+                LOG.error("Empty buffer while translating Map-Request");
+                continue;
+            }
+            final MapRequest mapRequest = MapRequestSerializer.getInstance().deserialize(ByteBuffer.wrap(buffer), null);
             assertNotNull(mapRequest);
             mapRequests.add(mapRequest);
         }
@@ -465,16 +521,27 @@ class MultiSiteScenario {
     }
 
     void checkSMR(final SocketReader socketReader, final String site, final String ... hosts) {
-        List<MapRequest> mapRequests = translateBuffersToMapRequest(socketReader.getBuffers(hosts.length));
+        LOG.debug("\n" + mapService.prettyPrintMappings());
+        byte[][] buffers = socketReader.getBuffers(hosts.length);
+        if (areBuffersEmpty(buffers)) {
+            fail("No SMR received!");
+        }
+        List<MapRequest> mapRequests = translateBuffersToMapRequest(buffers);
+        if (hosts.length != mapRequests.size()) {
+            LOG.error("Expected {} SMRs, received {}", hosts.length, mapRequests.size());
+            fail("Unexpected number of SMRs received");
+        }
         final Set<Eid> eids = prepareExpectedEid(hosts);
         final SourceEid expectedSourceEid = prepareSourceEid(site);
         for(MapRequest mapRequest : mapRequests) {
+            LOG.trace("Map-Request: {}", mapRequest);
             assertTrue(mapRequest.isSmr());
             final SourceEid receivedSourceEid = mapRequest.getSourceEid();
             assertEquals(expectedSourceEid, receivedSourceEid);
             final List<EidItem> currentEidItems = mapRequest.getEidItem();
             assertNotNull(currentEidItems);
             assertTrue(SMRContainsExpectedEid(eids, currentEidItems));
+            emitSMRInvokedMapRequestMessage(mapRequest);
         }
         //all expected eids should be after looping via mapRequests matched.
         assertTrue("Expected eids wasn't/weren't found " + eids, eids.isEmpty());
@@ -484,10 +551,28 @@ class MultiSiteScenario {
         for (EidItem eidItem : currentEidItems) {
             //if eid from map request is matched then it is removed from set of expected eids
             if (!eids.remove(eidItem.getEid())) {
-                fail("SMR contained " + eidItem.getEid() + " which wasn't expected.");
+                 fail("SMR contained EID `" + LispAddressStringifier.getString(eidItem.getEid())
+                         + "' which wasn't expected.");
+            }
+        }
+        return true;
+    }
+
+    private static boolean isBufferEmpty(byte[] buffer) {
+        for (byte b : buffer) {
+            if (b != 0) {
+                return false;
             }
         }
         return true;
     }
 
+    protected static boolean areBuffersEmpty(byte[][] buffers) {
+        for (byte[] buffer : buffers) {
+            if (!isBufferEmpty(buffer)) {
+                return false;
+            }
+        }
+        return true;
+    }
 }