Bugfix for stale state not being cleared up when switch goes down.

Change-Id: Ieee11bbc4253789779c6cf2cc29d18c3173d9ec3
diff --git a/app/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/app/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index 46d94ed..240d6e9 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -429,7 +429,7 @@
             if (linkDown == null) {
                 // either a linkUp or a switchDown - compute all route changes by
                 // comparing all routes of existing ECMP SPG to new ECMP SPG
-                routeChanges = computeRouteChange();
+                routeChanges = computeRouteChange(switchDown);
 
                 // deal with linkUp of a seen-before link
                 if (linkUp != null && srManager.linkHandler.isSeenLink(linkUp)) {
@@ -1185,7 +1185,7 @@
      * @return the set of affected routes which may be empty if no routes were
      *         affected
      */
-    private Set<ArrayList<DeviceId>> computeRouteChange() {
+    private Set<ArrayList<DeviceId>> computeRouteChange(DeviceId failedSwitch) {
         ImmutableSet.Builder<ArrayList<DeviceId>> changedRtBldr =
                 ImmutableSet.builder();
 
@@ -1226,6 +1226,22 @@
             }
         }
 
+        // handle clearing state for a failed switch in case the switch does
+        // not have a pair, or the pair is not available
+        if (failedSwitch != null) {
+            DeviceId pairDev = getPairDev(failedSwitch);
+            if (pairDev == null || !srManager.deviceService.isAvailable(pairDev)) {
+                log.debug("Proxy Route changes to downed Sw:{}", failedSwitch);
+                srManager.deviceService.getDevices().forEach(dev -> {
+                    if (!dev.id().equals(failedSwitch) &&
+                            srManager.mastershipService.isLocalMaster(dev.id())) {
+                        log.debug(" : {}", dev.id());
+                        changedRtBldr.add(Lists.newArrayList(dev.id(), failedSwitch));
+                    }
+                });
+            }
+        }
+
         Set<ArrayList<DeviceId>> changedRoutes = changedRtBldr.build();
         for (ArrayList<DeviceId> route: changedRoutes) {
             log.debug("Route changes Target -> Root");
@@ -1353,8 +1369,8 @@
 
         if (pairDev != null) {
             if (!srManager.deviceService.isAvailable(pairDev)) {
-                log.warn("pairedDev {} not available .. routing this dev:{} "
-                        + "without mastership check",
+                log.warn("pairedDev {} not available .. routing both this dev:{} "
+                        + "and pair without mastership check for pair",
                           pairDev, deviceId);
                 return pairDev; // handle both temporarily
             }
diff --git a/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index bd57248..06f7ef0 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -677,6 +677,7 @@
             tbuilder.deferred().decMplsTtl();
             // swap results in MPLS packet with same BoS bit regardless of bit value
             // depending on configuration we can ECMP this packet or choose one output
+            // XXX reconsider types
             if (srManager.getMplsEcmp()) {
                 ds = new DestinationSet(false, true, segmentId, destSw);
             } else {
diff --git a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 37b27ad..65ffb53 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -1139,11 +1139,13 @@
                             event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
                         DeviceId deviceId = ((Device) event.subject()).id();
                         if (deviceService.isAvailable(deviceId)) {
-                            log.info("Processing device event {} for available device {}",
+                            log.info("** DEVICE UP Processing device event {} "
+                                    + "for available device {}",
                                      event.type(), ((Device) event.subject()).id());
                             processDeviceAdded((Device) event.subject());
                         } else {
-                            log.info("Processing device event {} for unavailable device {}",
+                            log.info(" ** DEVICE DOWN Processing device event {}"
+                                    + " for unavailable device {}",
                                      event.type(), ((Device) event.subject()).id());
                             processDeviceRemoved((Device) event.subject());
                         }
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index adfe3f1..fe469d3 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -16,7 +16,6 @@
 package org.onosproject.segmentrouting.grouphandler;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -470,31 +469,29 @@
             Set<DeviceId> currNeighbors = nhops.nextHops(destSw);
             int edgeLabel = dskey.destinationSet().getEdgeLabel(destSw);
             Integer nextId = nhops.nextId();
+            if (currNeighbors == null || nextHops == null) {
+                log.warn("fixing hash groups but found currNeighbors:{} or nextHops:{}"
+                        + " in targetSw:{} for dstSw:{}", currNeighbors,
+                         nextHops, targetSw, destSw);
+                success &= false;
+                continue;
+            }
 
             // some store elements may not be hashed next-objectives - ignore them
             if (isSimpleNextObjective(dskey)) {
-                Set<DeviceId> displayNextHops = nextHops == null ? ImmutableSet.of() : nextHops;
                 log.debug("Ignoring {} of SIMPLE nextObj for targetSw:{}"
                         + " -> dstSw:{} with current nextHops:{} to new"
                         + " nextHops: {} in nextId:{}",
                           (revoke) ? "removal" : "addition", targetSw, destSw,
                           currNeighbors, nextHops, nextId);
-                if ((revoke && !displayNextHops.isEmpty())
-                        || (!revoke && !displayNextHops.equals(currNeighbors))) {
+                if ((revoke && !nextHops.isEmpty())
+                        || (!revoke && !nextHops.equals(currNeighbors))) {
                     log.warn("Simple next objective cannot be edited to "
                             + "move from {} to {}", currNeighbors, nextHops);
                 }
                 continue;
             }
 
-            if (currNeighbors == null || nextHops == null) {
-                log.warn("fixing hash groups but found currNeighbors:{} or nextHops:{}"
-                        + " in targetSw:{} for dstSw:{}", currNeighbors, nextHops,
-                        targetSw, destSw);
-                success &= false;
-                continue;
-            }
-
             Set<DeviceId> diff;
             if (revoke) {
                 diff = Sets.difference(currNeighbors, nextHops);