Magnesium platform upgrade
[lispflowmapping.git] / mappingservice / implementation / src / main / java / org / opendaylight / lispflowmapping / implementation / MappingSystem.java
index 14762a0e2fa7eef7de5dd4adde6c2eeb22dd1a63..1c9799d7cc2bdfa7ab979bd44cb97d599e80b2fb 100644 (file)
@@ -19,8 +19,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.lispflowmapping.config.ConfigIni;
 import org.opendaylight.lispflowmapping.dsbackend.DataStoreBackEnd;
 import org.opendaylight.lispflowmapping.implementation.timebucket.implementation.TimeBucketMappingTimeoutService;
@@ -41,12 +39,15 @@ import org.opendaylight.lispflowmapping.lisp.type.LispMessage;
 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.MappingRecordUtil;
 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
 import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper;
 import org.opendaylight.lispflowmapping.mapcache.AuthKeyDb;
 import org.opendaylight.lispflowmapping.mapcache.MultiTableMapCache;
 import org.opendaylight.lispflowmapping.mapcache.SimpleMapCache;
 import org.opendaylight.lispflowmapping.mapcache.lisp.LispMapCacheStringifier;
+import org.opendaylight.mdsal.binding.api.NotificationPublishService;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.SimpleAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.ExplicitLocatorPath;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4;
@@ -87,19 +88,19 @@ public class MappingSystem implements IMappingSystem {
     private static final String AUTH_KEY_TABLE = "authentication";
     //private static final int TTL_RLOC_TIMED_OUT = 1;
     private static final int TTL_NO_RLOC_KNOWN = ConfigIni.getInstance().getNegativeMappingTTL();
-    private NotificationPublishService notificationPublishService;
+    private final NotificationPublishService notificationPublishService;
     private boolean mappingMerge;
-    private ILispDAO dao;
+    private final ILispDAO dao;
     private ILispDAO sdao;
     private ILispMapCache smc;
     private IMapCache pmc;
-    private ConcurrentHashMap<Eid, Set<Subscriber>> subscriberdb = new ConcurrentHashMap<>();
+    private final ConcurrentHashMap<Eid, Set<Subscriber>> subscriberdb = new ConcurrentHashMap<>();
     private IAuthKeyDb akdb;
     private final EnumMap<MappingOrigin, IMapCache> tableMap = new EnumMap<>(MappingOrigin.class);
     private DataStoreBackEnd dsbe;
     private boolean isMaster = false;
 
-    private ISouthBoundMappingTimeoutService sbMappingTimeoutService;
+    private final ISouthBoundMappingTimeoutService sbMappingTimeoutService;
 
     public MappingSystem(ILispDAO dao, boolean iterateMask, NotificationPublishService nps, boolean mappingMerge) {
         this.dao = dao;
@@ -166,6 +167,17 @@ public class MappingSystem implements IMappingSystem {
             return;
         }
 
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("DAO: Adding {} mapping for EID {}", origin, LispAddressStringifier.getString(key));
+        }
+
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("mappingData = {}", mappingData.getString());
+        }
+
+        // Save the old mapping for the key before we modify anything, so that we can detect changes later
+        final MappingRecord oldMapping = getMappingRecord(getMapping(key));
+
         if (origin == MappingOrigin.Southbound) {
             XtrId xtrId = mappingData.getXtrId();
             if (xtrId == null && mappingMerge && mappingData.isMergeEnabled()) {
@@ -187,12 +199,18 @@ public class MappingSystem implements IMappingSystem {
 
         tableMap.get(origin).addMapping(key, mappingData);
 
-        if (origin != MappingOrigin.Southbound) {
-            // If a NB mapping is added, we need to check if it's covering negative mappings in SB, and remove those
+        // We need to check if the newly added mapping is covering negatives in SB, and remove those (with notification)
+        if (mappingData.isPositive().or(true)) {
             handleSbNegativeMappings(key);
-            // Notifications for SB changes are sent in the SB code itself, so this is called for non-SB additions only
-            notifyChange(key, mappingData.getRecord(), changeType);
         }
+
+        MappingRecord newMapping = getMappingRecord(getMapping(key));
+
+        handleAddMappingNotifications(origin, key, mappingData, oldMapping, newMapping, changeType);
+    }
+
+    private static MappingRecord getMappingRecord(MappingData mappingData) {
+        return mappingData != null ? mappingData.getRecord() : null;
     }
 
     @SuppressWarnings("unchecked")
@@ -225,26 +243,19 @@ public class MappingSystem implements IMappingSystem {
     private void handleSbNegativeMappings(Eid key) {
         Set<Eid> childPrefixes = getSubtree(MappingOrigin.Southbound, key);
 
-        // We don't want to remove a newly added negative mapping, so remove it from the child set
-        childPrefixes.remove(key);
-
-        LOG.trace("handleSbNegativeMappings(): subtree prefix set for EID {} (excluding the EID itself): {}",
+        LOG.trace("handleSbNegativeMappings(): subtree prefix set for EID {}: {}",
                 LispAddressStringifier.getString(key),
                 LispAddressStringifier.getString(childPrefixes));
-        if (childPrefixes == null || childPrefixes.isEmpty()) {
-            // The assumption here is that negative prefixes are well maintained and never overlapping.
-            // If we have children for the EID, no parent lookup should thus be necessary.
-            Eid parentPrefix = smc.getCoveringLessSpecific(key);
-            LOG.trace("handleSbNegativeMappings(): parent prefix for EID {}: {}",
-                    LispAddressStringifier.getString(key),
-                    LispAddressStringifier.getString(parentPrefix));
-            handleSbNegativeMapping(parentPrefix);
-            return;
-        }
 
         for (Eid prefix : childPrefixes) {
             handleSbNegativeMapping(prefix);
         }
+
+        Eid parentPrefix = smc.getCoveringLessSpecific(key);
+        LOG.trace("handleSbNegativeMappings(): parent prefix for EID {}: {}",
+                LispAddressStringifier.getString(key),
+                LispAddressStringifier.getString(parentPrefix));
+        handleSbNegativeMapping(parentPrefix);
     }
 
     private void handleSbNegativeMapping(Eid key) {
@@ -254,6 +265,34 @@ public class MappingSystem implements IMappingSystem {
         }
     }
 
+    private void handleAddMappingNotifications(MappingOrigin origin, Eid key, MappingData mappingData,
+                                               MappingRecord oldMapping, MappingRecord newMapping,
+                                               MappingChange changeType) {
+        // Non-southbound origins are MD-SAL first, so they only get to call addMapping() if there is a change
+        // Southbound is different, so we need to check if there is a change in the mapping. This check takes into
+        // account policy as well
+        if (origin != MappingOrigin.Southbound || MappingRecordUtil.mappingChanged(oldMapping, newMapping)) {
+            notifyChange(key, mappingData.getRecord(), changeType);
+
+            Eid dstKey = key;
+            // Since the above notifyChange() already notifies the dest part of source/dest addresses, we save the dest
+            // for the checks that we do afterwards
+            if (key.getAddress() instanceof SourceDestKey) {
+                dstKey = SourceDestKeyHelper.getDstBinary(key);
+            }
+            // If the old mapping had a different EID than what was just added, notify those subscribers too
+            if (oldMapping != null && !oldMapping.getEid().equals(key) && !oldMapping.getEid().equals(dstKey)) {
+                notifyChange(oldMapping.getEid(), oldMapping, changeType);
+            }
+            // If the new mapping has a different EID than what was just added (e.g., due to NB_AND_SB), notify those
+            // subscribers too
+            if (newMapping != null && !newMapping.getEid().equals(key) && !newMapping.getEid().equals(dstKey)) {
+                notifyChange(newMapping.getEid(), newMapping, changeType);
+            }
+        }
+
+    }
+
     @Override
     public MappingData addNegativeMapping(Eid key) {
         MappingRecord mapping = buildNegativeMapping(key);
@@ -290,6 +329,7 @@ public class MappingSystem implements IMappingSystem {
      * Since this method is only called when there is a hit in the southbound Map-Register cache, and that cache is
      * not used when merge is on, it's OK to ignore the effects of timestamp changes on merging for now.
      */
+    @Override
     public void refreshMappingRegistration(Eid key, XtrId xtrId, Long timestamp) {
 
         sbMappingTimeoutService.removeExpiredMappings();
@@ -327,7 +367,7 @@ public class MappingSystem implements IMappingSystem {
         }
 
         LocatorRecord locatorRecord = mappingData.getRecord().getLocatorRecord().get(0);
-        long serviceIndex = ((ServicePath) eid.getAddress()).getServicePath().getServiceIndex();
+        long serviceIndex = ((ServicePath) eid.getAddress()).getServicePath().getServiceIndex().toJava();
         int index = LispAddressUtil.STARTING_SERVICE_INDEX - (int) serviceIndex;
         Rloc rloc = locatorRecord.getRloc();
         if (rloc.getAddress() instanceof Ipv4 || rloc.getAddress() instanceof Ipv6) {
@@ -356,6 +396,7 @@ public class MappingSystem implements IMappingSystem {
     }
 
     private MappingData handleMergedMapping(Eid key) {
+        LOG.trace("Merging mappings for EID {}", LispAddressStringifier.getString(key));
         List<MappingData> expiredMappingDataList = new ArrayList<>();
         Set<IpAddressBinary> sourceRlocs = new HashSet<>();
 
@@ -379,8 +420,13 @@ public class MappingSystem implements IMappingSystem {
     @Override
     public MappingData getMapping(Eid src, Eid dst) {
         // NOTE: Currently we have two lookup algorithms implemented, which are configurable
+        IMappingService.LookupPolicy policy = ConfigIni.getInstance().getLookupPolicy();
+        LOG.debug("DAO: Looking up mapping for {}, source EID {} with policy {}",
+                LispAddressStringifier.getString(dst),
+                LispAddressStringifier.getString(src),
+                policy);
 
-        if (ConfigIni.getInstance().getLookupPolicy() == IMappingService.LookupPolicy.NB_AND_SB) {
+        if (policy == IMappingService.LookupPolicy.NB_AND_SB) {
             return getMappingNbSbIntersection(src, dst);
         } else {
             return getMappingNbFirst(src, dst);
@@ -449,11 +495,17 @@ public class MappingSystem implements IMappingSystem {
 
     private MappingData getSbMappingWithExpiration(Eid src, Eid dst, XtrId xtrId) {
         MappingData mappingData = (MappingData) smc.getMapping(dst, xtrId);
-        if (mappingData != null && MappingMergeUtil.mappingIsExpired(mappingData)) {
-            return handleSbExpiredMapping(dst, xtrId, mappingData);
-        } else {
-            return mappingData;
+        while (mappingData != null && MappingMergeUtil.mappingIsExpired(mappingData)) {
+            // If the mappingData is expired, handleSbExpiredMapping() will run merge for it if merge is enabled,
+            // otherwise it will remove the expired mapping, returning null.
+            MappingData mergedMappingData = handleSbExpiredMapping(dst, xtrId, mappingData);
+            if (mergedMappingData != null) {
+                return mergedMappingData;
+            }
+            // If the expired mapping was removed, we look up the original query again
+            mappingData = (MappingData) smc.getMapping(dst, xtrId);
         }
+        return mappingData;
     }
 
     public MappingData handleSbExpiredMapping(Eid key, XtrId xtrId, MappingData mappingData) {
@@ -470,6 +522,11 @@ public class MappingSystem implements IMappingSystem {
     }
 
     private void removeSbXtrIdSpecificMapping(Eid key, XtrId xtrId, MappingData mappingData) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("DAO: Removing southbound mapping for EID {}, xTR-ID {}",
+                    LispAddressStringifier.getString(key),
+                    LispAddressStringifier.getString(xtrId));
+        }
         smc.removeMapping(key, xtrId);
         dsbe.removeXtrIdMapping(DSBEInputUtil.toXtrIdMapping(mappingData));
     }
@@ -480,7 +537,10 @@ public class MappingSystem implements IMappingSystem {
         }
 
         removeFromSbTimeoutService(key);
-        Set<Subscriber> subscribers = getSubscribers(key);
+        final Set<Subscriber> subscribers = getSubscribers(key);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("DAO: Removing southbound mapping for EID {}", LispAddressStringifier.getString(key));
+        }
         smc.removeMapping(key);
         dsbe.removeMapping(DSBEInputUtil.toMapping(MappingOrigin.Southbound, key, mappingData));
         publishNotification(mappingData.getRecord(), null, subscribers, null, MappingChange.Removed);
@@ -598,7 +658,11 @@ public class MappingSystem implements IMappingSystem {
             dstSubscribers = getSubscribers(dstAddr);
             notifyChildren(dstAddr, mapping, mappingChange);
         }
-        publishNotification(mapping, eid, subscribers, dstSubscribers, mappingChange);
+
+        // No reason to send a notification when no subscribers exist
+        if (subscribers != null || dstSubscribers != null) {
+            publishNotification(mapping, eid, subscribers, dstSubscribers, mappingChange);
+        }
 
         notifyChildren(eid, mapping, mappingChange);
     }
@@ -618,7 +682,10 @@ public class MappingSystem implements IMappingSystem {
         childPrefixes.remove(eid);
         for (Eid prefix : childPrefixes) {
             Set<Subscriber> subscribers = getSubscribers(prefix);
-            publishNotification(mapping, prefix, subscribers, null, mappingChange);
+            // No reason to send a notification when no subscribers exist
+            if (subscribers != null) {
+                publishNotification(mapping, prefix, subscribers, null, mappingChange);
+            }
         }
     }
 
@@ -675,13 +742,13 @@ public class MappingSystem implements IMappingSystem {
     private static Eid getVirtualParent(Eid eid) {
         if (eid.getAddress() instanceof Ipv4PrefixBinary) {
             Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
-            short parentPrefixLength = (short) (prefix.getIpv4MaskLength() - 1);
+            short parentPrefixLength = (short) (prefix.getIpv4MaskLength().toJava() - 1);
             byte[] parentPrefix = MaskUtil.normalizeByteArray(prefix.getIpv4AddressBinary().getValue(),
                     parentPrefixLength);
             return LispAddressUtil.asIpv4PrefixBinaryEid(eid, parentPrefix, parentPrefixLength);
         } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
             Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
-            short parentPrefixLength = (short) (prefix.getIpv6MaskLength() - 1);
+            short parentPrefixLength = (short) (prefix.getIpv6MaskLength().toJava() - 1);
             byte[] parentPrefix = MaskUtil.normalizeByteArray(prefix.getIpv6AddressBinary().getValue(),
                     parentPrefixLength);
             return LispAddressUtil.asIpv6PrefixBinaryEid(eid, parentPrefix, parentPrefixLength);