ONOS-1823 and ONOS-1838:Segment Routing Multi-instance Support-1

Change-Id: I3cc848415a609a9c4001d135e51104c62fb2830d
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 1d9f4ec..d9e6b2c 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -26,6 +26,7 @@
 import java.util.List;
 import java.util.Random;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
@@ -42,6 +43,7 @@
 import org.onosproject.net.group.DefaultGroupKey;
 import org.onosproject.net.group.GroupKey;
 import org.onosproject.net.link.LinkService;
+import org.onosproject.store.service.EventuallyConsistentMap;
 import org.slf4j.Logger;
 
 /**
@@ -66,8 +68,10 @@
             new HashMap<DeviceId, Set<PortNumber>>();
     protected HashMap<PortNumber, DeviceId> portDeviceMap =
             new HashMap<PortNumber, DeviceId>();
-    protected HashMap<GroupKey, Integer> deviceNextObjectiveIds =
-            new HashMap<GroupKey, Integer>();
+    //protected HashMap<NeighborSet, Integer> deviceNextObjectiveIds =
+    //        new HashMap<NeighborSet, Integer>();
+    protected EventuallyConsistentMap<
+        NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
     protected Random rand = new Random();
 
     protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
@@ -81,7 +85,10 @@
     protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
                                   DeviceProperties config,
                                   LinkService linkService,
-                                  FlowObjectiveService flowObjService) {
+                                  FlowObjectiveService flowObjService,
+                                  EventuallyConsistentMap<
+                                  NeighborSetNextObjectiveStoreKey,
+                                  Integer> nsNextObjStore) {
         this.deviceId = checkNotNull(deviceId);
         this.appId = checkNotNull(appId);
         this.deviceConfig = checkNotNull(config);
@@ -91,6 +98,7 @@
         isEdgeRouter = config.isEdgeDevice(deviceId);
         nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
         this.flowObjectiveService = flowObjService;
+        this.nsNextObjStore = nsNextObjStore;
 
         populateNeighborMaps();
     }
@@ -111,13 +119,20 @@
                                                          ApplicationId appId,
                                                          DeviceProperties config,
                                                          LinkService linkService,
-                                                         FlowObjectiveService flowObjService) {
+                                                         FlowObjectiveService flowObjService,
+                                                         EventuallyConsistentMap<
+                                                         NeighborSetNextObjectiveStoreKey,
+                                                         Integer> nsNextObjStore) {
         if (config.isEdgeDevice(deviceId)) {
             return new DefaultEdgeGroupHandler(deviceId, appId, config,
-                                               linkService, flowObjService);
+                                               linkService,
+                                               flowObjService,
+                                               nsNextObjStore);
         } else {
             return new DefaultTransitGroupHandler(deviceId, appId, config,
-                                                  linkService, flowObjService);
+                                                  linkService,
+                                                  flowObjService,
+                                                  nsNextObjStore);
         }
     }
 
@@ -150,12 +165,56 @@
 
         log.debug("Device {} linkUp at local port {} to neighbor {}", deviceId,
                   newLink.src().port(), newLink.dst().deviceId());
-        if (devicePortMap.get(newLink.dst().deviceId()) == null) {
+        addNeighborAtPort(newLink.dst().deviceId(),
+                          newLink.src().port());
+        /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
             // New Neighbor
             newNeighbor(newLink);
         } else {
             // Old Neighbor
             newPortToExistingNeighbor(newLink);
+        }*/
+        Set<NeighborSet> nsSet = nsNextObjStore.keySet()
+                .stream()
+                .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
+                .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
+                .filter((ns) -> (ns.getDeviceIds()
+                        .contains(newLink.dst().deviceId())))
+                .collect(Collectors.toSet());
+        log.trace("linkUp: nsNextObjStore contents for device {}:",
+                  deviceId,
+                  nsSet);
+        for (NeighborSet ns : nsSet) {
+            // Create the new bucket to be updated
+            TrafficTreatment.Builder tBuilder =
+                    DefaultTrafficTreatment.builder();
+            tBuilder.setOutput(newLink.src().port())
+                    .setEthDst(deviceConfig.getDeviceMac(
+                          newLink.dst().deviceId()))
+                    .setEthSrc(nodeMacAddr);
+            if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
+                tBuilder.pushMpls()
+                        .setMpls(MplsLabel.
+                                 mplsLabel(ns.getEdgeLabel()));
+            }
+
+            Integer nextId = nsNextObjStore.
+                    get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
+            if (nextId != null) {
+                NextObjective.Builder nextObjBuilder = DefaultNextObjective
+                        .builder().withId(nextId)
+                        .withType(NextObjective.Type.HASHED).fromApp(appId);
+
+                nextObjBuilder.addTreatment(tBuilder.build());
+
+                log.debug("linkUp in device {}: Adding Bucket "
+                        + "with Port {} to next object id {}",
+                        deviceId,
+                        newLink.src().port(),
+                        nextId);
+                NextObjective nextObjective = nextObjBuilder.add();
+                flowObjectiveService.next(deviceId, nextObjective);
+            }
         }
     }
 
@@ -171,10 +230,20 @@
         }
         log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
                   portDeviceMap.get(port));
-        Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
+        /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
                                                                                 .get(port),
                                                                         devicePortMap
-                                                                                .keySet());
+                                                                                .keySet());*/
+        Set<NeighborSet> nsSet = nsNextObjStore.keySet()
+                .stream()
+                .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
+                .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
+                .filter((ns) -> (ns.getDeviceIds()
+                        .contains(portDeviceMap.get(port))))
+                .collect(Collectors.toSet());
+        log.trace("portDown: nsNextObjStore contents for device {}:",
+                  deviceId,
+                  nsSet);
         for (NeighborSet ns : nsSet) {
             // Create the bucket to be removed
             TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
@@ -187,13 +256,19 @@
                                                     .getEdgeLabel()));
             }
 
-            Integer nextId = deviceNextObjectiveIds.get(getGroupKey(ns));
+            Integer nextId = nsNextObjStore.
+                    get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
             if (nextId != null) {
                 NextObjective.Builder nextObjBuilder = DefaultNextObjective
                         .builder().withType(NextObjective.Type.SIMPLE).withId(nextId).fromApp(appId);
 
                 nextObjBuilder.addTreatment(tBuilder.build());
 
+                log.debug("portDown in device {}: Removing Bucket "
+                        + "with Port {} to next object id {}",
+                        deviceId,
+                        port,
+                        nextId);
                 NextObjective nextObjective = nextObjBuilder.remove();
 
                 flowObjectiveService.next(deviceId, nextObjective);
@@ -214,14 +289,31 @@
      * @return int if found or -1
      */
     public int getNextObjectiveId(NeighborSet ns) {
-        Integer nextId = deviceNextObjectiveIds.get(getGroupKey(ns));
+        Integer nextId = nsNextObjStore.
+                get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
         if (nextId == null) {
+            log.trace("getNextObjectiveId in device{}: Next objective id "
+                    + "not found for {} and creating", deviceId, ns);
+            log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
+                      deviceId,
+                      nsNextObjStore.entrySet()
+                      .stream()
+                      .filter((nsStoreEntry) ->
+                      (nsStoreEntry.getKey().deviceId().equals(deviceId)))
+                      .collect(Collectors.toList()));
             createGroupsFromNeighborsets(Collections.singleton(ns));
-            nextId = deviceNextObjectiveIds.get(getGroupKey(ns));
+            nextId = nsNextObjStore.
+                    get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
             if (nextId == null) {
                 log.warn("getNextObjectiveId: unable to create next objective");
                 return -1;
+            } else {
+                log.debug("getNextObjectiveId in device{}: Next objective id {} "
+                    + "created for {}", deviceId, nextId.intValue(), ns);
             }
+        } else {
+            log.trace("getNextObjectiveId in device{}: Next objective id {} "
+                    + "found for {}", deviceId, nextId.intValue(), ns);
         }
         return nextId.intValue();
     }
@@ -338,6 +430,10 @@
                 if (devicePortMap.get(d) == null) {
                     log.warn("Device {} is not in the port map yet", d);
                     return;
+                } else if (devicePortMap.get(d).size() == 0) {
+                    log.warn("There are no ports for "
+                            + "the Device {} in the port map yet", d);
+                    return;
                 }
 
                 for (PortNumber sp : devicePortMap.get(d)) {
@@ -356,7 +452,11 @@
 
             NextObjective nextObj = nextObjBuilder.add();
             flowObjectiveService.next(deviceId, nextObj);
-            deviceNextObjectiveIds.put(getGroupKey(ns), nextId);
+            log.debug("createGroupsFromNeighborsets: Submited "
+                    + "next objective {} in device {}",
+                    nextId, deviceId);
+            nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
+                               nextId);
         }
     }