CORD-45 CORD-394
Bugfix in group store - group delete state updated correctly.
SR app no longer deletes buckets in existing groups - workaround for OFDPA bug.
Instead it invalidates the entire group, thereby forcing new group creation.
Also incorporating Charles' changes to remove state from group and flow stores,
and the SR app when device goes offline.

Change-Id: I162d3fb6bf709a8f02b01b8d57e131c2bac9b46b
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index 9e24da4..df340a9 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -561,4 +561,9 @@
             statusLock.unlock();
         }
     }
+
+    public void purgeEcmpGraph(DeviceId deviceId) {
+        currentEcmpSpgMap.remove(deviceId);
+        updatedEcmpSpgMap.remove(deviceId);
+    }
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 2cc5aae..e94c344 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -30,6 +30,7 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.util.KryoNamespace;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.event.Event;
@@ -139,6 +140,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected NetworkConfigRegistry cfgService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService compCfgService;
+
     protected ArpHandler arpHandler = null;
     protected IcmpHandler icmpHandler = null;
     protected IpHandler ipHandler = null;
@@ -323,6 +327,11 @@
                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
                 .build();
 
+        compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
+                "purgeOnDisconnection", "true");
+        compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
+                "purgeOnDisconnection", "true");
+
         processor = new InternalPacketProcessor();
         linkListener = new InternalLinkListener();
         deviceListener = new InternalDeviceListener();
@@ -676,15 +685,11 @@
                             log.info("Processing device event {} for available device {}",
                                      event.type(), ((Device) event.subject()).id());
                             processDeviceAdded((Device) event.subject());
-                        } /* else {
-                            if (event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
-                                // availability changed and not available - dev gone
-                                DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
-                                if (groupHandler != null) {
-                                    groupHandler.removeAllGroups();
-                                }
-                            }
-                        }*/
+                        } else {
+                            log.info("Processing device event {} for unavailable device {}",
+                                    event.type(), ((Device) event.subject()).id());
+                            processDeviceRemoved((Device) event.subject());
+                        }
                     } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
                         processPortRemoved((Device) event.subject(),
                                            ((DeviceEvent) event).port());
@@ -793,6 +798,42 @@
         netcfgHandler.initVRouters(device.id());
     }
 
+    private void processDeviceRemoved(Device device) {
+        nsNextObjStore.entrySet().stream()
+                .filter(entry -> entry.getKey().deviceId().equals(device.id()))
+                .forEach(entry -> {
+                    nsNextObjStore.remove(entry.getKey());
+                });
+
+        subnetNextObjStore.entrySet().stream()
+                .filter(entry -> entry.getKey().deviceId().equals(device.id()))
+                .forEach(entry -> {
+                    subnetNextObjStore.remove(entry.getKey());
+                });
+
+        portNextObjStore.entrySet().stream()
+                .filter(entry -> entry.getKey().deviceId().equals(device.id()))
+                .forEach(entry -> {
+                    portNextObjStore.remove(entry.getKey());
+                });
+
+        xConnectNextObjStore.entrySet().stream()
+                .filter(entry -> entry.getKey().deviceId().equals(device.id()))
+                .forEach(entry -> {
+                    xConnectNextObjStore.remove(entry.getKey());
+                });
+
+        subnetVidStore.entrySet().stream()
+                .filter(entry -> entry.getKey().deviceId().equals(device.id()))
+                .forEach(entry -> {
+                    subnetVidStore.remove(entry.getKey());
+                });
+
+        groupHandlerMap.remove(device.id());
+
+        defaultRoutingHandler.purgeEcmpGraph(device.id());
+    }
+
     private void processPortRemoved(Device device, Port port) {
         log.debug("Port {} was removed", port.toString());
         DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
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 4e64c4b..0243693 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
@@ -288,6 +288,7 @@
             return;
         }
 
+        @SuppressWarnings("unused")
         MacAddress dstMac;
         try {
             dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
@@ -312,9 +313,17 @@
         log.debug("portDown: nsNextObjStore contents for device {}:{}",
                   deviceId, nsSet);
         for (NeighborSet ns : nsSet) {
-            Integer nextId = nsNextObjStore.
-                    get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
+            NeighborSetNextObjectiveStoreKey nsStoreKey =
+                    new NeighborSetNextObjectiveStoreKey(deviceId, ns);
+            Integer nextId = nsNextObjStore.get(nsStoreKey);
             if (nextId != null && isMaster) {
+                // XXX This is a workaround for BUG (CORD-611) in current switches.
+                // Should be temporary because this workaround prevents correct
+                // functionality in LAG recovery.
+                log.info("**portDown port:{} in device {}: Invalidating nextId {}",
+                         port, deviceId, nextId);
+                nsNextObjStore.remove(nsStoreKey);
+                /*
                 log.info("**portDown in device {}: Removing Bucket "
                         + "with Port {} to next object id {}",
                         deviceId,
@@ -341,7 +350,7 @@
                         removeFromExisting(new SRNextObjectiveContext(deviceId));
 
                 flowObjectiveService.next(deviceId, nextObjective);
-
+                */
                 // the removal of a bucket may actually change the neighborset
                 // update the global store
                 /*
diff --git a/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java b/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
index 520c65d..0cf77b3 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
@@ -769,6 +769,9 @@
                 existing.state());
         synchronized (existing) {
             existing.setState(GroupState.PENDING_DELETE);
+            getGroupStoreKeyMap().
+                put(new GroupStoreKeyMapKey(existing.deviceId(), existing.appCookie()),
+                    existing);
         }
         log.debug("deleteGroupDescriptionInternal: in device {} issuing GROUP_REMOVE_REQUESTED",
                   deviceId);