SMR parent prefix continued 77/48977/33
authorLorand Jakab <lojakab@cisco.com>
Mon, 5 Dec 2016 12:15:51 +0000 (14:15 +0200)
committerLorand Jakab <lojakab@cisco.com>
Thu, 16 Mar 2017 14:28:49 +0000 (16:28 +0200)
This patch completes work started in
https://git.opendaylight.org/gerrit/#/c/47120/

First, it handles the insertion of a positive mapping that overlaps
a negative one, by removing the negative mapping and generating SMRs for
its subscribers. This leads to pushing the positive mapping to the right
subscribers and generating only the needed negative mappings.

Second, it merges negative mappings when a positive mapping is removed
(reversing what was done in the first point above).

Additionally, it creates a variable for the action considered the
default for negative mappings, and uses it in the right places instead
of harcoding Action.NativelyForward.

Change-Id: I6a8799d3af23c20a9797840b3e64f632a3e2ee91
Signed-off-by: Lorand Jakab <lojakab@cisco.com>
14 files changed:
mappingservice/api/src/main/java/org/opendaylight/lispflowmapping/interfaces/mapcache/ILispMapCache.java
mappingservice/api/src/main/java/org/opendaylight/lispflowmapping/interfaces/mapcache/IMappingSystem.java
mappingservice/api/src/main/java/org/opendaylight/lispflowmapping/interfaces/mappingservice/IMappingService.java
mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/MappingService.java
mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/MappingSystem.java
mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/lisp/MapResolver.java
mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/lisp/MapServer.java
mappingservice/implementation/src/test/java/org/opendaylight/lispflowmapping/implementation/MappingSystemTest.java
mappingservice/implementation/src/test/java/org/opendaylight/lispflowmapping/implementation/lisp/MapResolverTest.java
mappingservice/lisp-proto/src/main/java/org/opendaylight/lispflowmapping/lisp/type/LispMessage.java
mappingservice/lisp-proto/src/main/java/org/opendaylight/lispflowmapping/lisp/type/MappingData.java
mappingservice/lisp-proto/src/main/java/org/opendaylight/lispflowmapping/lisp/util/MappingRecordUtil.java [new file with mode: 0644]
mappingservice/lisp-proto/src/main/java/org/opendaylight/lispflowmapping/lisp/util/MaskUtil.java
mappingservice/mapcache/src/main/java/org/opendaylight/lispflowmapping/mapcache/SimpleMapCache.java

index af703e7a7bafde9bde62ec101e0ca62e16550e8d..0a745dfeb3c361da2c72e7f5382d82e297da0bd7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Cisco Systems, Inc.  All rights reserved.
+ * Copyright (c) 2016, 2017 Cisco Systems, Inc.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -93,8 +93,26 @@ public interface ILispMapCache extends IMapCache {
      * Returns the parent prefix for given key.
      *
      * @param key
-     *            The key which parent is to be returned.
-     * @return The parent perfix of a specific key.
+     *            The key for which parent is to be returned.
+     * @return The parent prefix of a specific key.
      */
     Eid getParentPrefix(Eid key);
+
+    /**
+     * Returns the sibling prefix for given key.
+     *
+     * @param key
+     *            The key for which sibling is to be returned.
+     * @return The sibling prefix of a specific key.
+     */
+    Eid getSiblingPrefix(Eid key);
+
+    /**
+     * Returns the virtual parent sibling prefix for given key.
+     *
+     * @param key
+     *            The key for which virtual parent sibling is to be returned.
+     * @return The virtual parent sibling prefix of a specific key.
+     */
+    Eid getVirtualParentSiblingPrefix(Eid key);
 }
index b617efe3321de8171b1f522404f852438ca8351c..9aa641ec5f5c884f64aa329a8ab4dd5f96e8c094 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Cisco Systems, Inc.  All rights reserved.
+ * Copyright (c) 2015, 2017 Cisco Systems, Inc.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -34,6 +34,15 @@ public interface IMappingSystem {
      */
     void addMapping(MappingOrigin origin, Eid key, MappingData mapping);
 
+    /**
+     * Generate and add a negative mapping entry originated from the southbound, and return the generated mapping.
+     *
+     * @param key
+     *            Key of the mapping
+     * @return Returns the generated negative mapping (which is never null).
+     */
+    MappingData addNegativeMapping(Eid key);
+
     /**
      * Retrieves mapping for the provided src and dst key.
      *
index df53aa3c053e3112e66a4f6efbf42f729f66f667..e917a97896d327138b5175c4596e2afaf61d2bfd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Cisco Systems, Inc.  All rights reserved.
+ * Copyright (c) 2015, 2017 Cisco Systems, Inc.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -40,6 +40,15 @@ public interface IMappingService {
      */
     void addMapping(MappingOrigin origin, Eid key, SiteId siteId, MappingData mapping);
 
+    /**
+     * Generate and add a negative mapping entry originated from the southbound, and return the generated mapping.
+     *
+     * @param key
+     *            Key of the mapping
+     * @return Returns the generated negative mapping (which is never null).
+     */
+    MappingData addNegativeMapping(Eid key);
+
     /**
      * Retrieves mapping with given origin for the provided key. The lookup policy for the key is defined in the Mapping
      * System.
index a60c8a0107166d1ce4e79293bc98e3d2979d3611..6bce0e86663d8340f38a663682acc04b868b1548 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Cisco Systems, Inc.  All rights reserved.
+ * Copyright (c) 2015, 2017 Cisco Systems, Inc.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -126,7 +126,7 @@ public class MappingService implements OdlMappingserviceService, IMappingService
         LOG.info("Mapping Service initializing...");
         dsbe = new DataStoreBackEnd(dataBroker);
 
-        mappingSystem = new MappingSystem(dao, iterateMask, notificationPolicy, mappingMergePolicy);
+        mappingSystem = new MappingSystem(dao, iterateMask, notificationPublishService, mappingMergePolicy);
         mappingSystem.setDataStoreBackEnd(dsbe);
         mappingSystem.initialize();
 
@@ -187,6 +187,11 @@ public class MappingService implements OdlMappingserviceService, IMappingService
         }
     }
 
+    @Override
+    public MappingData addNegativeMapping(Eid key) {
+        return mappingSystem.addNegativeMapping(key);
+    }
+
     @Override
     public void refreshMappingRegistration(Eid key, XtrId xtrId, Long timestamp) {
         mappingSystem.refreshMappingRegistration(key, xtrId, timestamp);
index 3446930da7b84be1c409bde73c528247f39e6bb4..9005491813ded5773f1c3c0c447a578ac6bd089e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Cisco Systems, Inc.  All rights reserved.
+ * Copyright (c) 2015, 2017 Cisco Systems, Inc.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -8,30 +8,35 @@
 
 package org.opendaylight.lispflowmapping.implementation;
 
+import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.EnumMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-
+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;
 import org.opendaylight.lispflowmapping.implementation.timebucket.interfaces.ISouthBoundMappingTimeoutService;
 import org.opendaylight.lispflowmapping.implementation.util.DSBEInputUtil;
+import org.opendaylight.lispflowmapping.implementation.util.MSNotificationInputUtil;
 import org.opendaylight.lispflowmapping.implementation.util.MappingMergeUtil;
 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
+import org.opendaylight.lispflowmapping.interfaces.dao.Subscriber;
 import org.opendaylight.lispflowmapping.interfaces.mapcache.IAuthKeyDb;
 import org.opendaylight.lispflowmapping.interfaces.mapcache.ILispMapCache;
 import org.opendaylight.lispflowmapping.interfaces.mapcache.IMapCache;
 import org.opendaylight.lispflowmapping.interfaces.mapcache.IMappingSystem;
 import org.opendaylight.lispflowmapping.interfaces.mappingservice.IMappingService;
+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.MaskUtil;
 import org.opendaylight.lispflowmapping.mapcache.AuthKeyDb;
 import org.opendaylight.lispflowmapping.mapcache.MultiTableMapCache;
 import org.opendaylight.lispflowmapping.mapcache.SimpleMapCache;
@@ -42,13 +47,19 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.addres
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.ServicePath;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.explicit.locator.path.explicit.locator.path.Hop;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.inet.binary.types.rev160303.IpAddressBinary;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.Ipv4PrefixBinaryAfi;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.Ipv6PrefixBinaryAfi;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4PrefixBinary;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6PrefixBinary;
 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.locatorrecords.LocatorRecord;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.authkey.container.MappingAuthkey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.rloc.container.Rloc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingChange;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.AuthenticationKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.Mapping;
@@ -60,12 +71,15 @@ import org.slf4j.LoggerFactory;
  * mapping lookups.
  *
  * @author Florin Coras
+ * @author Lorand Jakab
  *
  */
 public class MappingSystem implements IMappingSystem {
     private static final Logger LOG = LoggerFactory.getLogger(MappingSystem.class);
     private static final String AUTH_KEY_TABLE = "authentication";
-    private boolean notificationService;
+    private static final int TTL_RLOC_TIMED_OUT = 1;
+    private static final int TTL_NO_RLOC_KNOWN = 15;
+    private NotificationPublishService notificationPublishService;
     private boolean mappingMerge;
     private ILispDAO dao;
     private ILispDAO sdao;
@@ -78,9 +92,9 @@ public class MappingSystem implements IMappingSystem {
 
     private ISouthBoundMappingTimeoutService sbMappingTimeoutService;
 
-    public MappingSystem(ILispDAO dao, boolean iterateMask, boolean notifications, boolean mappingMerge) {
+    public MappingSystem(ILispDAO dao, boolean iterateMask, NotificationPublishService nps, boolean mappingMerge) {
         this.dao = dao;
-        this.notificationService = notifications;
+        this.notificationPublishService = nps;
         this.mappingMerge = mappingMerge;
         buildMapCaches();
 
@@ -181,6 +195,36 @@ public class MappingSystem implements IMappingSystem {
         smc.addData(key, SubKeys.TIME_BUCKET_ID, updatedBucketId);
     }
 
+    @Override
+    public MappingData addNegativeMapping(Eid key) {
+        MappingRecord mapping = buildNegativeMapping(key);
+        MappingData mappingData = new MappingData(mapping);
+        smc.addMapping(mapping.getEid(), mappingData);
+        dsbe.addMapping(DSBEInputUtil.toMapping(MappingOrigin.Southbound, mapping.getEid(), null, mappingData));
+        return mappingData;
+    }
+
+    private MappingRecord buildNegativeMapping(Eid eid) {
+        MappingRecordBuilder recordBuilder = new MappingRecordBuilder();
+        recordBuilder.setAuthoritative(false);
+        recordBuilder.setMapVersion((short) 0);
+        recordBuilder.setEid(eid);
+        if (eid.getAddressType().equals(Ipv4PrefixBinaryAfi.class)
+                || eid.getAddressType().equals(Ipv6PrefixBinaryAfi.class)) {
+            Eid widestNegativePrefix = getWidestNegativePrefix(eid);
+            if (widestNegativePrefix != null) {
+                recordBuilder.setEid(widestNegativePrefix);
+            }
+        }
+        recordBuilder.setAction(LispMessage.NEGATIVE_MAPPING_ACTION);
+        if (getAuthenticationKey(eid) != null) {
+            recordBuilder.setRecordTtl(TTL_RLOC_TIMED_OUT);
+        } else {
+            recordBuilder.setRecordTtl(TTL_NO_RLOC_KNOWN);
+        }
+        return recordBuilder.build();
+    }
+
     /*
      * 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.
@@ -407,13 +451,75 @@ public class MappingSystem implements IMappingSystem {
 
     @Override
     public void removeMapping(MappingOrigin origin, Eid key) {
+        Set<Subscriber> subscribers = null;
         if (origin == MappingOrigin.Southbound) {
             removeFromSbTimeoutService(key);
+            MappingData mapping = (MappingData) smc.getMapping(null, key);
+            if (mapping != null && !mapping.isNegative()) {
+                SimpleImmutableEntry<Eid, Set<Subscriber>> mergedNegativePrefix = computeMergedNegativePrefix(key);
+                if (mergedNegativePrefix != null) {
+                    addNegativeMapping(mergedNegativePrefix.getKey());
+                    subscribers = mergedNegativePrefix.getValue();
+                    try {
+                        notificationPublishService.putNotification(
+                                MSNotificationInputUtil.toMappingChanged(mapping, subscribers, MappingChange.Created));
+                    } catch (InterruptedException e) {
+                        LOG.warn("Notification publication interrupted!");
+                    }
+                }
+            }
         }
         tableMap.get(origin).removeMapping(key);
-        if (notificationService) {
-            // TODO
+    }
+
+    @SuppressWarnings("unchecked")
+    /*
+     * Returns the "merged" prefix and the subscribers of the prefixes that were merged.
+     */
+    private SimpleImmutableEntry<Eid, Set<Subscriber>> computeMergedNegativePrefix(Eid eid) {
+        // Variable to hold subscribers we collect along the way
+        Set<Subscriber> subscribers = null;
+
+        // If prefix sibling has a negative mapping, save its subscribers
+        Eid sibling = smc.getSiblingPrefix(eid);
+        MappingData mapping = (MappingData) smc.getMapping(null, sibling);
+        if (mapping != null && mapping.isNegative()) {
+            subscribers = (Set<Subscriber>) getData(MappingOrigin.Southbound, eid, SubKeys.SUBSCRIBERS);
+        } else {
+            return null;
+        }
+
+        Eid currentNode = sibling;
+        Eid previousNode = sibling;
+        while ((currentNode = smc.getVirtualParentSiblingPrefix(currentNode)) != null) {
+            mapping = (MappingData) smc.getMapping(null, currentNode);
+            if (mapping != null && mapping.isNegative()) {
+                subscribers.addAll((Set<Subscriber>)
+                        getData(MappingOrigin.Southbound, currentNode, SubKeys.SUBSCRIBERS));
+                removeSbMapping(currentNode, mapping);
+            } else {
+                break;
+            }
+            previousNode = currentNode;
+        }
+        return new SimpleImmutableEntry<>(getVirtualParent(previousNode), subscribers);
+    }
+
+    private static Eid getVirtualParent(Eid eid) {
+        if (eid.getAddress() instanceof Ipv4PrefixBinary) {
+            Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
+            short parentPrefixLength = (short) (prefix.getIpv4MaskLength() - 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);
+            byte[] parentPrefix = MaskUtil.normalizeByteArray(prefix.getIpv6AddressBinary().getValue(),
+                    parentPrefixLength);
+            return LispAddressUtil.asIpv6PrefixBinaryEid(eid, parentPrefix, parentPrefixLength);
         }
+        return null;
     }
 
     @Override
index b8bfe9f806e25230733cd749459b962028365569..1be9e16b5191f69ed27840c1691c78537ee178f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Contextream, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014, 2017 Contextream, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -46,7 +46,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.ei
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecord;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItemBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapreplymessage.MapReplyBuilder;
@@ -59,9 +58,6 @@ import org.slf4j.LoggerFactory;
 public class MapResolver implements IMapResolverAsync {
     protected static final Logger LOG = LoggerFactory.getLogger(MapResolver.class);
 
-    private static final int TTL_RLOC_TIMED_OUT = 1;
-    private static final int TTL_NO_RLOC_KNOWN = 15;
-
     private IMappingService mapService;
     private boolean subscriptionService;
     private String elpPolicy;
@@ -113,8 +109,7 @@ public class MapResolver implements IMapResolverAsync {
             MappingData mappingData = mapService.getMapping(srcEid, eidRecord.getEid());
             MappingRecord mapping;
             if (mappingData == null) {
-                mapping = getNegativeMapping(eidRecord.getEid());
-                mapService.addMapping(MappingOrigin.Southbound, mapping.getEid(), null, new MappingData(mapping));
+                mapping = mapService.addNegativeMapping(eidRecord.getEid()).getRecord();
             } else {
                 mapping = mappingData.getRecord();
             }
@@ -183,27 +178,6 @@ public class MapResolver implements IMapResolverAsync {
         }
     }
 
-    private MappingRecord getNegativeMapping(Eid eid) {
-        MappingRecordBuilder recordBuilder = new MappingRecordBuilder();
-        recordBuilder.setAuthoritative(false);
-        recordBuilder.setMapVersion((short) 0);
-        recordBuilder.setEid(eid);
-        if (eid.getAddressType().equals(Ipv4PrefixBinaryAfi.class)
-                || eid.getAddressType().equals(Ipv6PrefixBinaryAfi.class)) {
-            Eid widestNegativePrefix = mapService.getWidestNegativePrefix(eid);
-            if (widestNegativePrefix != null) {
-                recordBuilder.setEid(widestNegativePrefix);
-            }
-        }
-        recordBuilder.setAction(Action.NativelyForward);
-        if (authenticate && mapService.getAuthenticationKey(eid) != null) {
-            recordBuilder.setRecordTtl(TTL_RLOC_TIMED_OUT);
-        } else {
-            recordBuilder.setRecordTtl(TTL_NO_RLOC_KNOWN);
-        }
-        return recordBuilder.build();
-    }
-
     private void updateSubscribers(Rloc itrRloc, Eid reqEid, Eid mapEid, Eid srcEid, Integer recordTtl) {
         Subscriber subscriber = new Subscriber(itrRloc, srcEid, Subscriber.recordTtlToSubscriberTime(recordTtl));
         Eid subscribedEid = mapEid;
index 4fda63c955e102246dd44de2ce9c6a69510e9e29..225bce15060759fbf1e83b13ca517f630f738fa6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Contextream, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014, 2017 Contextream, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -45,6 +45,7 @@ import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier;
 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
 import org.opendaylight.lispflowmapping.lisp.util.MapNotifyBuilderHelper;
 import org.opendaylight.lispflowmapping.lisp.util.MapRequestUtil;
+import org.opendaylight.lispflowmapping.lisp.util.MappingRecordUtil;
 import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
@@ -102,6 +103,7 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS
     @SuppressWarnings("unchecked")
     public void handleMapRegister(MapRegister mapRegister) {
         boolean mappingUpdated = false;
+        boolean oldMappingRemoved = false;
         boolean merge = ConfigIni.getInstance().mappingMergeIsSet() && mapRegister.isMergeEnabled();
         Set<Subscriber> subscribers = null;
         MappingRecord oldMapping;
@@ -124,6 +126,10 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS
 
             oldMapping = getMappingRecord(mapService.getMapping(MappingOrigin.Southbound, eid));
             mapService.addMapping(MappingOrigin.Southbound, eid, getSiteId(mapRegister), mappingData);
+            if (oldMapping != null && MappingRecordUtil.isNegativeMapping(oldMapping)) {
+                mapService.removeMapping(MappingOrigin.Southbound, oldMapping.getEid());
+                oldMappingRemoved = true;
+            }
 
             if (subscriptionService) {
                 MappingRecord newMapping = merge
@@ -139,6 +145,10 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS
                         subscribers = addParentSubscribers(eid, subscribers);
                     }
                     sendSmrs(eid, subscribers);
+                    if (oldMapping != null && oldMappingRemoved && !oldMapping.getEid().equals(eid)) {
+                        subscribers = getSubscribers(oldMapping.getEid());
+                        sendSmrs(oldMapping.getEid(), subscribers);
+                    }
                     mappingUpdated = true;
                 }
             }
index 45702943068c355e84c089eed4e8bffb18e1e9e9..02ceaa375aea6aef738839c54598516e7adc0b2d 100644 (file)
@@ -27,6 +27,7 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
+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;
@@ -87,8 +88,9 @@ public class MappingSystemTest {
     @Mock private static IMapCache pmcMock;
     @Mock private static IAuthKeyDb akdbMock;
     @Mock private static DataStoreBackEnd dsbeMock;
+    @Mock private static NotificationPublishService npsMock;
     @Mock private static EnumMap<MappingOrigin, IMapCache> tableMapMock;
-    @InjectMocks private static MappingSystem mappingSystem = new MappingSystem(daoMock, false, true, true);
+    @InjectMocks private static MappingSystem mappingSystem = new MappingSystem(daoMock, false, npsMock, true);
 
     private static final String IPV4_SRC =      "127.0.0.1";
     private static final String IPV4_DST =      "192.168.0.1";
@@ -434,7 +436,7 @@ public class MappingSystemTest {
      */
     @Test
     public void removeMappingTest_sb() throws NoSuchFieldException, IllegalAccessException {
-        mappingSystem = new MappingSystem(daoMock, false, true, false);
+        mappingSystem = new MappingSystem(daoMock, false, npsMock, false);
         injectMocks();
         Mockito.when(tableMapMock.get(MappingOrigin.Southbound)).thenReturn(smcMock);
 
@@ -564,7 +566,7 @@ public class MappingSystemTest {
         Mockito.verify(smcMock).printMappings();
 
         mappingSystem.destroy();
-        mappingSystem = new MappingSystem(daoMock, true, true, true);
+        mappingSystem = new MappingSystem(daoMock, true, npsMock, true);
         mappingSystem.setDataStoreBackEnd(dsbeMock);
         mappingSystem.setMappingMerge(false);
         mappingSystem.setIterateMask(true);
index b0e82c7fe6aef7e6bec9f3ce36dc0d12f6dd51a4..632bbc27c2528666caae9a12c777d6417df90a64 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2016, 2017 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -22,6 +22,7 @@ import org.opendaylight.lispflowmapping.implementation.LispMappingService;
 import org.opendaylight.lispflowmapping.implementation.MappingService;
 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
 import org.opendaylight.lispflowmapping.interfaces.dao.Subscriber;
+import org.opendaylight.lispflowmapping.lisp.type.LispMessage;
 import org.opendaylight.lispflowmapping.lisp.type.MappingData;
 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
 import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper;
@@ -49,7 +50,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.ei
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItemBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.authkey.container.MappingAuthkeyBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItemBuilder;
@@ -153,14 +153,13 @@ public class MapResolverTest {
                 .setAuthoritative(false)
                 .setMapVersion((short) 0)
                 .setEid(IPV4_PREFIX_EID_1)
-                .setAction(MappingRecord.Action.NativelyForward)
+                .setAction(LispMessage.NEGATIVE_MAPPING_ACTION)
                 .setRecordTtl(TTL_RLOC_TIMED_OUT);
 
         Mockito.when(mapServiceMock.getMapping(mapRequestBuilder.getSourceEid().getEid(), IPV4_PREFIX_EID_1))
                 .thenReturn(null);
-        Mockito.when(mapServiceMock.getAuthenticationKey(IPV4_PREFIX_EID_1))
-                .thenReturn(new MappingAuthkeyBuilder().build());
-        Mockito.when(mapServiceMock.getWidestNegativePrefix(IPV4_PREFIX_EID_1)).thenReturn(IPV4_PREFIX_EID_1);
+        Mockito.when(mapServiceMock.addNegativeMapping(IPV4_PREFIX_EID_1))
+                .thenReturn(getDefaultMappingData(mappingRecordBuilder.build()));
 
         // result
         final MapReplyBuilder mapReplyBuilder = getDefaultMapReplyBuilder();
index e339fa385696ad2071ac991e3965c33db12db0e2..11e85a5a20bac5cba92f50bb16eb9aeda6c44e7b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Contextream, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014, 2017 Contextream, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -8,9 +8,12 @@
 
 package org.opendaylight.lispflowmapping.lisp.type;
 
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord.Action;
+
 public interface LispMessage {
     int PORT_NUM = 4342;
     int XTR_PORT_NUM = 4343;
+    Action NEGATIVE_MAPPING_ACTION = Action.NativelyForward;
 
     interface Pos {
         int TYPE = 0;
index b875e43393ea8b6f071b9de3c5cd9b6e6748c459..c66e0c68ac2e056db7787ce8df4b79508ac1e74f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2016, 2017 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -9,6 +9,7 @@
 package org.opendaylight.lispflowmapping.lisp.type;
 
 import java.util.Date;
+import org.opendaylight.lispflowmapping.lisp.util.MappingRecordUtil;
 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.mapping.record.container.MappingRecord;
 
@@ -69,6 +70,22 @@ public class MappingData {
         this.mergeEnabled = mergeEnabled;
     }
 
+    public Boolean isNegative() {
+        if (record != null) {
+            return MappingRecordUtil.isNegativeMapping(record);
+        } else {
+            return null;
+        }
+    }
+
+    public Boolean isPositive() {
+        if (record != null) {
+            return MappingRecordUtil.isPositiveMapping(record);
+        } else {
+            return null;
+        }
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("MappingData [");
diff --git a/mappingservice/lisp-proto/src/main/java/org/opendaylight/lispflowmapping/lisp/util/MappingRecordUtil.java b/mappingservice/lisp-proto/src/main/java/org/opendaylight/lispflowmapping/lisp/util/MappingRecordUtil.java
new file mode 100644 (file)
index 0000000..9c54ac9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.lispflowmapping.lisp.util;
+
+import java.util.List;
+import org.opendaylight.lispflowmapping.lisp.type.LispMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecord;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for MappingRecord objects.
+ *
+ * @author Lorand Jakab
+ *
+ */
+public final class MappingRecordUtil {
+    protected static final Logger LOG = LoggerFactory.getLogger(MappingRecordUtil.class);
+
+    // Utility class, should not be instantiated
+    private MappingRecordUtil() {
+    }
+
+    public static boolean isNegativeMapping(MappingRecord mapping) {
+        List<LocatorRecord> rlocs = mapping.getLocatorRecord();
+        if (mapping.getAction() == LispMessage.NEGATIVE_MAPPING_ACTION && (rlocs == null || rlocs.isEmpty())) {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean isPositiveMapping(MappingRecord mapping) {
+        return !isNegativeMapping(mapping);
+    }
+}
index 6fa17c40c69efe76190e3540aa97970c3f535ffb..2204dec8ba3d34e76bcfdf35c87fc4c02bfe9bdb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Contextream, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014, 2017 Contextream, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -179,7 +179,7 @@ public final class MaskUtil {
         return InetAddress.getByAddress(normalizeByteArray(address.getAddress(), (short) maskLength));
     }
 
-    private static byte[] normalizeByteArray(byte[] address, short maskLength) {
+    public static byte[] normalizeByteArray(byte[] address, short maskLength) {
         ByteBuffer byteRepresentation = ByteBuffer.wrap(address);
         byte byteMask = (byte) 0xff;
         int mask = maskLength;
index 764104a1146df2547efb32b3c436060aa3299b4d..636d1655462f483a7b0c51b43ab653920de4c0a4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2015, 2017 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -171,22 +171,39 @@ public class SimpleMapCache implements ILispMapCache {
 
     @Override
     public Eid getParentPrefix(Eid eid) {
-        Eid key = MaskUtil.normalize(eid);
-        ILispDAO table = getVniTable(key);
+        ILispDAO table = getVniTable(eid);
+        if (table == null) {
+            return null;
+        }
+        return table.getParentPrefix(MaskUtil.normalize(eid));
+    }
+
+    @Override
+    public Eid getSiblingPrefix(Eid eid) {
+        ILispDAO table = getVniTable(eid);
         if (table == null) {
             return null;
         }
-        return table.getParentPrefix(key);
+        return table.getSiblingPrefix(MaskUtil.normalize(eid));
+    }
+
+    @Override
+    public Eid getVirtualParentSiblingPrefix(Eid eid) {
+        ILispDAO table = getVniTable(eid);
+        if (table == null) {
+            return null;
+        }
+        return table.getVirtualParentSiblingPrefix(MaskUtil.normalize(eid));
     }
 
     @Override
     public void removeMapping(Eid eid) {
-        Eid key = MaskUtil.normalize(eid);
-        ILispDAO table = getVniTable(key);
+        ILispDAO table = getVniTable(eid);
         if (table == null) {
             return;
         }
 
+        Eid key = MaskUtil.normalize(eid);
         // We intentionally don't remove subscribers, so in case a mapping is re-added, they get notified
         table.removeSpecific(key, SubKeys.RECORD);
         table.removeSpecific(key, SubKeys.SRC_RLOCS);
@@ -196,11 +213,11 @@ public class SimpleMapCache implements ILispMapCache {
 
     @Override
     public void removeMapping(Eid eid, XtrId xtrId) {
-        Eid key = MaskUtil.normalize(eid);
-        ILispDAO table = getVniTable(key);
+        ILispDAO table = getVniTable(eid);
         if (table == null) {
             return;
         }
+        Eid key = MaskUtil.normalize(eid);
         ILispDAO xtrIdTable = (ILispDAO) table.getSpecific(key, SubKeys.XTRID_RECORDS);
         if (xtrIdTable == null) {
             return;
@@ -210,11 +227,11 @@ public class SimpleMapCache implements ILispMapCache {
 
     @Override
     public void removeXtrIdMappings(Eid eid, List<XtrId> xtrIds) {
-        Eid key = MaskUtil.normalize(eid);
-        ILispDAO table = getVniTable(key);
+        ILispDAO table = getVniTable(eid);
         if (table == null) {
             return;
         }
+        Eid key = MaskUtil.normalize(eid);
         ILispDAO xtrIdTable = (ILispDAO) table.getSpecific(key, SubKeys.XTRID_RECORDS);
         if (xtrIdTable == null) {
             return;
@@ -226,8 +243,8 @@ public class SimpleMapCache implements ILispMapCache {
 
     @Override
     public void addData(Eid eid, String subKey, Object data) {
+        ILispDAO table = getOrInstantiateVniTable(eid);
         Eid key = MaskUtil.normalize(eid);
-        ILispDAO table = getOrInstantiateVniTable(key);
         table.put(key, new MappingEntry<>(subKey, data));
     }