CORD-1304 Set of changes for fabric routing to optimize use of ECMP groups

Also removing some old demo code in the SR app
Adding a couple of CLI commands for debugging
Bug fix in the DistributedGroupStore for group_exists error message
Bug fixes for ofdpa driver:
    - synchronized update of flowObjectiveStore when buckets are added to or removed from groups
      to avoid one thread from overwriting an update from another thread doing an update at the same time
    - addBucketToL2FloodGroup now updates flowObjectiveStore after accounting for changes
    - addBucketToHashGroup accounts for all added buckets, not just the first one

Change-Id: I6207c1c3c1b4379986805d73a73bc460fea8fe3f
diff --git a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index 850962a..ca24e00 100644
--- a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -34,6 +34,7 @@
 import org.onosproject.segmentrouting.DefaultRoutingHandler.PortFilterInfo;
 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
 import org.onosproject.segmentrouting.config.DeviceConfiguration;
+import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Port;
@@ -326,10 +327,10 @@
         // is not set.
         if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
             tbuilder.immediate().decNwTtl();
-            ns = new NeighborSet(nextHops, false);
+            ns = new NeighborSet(nextHops, false, destSw);
             treatment = tbuilder.build();
         } else {
-            ns = new NeighborSet(nextHops, false, segmentId);
+            ns = new NeighborSet(nextHops, false, segmentId, destSw);
             treatment = null;
         }
 
@@ -338,8 +339,14 @@
         // other neighboring routers, there is no subnet assigned on those ports.
         TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder(selector);
         metabuilder.matchVlanId(SegmentRoutingManager.INTERNAL_VLAN);
+        DefaultGroupHandler grpHandler = srManager.getGroupHandler(deviceId);
+        if (grpHandler == null) {
+            log.warn("populateIPRuleForRouter: groupHandler for device {} "
+                    + "not found", deviceId);
+            return false;
+        }
 
-        int nextId = srManager.getNextObjectiveId(deviceId, ns, metabuilder.build());
+        int nextId = grpHandler.getNextObjectiveId(ns, metabuilder.build(), true);
         if (nextId <= 0) {
             log.warn("No next objective in {} for ns: {}", deviceId, ns);
             return false;
@@ -356,10 +363,8 @@
         if (treatment != null) {
             fwdBuilder.withTreatment(treatment);
         }
-        log.debug("Installing IPv4 forwarding objective "
-                        + "for router IP/subnet {} in switch {}",
-                ipPrefix,
-                deviceId);
+        log.debug("Installing IPv4 forwarding objective for router IP/subnet {} "
+                + "in switch {} with nextId: {}", ipPrefix, deviceId, nextId);
         ObjectiveContext context = new DefaultObjectiveContext(
                 (objective) -> log.debug("IP rule for router {} populated in dev:{}",
                                          ipPrefix, deviceId),
@@ -438,7 +443,7 @@
         if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
             // If the next hop is the destination router for the segment, do pop
             log.debug("populateMplsRule: Installing MPLS forwarding objective for "
-                              + "label {} in switch {} with pop", segmentId, targetSwId);
+                    + "label {} in switch {} with pop", segmentId, targetSwId);
             // Not-bos pop case (php for the current label). If MPLS-ECMP
             // has been configured, the application we will request the
             // installation for an MPLS-ECMP group.
@@ -448,7 +453,8 @@
                                                true,
                                                isMplsBos,
                                                metabuilder.build(),
-                                               routerIp);
+                                               routerIp,
+                                               destSwId);
             // Error case, we cannot handle, exit.
             if (fwdObjNoBosBuilder == null) {
                 return Collections.emptyList();
@@ -457,8 +463,8 @@
 
         } else {
             // next hop is not destination, SR CONTINUE case (swap with self)
-            log.debug("Installing MPLS forwarding objective for "
-                              + "label {} in switch {} without pop", segmentId, targetSwId);
+            log.debug("Installing MPLS forwarding objective for label {} in "
+                    + "switch {} without pop", segmentId, targetSwId);
             // Not-bos pop case. If MPLS-ECMP has been configured, the
             // application we will request the installation for an MPLS-ECMP
             // group.
@@ -468,7 +474,8 @@
                                                false,
                                                isMplsBos,
                                                metabuilder.build(),
-                                               routerIp);
+                                               routerIp,
+                                               destSwId);
             // Error case, we cannot handle, exit.
             if (fwdObjNoBosBuilder == null) {
                 return Collections.emptyList();
@@ -561,7 +568,8 @@
                                              boolean phpRequired,
                                              boolean isBos,
                                              TrafficSelector meta,
-                                             IpAddress routerIp) {
+                                             IpAddress routerIp,
+                                             DeviceId destSw) {
 
         ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
                 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
@@ -592,11 +600,11 @@
         fwdBuilder.withTreatment(tbuilder.build());
         // if MPLS-ECMP == True we will build a standard NeighborSet.
         // Otherwise a RandomNeighborSet.
-        NeighborSet ns = NeighborSet.neighborSet(false, nextHops, false);
+        NeighborSet ns = NeighborSet.neighborSet(false, nextHops, false, destSw);
         if (!isBos && this.srManager.getMplsEcmp()) {
-            ns = NeighborSet.neighborSet(false, nextHops, true);
+            ns = NeighborSet.neighborSet(false, nextHops, true, destSw);
         } else if (!isBos && !this.srManager.getMplsEcmp()) {
-            ns = NeighborSet.neighborSet(true, nextHops, true);
+            ns = NeighborSet.neighborSet(true, nextHops, true, destSw);
         }
         log.debug("Trying to get a nextObjId for mpls rule on device:{} to ns:{}",
                   deviceId, ns);
@@ -606,7 +614,13 @@
         // MPLS-ECMP.
         // The metadata informs the driver that the next-Objective will be used
         // by MPLS flows and if Bos == False the driver will use MPLS groups.
-        int nextId = srManager.getNextObjectiveId(deviceId, ns, meta, isBos);
+        DefaultGroupHandler grpHandler = srManager.getGroupHandler(deviceId);
+        if (grpHandler == null) {
+            log.warn("populateIPRuleForRouter: groupHandler for device {} "
+                    + "not found", deviceId);
+            return null;
+        }
+        int nextId = grpHandler.getNextObjectiveId(ns, meta, isBos);
         if (nextId <= 0) {
             log.warn("No next objective in {} for ns: {}", deviceId, ns);
             return null;
@@ -710,13 +724,13 @@
             // error encountered during build
             return false;
         }
-        log.info("{} filtering objectives for dev/port:{}/{}", (install ? "Installing" : "Removing"),
-                deviceId, portnum);
+        log.debug("{} filtering objectives for dev/port:{}/{}",
+                 install ? "Installing" : "Removing", deviceId, portnum);
         ObjectiveContext context = new DefaultObjectiveContext(
                 (objective) -> log.debug("Filter for {}/{} {}", deviceId, portnum,
-                        (install ? "installed" : "removed")),
+                        install ? "installed" : "removed"),
                 (objective, error) -> log.warn("Failed to {} filter for {}/{}: {}",
-                        (install ? "install" : "remove"), deviceId, portnum, error));
+                        install ? "install" : "remove", deviceId, portnum, error));
         if (install) {
             srManager.flowObjectiveService.filter(deviceId, fob.add(context));
         } else {
@@ -894,10 +908,6 @@
      * priority Bridging Table entries to a group that contains all ports of
      * its subnet.
      *
-     * Note: We assume that packets sending from the edge switches to the hosts
-     * have untagged VLAN.
-     * The VLAN tag will be popped later in the flooding group.
-     *
      * @param deviceId switch ID to set the rules
      */
     public void populateSubnetBroadcastRule(DeviceId deviceId) {