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/DefaultRoutingHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index 0fa2aca..14187c0 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -89,14 +89,18 @@
         populationStatus = Status.STARTED;
         rulePopulator.resetCounter();
         log.info("Starts to populate routing rules");
+        log.debug("populateAllRoutingRules: populationStatus is STARTED");
 
         for (Device sw : srManager.deviceService.getDevices()) {
             if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) {
+                log.debug("populateAllRoutingRules: skipping device {}...we are not master",
+                          sw.id());
                 continue;
             }
 
             ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(sw.id(), srManager);
             if (!populateEcmpRoutingRules(sw.id(), ecmpSpg)) {
+                log.debug("populateAllRoutingRules: populationStatus is ABORTED");
                 populationStatus = Status.ABORTED;
                 log.debug("Abort routing rule population");
                 return false;
@@ -106,6 +110,7 @@
             // TODO: Set adjacency routing rule for all switches
         }
 
+        log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
         populationStatus = Status.SUCCEEDED;
         log.info("Completes routing rule population. Total # of rules pushed : {}",
                 rulePopulator.getCounter());
@@ -144,6 +149,8 @@
             log.info("Starts rule population from link change");
 
             Set<ArrayList<DeviceId>> routeChanges;
+            log.trace("populateRoutingRulesForLinkStatusChange: "
+                    + "populationStatus is STARTED");
             populationStatus = Status.STARTED;
             if (linkFail == null) {
                 // Compare all routes of existing ECMP SPG with the new ones
@@ -155,16 +162,19 @@
 
             if (routeChanges.isEmpty()) {
                 log.info("No route changes for the link status change");
+                log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
                 populationStatus = Status.SUCCEEDED;
                 return true;
             }
 
             if (repopulateRoutingRulesForRoutes(routeChanges)) {
+                log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
                 populationStatus = Status.SUCCEEDED;
                 log.info("Complete to repopulate the rules. # of rules populated : {}",
                         rulePopulator.getCounter());
                 return true;
             } else {
+                log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
                 populationStatus = Status.ABORTED;
                 log.warn("Failed to repopulate the rules.");
                 return false;
@@ -177,6 +187,7 @@
         for (ArrayList<DeviceId> link: routes) {
             // When only the source device is defined, reinstall routes to all other devices
             if (link.size() == 1) {
+                log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
                 ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(link.get(0), srManager);
                 if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
                     currentEcmpSpgMap.put(link.get(0), ecmpSpg);
@@ -187,8 +198,7 @@
             } else {
                 DeviceId src = link.get(0);
                 DeviceId dst = link.get(1);
-                log.trace("repopulateRoutingRulesForRoutes: running ECMP graph "
-                        + "for device {}", dst);
+                log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", dst);
                 ECMPShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
                 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
                         ecmpSpg.getAllLearnedSwitchesAndVia();
@@ -278,14 +288,12 @@
             log.debug("Checking route change for switch {}", sw.id());
             ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
             if (ecmpSpg == null) {
-                log.debug("No existing ECMP path for Switch {}", sw.id());
+                log.debug("No existing ECMP graph for device {}", sw.id());
                 ArrayList<DeviceId> route = new ArrayList<>();
                 route.add(sw.id());
                 routes.add(route);
                 continue;
             }
-            log.debug("computeRouteChange: running ECMP graph "
-                    + "for device {}", sw.id());
             ECMPShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(sw.id());
             currentEcmpSpgMap.put(sw.id(), newEcmpSpg);
             HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
@@ -400,6 +408,8 @@
         // rule for both subnet and router IP.
         if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) {
             List<Ip4Prefix> subnets = config.getSubnets(destSw);
+            log.debug("populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
+                    targetSw, destSw, subnets);
             result = rulePopulator.populateIpRuleForSubnet(targetSw,
                                                            subnets,
                                                            destSw,
@@ -410,6 +420,8 @@
 
             Ip4Address routerIp = config.getRouterIp(destSw);
             IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
+            log.debug("populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
+                    targetSw, destSw, routerIpPrefix);
             result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
             if (!result) {
                 return false;
@@ -419,6 +431,8 @@
         } else if (config.isEdgeDevice(targetSw)) {
             Ip4Address routerIp = config.getRouterIp(destSw);
             IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
+            log.debug("populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
+                    targetSw, destSw, routerIpPrefix);
             result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
             if (!result) {
                 return false;
@@ -426,6 +440,8 @@
         }
 
         // Populates MPLS rules to all routers
+        log.debug("populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
+                targetSw, destSw);
         result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
         if (!result) {
             return false;
@@ -453,9 +469,13 @@
     public void startPopulationProcess() {
         synchronized (populationStatus) {
             if (populationStatus == Status.IDLE
-                    || populationStatus == Status.SUCCEEDED) {
+                    || populationStatus == Status.SUCCEEDED
+                    || populationStatus == Status.ABORTED) {
                 populationStatus = Status.STARTED;
                 populateAllRoutingRules();
+            } else {
+                log.warn("Not initiating startPopulationProcess as populationStatus is {}",
+                         populationStatus);
             }
         }
     }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
index d0721e9..ad8c0a3 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
@@ -99,6 +99,9 @@
                     deviceConfigMap.get(deviceId).nodeSid);
             return deviceConfigMap.get(deviceId).nodeSid;
         } else {
+            log.warn("getSegmentId for device {} "
+                    + "throwing IllegalStateException "
+                    + "because device does not exist in config", deviceId);
             throw new IllegalStateException();
         }
     }
@@ -151,6 +154,9 @@
                     deviceConfigMap.get(deviceId).mac);
             return deviceConfigMap.get(deviceId).mac;
         } else {
+            log.warn("getDeviceMac for device {} "
+                    + "throwing IllegalStateException "
+                    + "because device does not exist in config", deviceId);
             throw new IllegalStateException();
         }
     }
@@ -168,6 +174,9 @@
                     deviceConfigMap.get(deviceId).ip);
             return deviceConfigMap.get(deviceId).ip;
         } else {
+            log.warn("getRouterIp for device {} "
+                    + "throwing IllegalStateException "
+                    + "because device does not exist in config", deviceId);
             throw new IllegalStateException();
         }
     }
@@ -187,6 +196,9 @@
                     deviceConfigMap.get(deviceId).isEdge);
             return deviceConfigMap.get(deviceId).isEdge;
         } else {
+            log.warn("isEdgeDevice for device {} "
+                    + "throwing IllegalStateException "
+                    + "because device does not exist in config", deviceId);
             throw new IllegalStateException();
         }
     }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index f3ccaa0..7092093 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -217,6 +217,11 @@
 
         // If the next hop is the destination router, do PHP
         if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
+            log.debug("populateMplsRule: Installing MPLS forwarding objective for "
+                    + "label {} in switch {} with PHP",
+                    config.getSegmentId(destSwId),
+                    deviceId);
+
             ForwardingObjective.Builder fwdObjBosBuilder =
                     getMplsForwardingObjective(deviceId,
                                                destSwId,
@@ -237,6 +242,11 @@
                 return false;
             }
         } else {
+            log.debug("Installing MPLS forwarding objective for "
+                    + "label {} in switch {} without PHP",
+                    config.getSegmentId(destSwId),
+                    deviceId);
+
             ForwardingObjective.Builder fwdObjBosBuilder =
                     getMplsForwardingObjective(deviceId,
                                                destSwId,
@@ -264,8 +274,6 @@
                     .makePermanent()).withSelector(selector)
                     .withPriority(100))
                     .withFlag(ForwardingObjective.Flag.SPECIFIC);
-            log.debug("Installing MPLS forwarding objective in switch {}",
-                    deviceId);
             srManager.flowObjectiveService.forward(deviceId,
                                                    fwdObjBuilder.add());
             rulePopulationCounter.incrementAndGet();
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 9ace6b8..87282b4 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -22,23 +22,22 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
+import org.onlab.util.KryoNamespace;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.event.Event;
 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
+import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
-import org.onosproject.net.MastershipRole;
 import org.onosproject.net.Port;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupEvent;
 import org.onosproject.net.group.GroupKey;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.intent.IntentService;
@@ -51,9 +50,16 @@
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.topology.TopologyService;
 import org.onosproject.segmentrouting.config.NetworkConfigManager;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.EventuallyConsistentMapBuilder;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
+import org.onosproject.store.service.WallclockClockManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.net.URI;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -112,6 +118,11 @@
     private static ScheduledFuture<?> eventHandlerFuture = null;
     private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
     private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
+    // Per device next objective ID store with (device id + neighbor set) as key
+    private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
+        Integer> nsNextObjStore = null;
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
 
     private NetworkConfigManager networkConfigService = new NetworkConfigManager();;
 
@@ -119,10 +130,34 @@
     private static int numOfHandlerExecution = 0;
     private static int numOfHandlerScheduled = 0;
 
+    private KryoNamespace.Builder kryoBuilder = null;
+
     @Activate
     protected void activate() {
         appId = coreService
                 .registerApplication("org.onosproject.segmentrouting");
+
+        kryoBuilder = new KryoNamespace.Builder()
+            .register(NeighborSetNextObjectiveStoreKey.class,
+                  NeighborSet.class,
+                  DeviceId.class,
+                  URI.class,
+                  WallClockTimestamp.class,
+                  org.onosproject.cluster.NodeId.class,
+                  HashSet.class
+                );
+
+        log.debug("Creating EC map nsnextobjectivestore");
+        EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
+                nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
+
+        nsNextObjStore = nsNextObjMapBuilder
+                .withName("nsnextobjectivestore")
+                .withSerializer(kryoBuilder)
+                .withClockService(new WallclockClockManager<>())
+                .build();
+        log.trace("Current size {}", nsNextObjStore.size());
+
         networkConfigService.init();
         deviceConfiguration = new DeviceConfiguration(networkConfigService);
         arpHandler = new ArpHandler(this);
@@ -136,20 +171,18 @@
         deviceService.addListener(new InternalDeviceListener());
 
         for (Device device : deviceService.getDevices()) {
-            if (mastershipService.getLocalRole(device.id()) == MastershipRole.MASTER) {
-                DefaultGroupHandler groupHandler = DefaultGroupHandler
-                        .createGroupHandler(device.id(), appId,
-                                            deviceConfiguration, linkService,
-                                            flowObjectiveService);
-                groupHandlerMap.put(device.id(), groupHandler);
-                defaultRoutingHandler.populateTtpRules(device.id());
-                log.debug("Initiating default group handling for {}", device.id());
-            } else {
-                log.debug("Activate: Local role {} "
-                                  + "is not MASTER for device {}",
-                          mastershipService.getLocalRole(device.id()),
-                          device.id());
-            }
+            //Irrespective whether the local is a MASTER or not for this device,
+            //create group handler instance and push default TTP flow rules.
+            //Because in a multi-instance setup, instances can initiate
+            //groups for any devices. Also the default TTP rules are needed
+            //to be pushed before inserting any IP table entries for any device
+            DefaultGroupHandler groupHandler = DefaultGroupHandler
+                    .createGroupHandler(device.id(), appId,
+                                        deviceConfiguration, linkService,
+                                        flowObjectiveService,
+                                        nsNextObjStore);
+            groupHandlerMap.put(device.id(), groupHandler);
+            defaultRoutingHandler.populateTtpRules(device.id());
         }
 
         defaultRoutingHandler.startPopulationProcess();
@@ -180,8 +213,14 @@
 
     public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
 
-        return (groupHandlerMap.get(deviceId) != null) ? groupHandlerMap
-                .get(deviceId).getNextObjectiveId(ns) : -1;
+        if (groupHandlerMap.get(deviceId) != null) {
+            log.trace("getNextObjectiveId query in device {}", deviceId);
+            return groupHandlerMap
+                    .get(deviceId).getNextObjectiveId(ns);
+        } else {
+            log.warn("getNextObjectiveId query in device {} not found", deviceId);
+            return -1;
+        }
     }
 
     private class InternalPacketProcessor implements PacketProcessor {
@@ -224,12 +263,12 @@
 
         @Override
         public void event(DeviceEvent event) {
-            if (mastershipService.getLocalRole(event.subject().id()) != MastershipRole.MASTER) {
+            /*if (mastershipService.getLocalRole(event.subject().id()) != MastershipRole.MASTER) {
                 log.debug("Local role {} is not MASTER for device {}",
                           mastershipService.getLocalRole(event.subject().id()),
                           event.subject().id());
                 return;
-            }
+            }*/
 
             switch (event.type()) {
             case DEVICE_ADDED:
@@ -245,12 +284,14 @@
 
     private void scheduleEventHandlerIfNotScheduled(Event event) {
 
-        eventQueue.add(event);
-        numOfEvents++;
-        if (eventHandlerFuture == null || eventHandlerFuture.isDone()) {
-            eventHandlerFuture = executorService
-                    .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
-            numOfHandlerScheduled++;
+        synchronized (eventQueue) {
+            eventQueue.add(event);
+            numOfEvents++;
+            if (eventHandlerFuture == null || eventHandlerFuture.isDone()) {
+                eventHandlerFuture = executorService
+                        .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
+                numOfHandlerScheduled++;
+            }
         }
 
         log.trace("numOfEvents {}, numOfEventHanlderScheduled {}", numOfEvents,
@@ -262,44 +303,68 @@
 
         @Override
         public void run() {
-            numOfHandlerExecution++;
-            while (!eventQueue.isEmpty()) {
-                Event event = eventQueue.poll();
-                if (event.type() == LinkEvent.Type.LINK_ADDED) {
-                    processLinkAdded((Link) event.subject());
-                } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
-                    processLinkRemoved((Link) event.subject());
-                } else if (event.type() == GroupEvent.Type.GROUP_ADDED) {
-                    processGroupAdded((Group) event.subject());
-                } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
-                        event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
-                        event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
-                    if (deviceService.isAvailable(((Device) event.subject()).id())) {
-                        processDeviceAdded((Device) event.subject());
+            try {
+                synchronized (eventQueue) {
+                    numOfHandlerExecution++;
+                    while (!eventQueue.isEmpty()) {
+                        Event event = eventQueue.poll();
+                        if (event.type() == LinkEvent.Type.LINK_ADDED) {
+                            processLinkAdded((Link) event.subject());
+                        } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
+                            processLinkRemoved((Link) event.subject());
+                        //} else if (event.type() == GroupEvent.Type.GROUP_ADDED) {
+                        //    processGroupAdded((Group) event.subject());
+                        } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
+                                event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
+                                event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
+                            if (deviceService.isAvailable(((Device) event.subject()).id())) {
+                                processDeviceAdded((Device) event.subject());
+                            }
+                        } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
+                            processPortRemoved((Device) event.subject(),
+                                               ((DeviceEvent) event).port());
+                        } else {
+                            log.warn("Unhandled event type: {}", event.type());
+                        }
                     }
-                } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
-                    processPortRemoved((Device) event.subject(),
-                                       ((DeviceEvent) event).port());
-                } else {
-                    log.warn("Unhandled event type: {}", event.type());
                 }
+                log.debug("numOfHandlerExecution {} numOfEventHanlderScheduled {} numOfEvents {}",
+                          numOfHandlerExecution, numOfHandlerScheduled, numOfEvents);
+            } catch (Exception e) {
+                log.error("SegmentRouting event handler "
+                        + "thread thrown an exception: {}", e);
             }
-            log.debug("numOfHandlerExecution {} numOfEventHanlderScheduled {} numOfEvents {}",
-                      numOfHandlerExecution, numOfHandlerScheduled, numOfEvents);
         }
     }
 
     private void processLinkAdded(Link link) {
         log.debug("A new link {} was added", link.toString());
 
-        if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
-            DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
-                    .deviceId());
-            if (groupHandler != null) {
+        //Irrespective whether the local is a MASTER or not for this device,
+        //create group handler instance and push default TTP flow rules.
+        //Because in a multi-instance setup, instances can initiate
+        //groups for any devices. Also the default TTP rules are needed
+        //to be pushed before inserting any IP table entries for any device
+        DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
+                .deviceId());
+        if (groupHandler != null) {
+            groupHandler.linkUp(link);
+        } else {
+            Device device = deviceService.getDevice(link.src().deviceId());
+            if (device != null) {
+                log.warn("processLinkAdded: Link Added "
+                        + "Notification without Device Added "
+                        + "event, still handling it");
+                processDeviceAdded(device);
+                groupHandler = groupHandlerMap.get(link.src()
+                                                   .deviceId());
                 groupHandler.linkUp(link);
             }
         }
-        defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
+
+        //defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
+        log.trace("processLinkAdded: re-starting route population process");
+        defaultRoutingHandler.startPopulationProcess();
     }
 
     private void processLinkRemoved(Link link) {
@@ -308,20 +373,27 @@
         if (groupHandler != null) {
             groupHandler.portDown(link.src().port());
         }
-        defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
-    }
-
-    private void processGroupAdded(Group group) {
-        log.debug("A new group with ID {} was added", group.id());
-        defaultRoutingHandler.resumePopulationProcess();
+        //defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
+        log.trace("processLinkRemoved: re-starting route population process");
+        defaultRoutingHandler.startPopulationProcess();
     }
 
     private void processDeviceAdded(Device device) {
         log.debug("A new device with ID {} was added", device.id());
-        defaultRoutingHandler.populateTtpRules(device.id());
-        DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(device
-                .id(), appId, deviceConfiguration, linkService, flowObjectiveService);
+        //Irrespective whether the local is a MASTER or not for this device,
+        //create group handler instance and push default TTP flow rules.
+        //Because in a multi-instance setup, instances can initiate
+        //groups for any devices. Also the default TTP rules are needed
+        //to be pushed before inserting any IP table entries for any device
+        DefaultGroupHandler dgh = DefaultGroupHandler.
+                createGroupHandler(device.id(),
+                                   appId,
+                                   deviceConfiguration,
+                                   linkService,
+                                   flowObjectiveService,
+                                   nsNextObjStore);
         groupHandlerMap.put(device.id(), dgh);
+        defaultRoutingHandler.populateTtpRules(device.id());
     }
 
     private void processPortRemoved(Device device, Port port) {
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
index 4159d3c..41cf8ac 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
@@ -19,16 +19,12 @@
 import java.util.List;
 import java.util.Set;
 
-import org.onlab.packet.MplsLabel;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flowobjective.DefaultNextObjective;
 import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.net.link.LinkService;
+import org.onosproject.store.service.EventuallyConsistentMap;
 
 /**
  * Default ECMP group handler creation module for an edge device.
@@ -53,8 +49,11 @@
                                   ApplicationId appId,
                                   DeviceProperties config,
                                   LinkService linkService,
-                                  FlowObjectiveService flowObjService) {
-        super(deviceId, appId, config, linkService, flowObjService);
+                                  FlowObjectiveService flowObjService,
+                                  EventuallyConsistentMap<
+                                  NeighborSetNextObjectiveStoreKey,
+                                  Integer> nsNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
     }
 
     @Override
@@ -108,7 +107,7 @@
 
     @Override
     protected void newPortToExistingNeighbor(Link newNeighborLink) {
-        log.debug("New port to existing neighbor: Updating "
+        /*log.debug("New port to existing neighbor: Updating "
                 + "groups for edge device {}", deviceId);
         addNeighborAtPort(newNeighborLink.dst().deviceId(),
                           newNeighborLink.src().port());
@@ -129,7 +128,7 @@
                                  mplsLabel(ns.getEdgeLabel()));
             }
 
-            Integer nextId = deviceNextObjectiveIds.get(getGroupKey(ns));
+            Integer nextId = deviceNextObjectiveIds.get(ns);
             if (nextId != null) {
                 NextObjective.Builder nextObjBuilder = DefaultNextObjective
                         .builder().withId(nextId)
@@ -140,7 +139,7 @@
                 NextObjective nextObjective = nextObjBuilder.add();
                 flowObjectiveService.next(deviceId, nextObjective);
             }
-        }
+        }*/
     }
 
     @Override
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);
         }
     }
 
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
index 752ee2d..e12426c 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
@@ -18,16 +18,12 @@
 import java.util.HashSet;
 import java.util.Set;
 
-import org.onlab.packet.MplsLabel;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flowobjective.DefaultNextObjective;
 import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.net.link.LinkService;
+import org.onosproject.store.service.EventuallyConsistentMap;
 
 /**
  * Default ECMP group handler creation module for a transit device.
@@ -47,8 +43,11 @@
                                   ApplicationId appId,
                                   DeviceProperties config,
                                   LinkService linkService,
-                                  FlowObjectiveService flowObjService) {
-        super(deviceId, appId, config, linkService, flowObjService);
+                                  FlowObjectiveService flowObjService,
+                                  EventuallyConsistentMap<
+                                  NeighborSetNextObjectiveStoreKey,
+                                  Integer> nsNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
     }
 
     @Override
@@ -96,7 +95,7 @@
 
     @Override
     protected void newPortToExistingNeighbor(Link newNeighborLink) {
-        log.debug("New port to existing neighbor: Updating "
+        /*log.debug("New port to existing neighbor: Updating "
                 + "groups for transit device {}", deviceId);
         addNeighborAtPort(newNeighborLink.dst().deviceId(),
                           newNeighborLink.src().port());
@@ -118,7 +117,7 @@
             }
 
 
-            Integer nextId = deviceNextObjectiveIds.get(getGroupKey(ns));
+            Integer nextId = deviceNextObjectiveIds.get(ns);
             if (nextId != null) {
                 NextObjective.Builder nextObjBuilder = DefaultNextObjective
                         .builder().withId(nextId)
@@ -129,7 +128,7 @@
                 NextObjective nextObjective = nextObjBuilder.add();
                 flowObjectiveService.next(deviceId, nextObjective);
             }
-        }
+        }*/
     }
 
     @Override
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSetNextObjectiveStoreKey.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSetNextObjectiveStoreKey.java
new file mode 100644
index 0000000..9ace531
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSetNextObjectiveStoreKey.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting.grouphandler;
+
+import java.util.Objects;
+
+import org.onosproject.net.DeviceId;
+
+/**
+ * Class definition of Key for Neighborset to NextObjective store.
+ */
+public class NeighborSetNextObjectiveStoreKey {
+    private final DeviceId deviceId;
+    private final NeighborSet ns;
+
+    public NeighborSetNextObjectiveStoreKey(DeviceId deviceId,
+                                            NeighborSet ns) {
+        this.deviceId = deviceId;
+        this.ns = ns;
+    }
+
+    public DeviceId deviceId() {
+        return this.deviceId;
+    }
+
+    public NeighborSet neighborSet() {
+        return this.ns;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof NeighborSetNextObjectiveStoreKey)) {
+            return false;
+        }
+        NeighborSetNextObjectiveStoreKey that =
+                (NeighborSetNextObjectiveStoreKey) o;
+        return (Objects.equals(this.deviceId, that.deviceId) &&
+                Objects.equals(this.ns, that.ns));
+    }
+
+    // The list of neighbor ids and label are used for comparison.
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + Objects.hashCode(this.deviceId)
+                + Objects.hashCode(this.ns);
+
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Device: " + deviceId + " Neighborset: " + ns;
+    }
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
index a2a1b09..6623696 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
@@ -27,6 +27,7 @@
 import org.onlab.packet.MplsLabel;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.segmentrouting.grouphandler.GroupBucketIdentifier.BucketOutputType;
+import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -58,8 +59,11 @@
                               ApplicationId appId,
                               DeviceProperties config,
                               LinkService linkService,
-                              FlowObjectiveService flowObjService) {
-        super(deviceId, appId, config, linkService, flowObjService);
+                              FlowObjectiveService flowObjService,
+                              EventuallyConsistentMap<
+                              NeighborSetNextObjectiveStoreKey,
+                              Integer> nsNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
     }
 
     public PolicyGroupIdentifier createPolicyGroupChain(String id,
diff --git a/core/api/src/main/java/org/onosproject/net/group/GroupStore.java b/core/api/src/main/java/org/onosproject/net/group/GroupStore.java
index 0821604..8b6df5d 100644
--- a/core/api/src/main/java/org/onosproject/net/group/GroupStore.java
+++ b/core/api/src/main/java/org/onosproject/net/group/GroupStore.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.net.group;
 
+import java.util.Collection;
+
 import org.onosproject.core.GroupId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.store.Store;
@@ -162,4 +164,12 @@
      * @param operation the group operation failed
      */
     void groupOperationFailed(DeviceId deviceId, GroupOperation operation);
+
+    /**
+     * Submits the group metrics to store for a given device ID.
+     *
+     * @param deviceId the device ID
+     * @param groupEntries the group entries as received from southbound
+     */
+    void pushGroupMetrics(DeviceId deviceId, Collection<Group> groupEntries);
 }
diff --git a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
index 0fcb1fc..b54e468 100644
--- a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
+++ b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
@@ -15,7 +15,11 @@
  */
 package org.onosproject.net.group.impl;
 
-import com.google.common.collect.Sets;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collection;
+import java.util.Collections;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -48,13 +52,6 @@
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Set;
-
-import static org.slf4j.LoggerFactory.getLogger;
-
 /**
  * Provides implementation of the group service APIs.
  */
@@ -316,131 +313,13 @@
             store.groupOperationFailed(deviceId, operation);
         }
 
-        private void groupMissing(Group group) {
-            checkValidity();
-            GroupProvider gp = getProvider(group.deviceId());
-            switch (group.state()) {
-                case PENDING_DELETE:
-                    log.debug("Group {} delete confirmation from device {}",
-                              group, group.deviceId());
-                    store.removeGroupEntry(group);
-                    break;
-                case ADDED:
-                case PENDING_ADD:
-                    log.debug("Group {} is in store but not on device {}",
-                              group, group.deviceId());
-                    GroupOperation groupAddOp = GroupOperation.
-                                    createAddGroupOperation(group.id(),
-                                                            group.type(),
-                                                            group.buckets());
-                    GroupOperations groupOps = new GroupOperations(
-                            Collections.singletonList(groupAddOp));
-                    gp.performGroupOperation(group.deviceId(), groupOps);
-                    break;
-                default:
-                    log.debug("Group {} has not been installed.", group);
-                    break;
-            }
-        }
-
-
-        private void extraneousGroup(Group group) {
-            log.debug("Group {} is on device {} but not in store.",
-                      group, group.deviceId());
-            checkValidity();
-            store.addOrUpdateExtraneousGroupEntry(group);
-        }
-
-        private void groupAdded(Group group) {
-            checkValidity();
-
-            log.trace("Group {} Added or Updated in device {}",
-                      group, group.deviceId());
-            store.addOrUpdateGroupEntry(group);
-        }
-
         @Override
         public void pushGroupMetrics(DeviceId deviceId,
                                      Collection<Group> groupEntries) {
             log.trace("Received group metrics from device {}",
                     deviceId);
-            boolean deviceInitialAuditStatus =
-                    store.deviceInitialAuditStatus(deviceId);
-            Set<Group> southboundGroupEntries =
-                    Sets.newHashSet(groupEntries);
-            Set<Group> storedGroupEntries =
-                    Sets.newHashSet(store.getGroups(deviceId));
-            Set<Group> extraneousStoredEntries =
-                    Sets.newHashSet(store.getExtraneousGroups(deviceId));
-
-            log.trace("Displaying all ({}) southboundGroupEntries for device {}",
-                      southboundGroupEntries.size(),
-                      deviceId);
-            for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
-                Group group = it.next();
-                log.trace("Group {} in device {}", group, deviceId);
-            }
-
-            log.trace("Displaying all ({}) stored group entries for device {}",
-                      storedGroupEntries.size(),
-                      deviceId);
-            for (Iterator<Group> it1 = storedGroupEntries.iterator(); it1.hasNext();) {
-                Group group = it1.next();
-                log.trace("Stored Group {} for device {}", group, deviceId);
-            }
-
-            for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
-                Group group = it2.next();
-                if (storedGroupEntries.remove(group)) {
-                    // we both have the group, let's update some info then.
-                    log.trace("Group AUDIT: group {} exists "
-                            + "in both planes for device {}",
-                            group.id(), deviceId);
-                    groupAdded(group);
-                    it2.remove();
-                }
-            }
-            for (Group group : southboundGroupEntries) {
-                if (store.getGroup(group.deviceId(), group.id()) != null) {
-                    // There is a group existing with the same id
-                    // It is possible that group update is
-                    // in progress while we got a stale info from switch
-                    if (!storedGroupEntries.remove(store.getGroup(
-                                 group.deviceId(), group.id()))) {
-                        log.warn("Group AUDIT: Inconsistent state:"
-                                + "Group exists in ID based table while "
-                                + "not present in key based table");
-                    }
-                } else {
-                    // there are groups in the switch that aren't in the store
-                    log.trace("Group AUDIT: extraneous group {} exists "
-                            + "in data plane for device {}",
-                            group.id(), deviceId);
-                    extraneousStoredEntries.remove(group);
-                    extraneousGroup(group);
-                }
-            }
-            for (Group group : storedGroupEntries) {
-                // there are groups in the store that aren't in the switch
-                log.trace("Group AUDIT: group {} missing "
-                        + "in data plane for device {}",
-                        group.id(), deviceId);
-                groupMissing(group);
-            }
-            for (Group group : extraneousStoredEntries) {
-                // there are groups in the extraneous store that
-                // aren't in the switch
-                log.trace("Group AUDIT: clearing extransoeus group {} "
-                        + "from store for device {}",
-                        group.id(), deviceId);
-                store.removeExtraneousGroupEntry(group);
-            }
-
-            if (!deviceInitialAuditStatus) {
-                log.debug("Group AUDIT: Setting device {} initial "
-                        + "AUDIT completed", deviceId);
-                store.deviceInitialAuditCompleted(deviceId, true);
-            }
+            checkValidity();
+            store.pushGroupMetrics(deviceId, groupEntries);
         }
     }
 
@@ -450,10 +329,16 @@
         public void event(DeviceEvent event) {
             switch (event.type()) {
             case DEVICE_REMOVED:
-                log.debug("Clearing device {} initial "
-                        + "AUDIT completed status as device is going down",
-                        event.subject().id());
-                store.deviceInitialAuditCompleted(event.subject().id(), false);
+            case DEVICE_AVAILABILITY_CHANGED:
+                if (!deviceService.isAvailable(event.subject().id())) {
+                    log.debug("GroupService DeviceListener: Received event {}."
+                            + "Device is no more available."
+                            + "Clearing device {} initial "
+                            + "AUDIT completed status",
+                            event.type(),
+                            event.subject().id());
+                    store.deviceInitialAuditCompleted(event.subject().id(), false);
+                }
                 break;
 
             default:
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 60b72d7..8a732c8 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
@@ -17,6 +17,7 @@
 
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -63,7 +64,9 @@
 import org.onosproject.store.cluster.messaging.ClusterMessage;
 import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
 import org.onosproject.store.service.MultiValuedTimestamp;
+import org.onosproject.store.serializers.DeviceIdSerializer;
 import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.serializers.URISerializer;
 import org.onosproject.store.service.ClockService;
 import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
@@ -74,10 +77,13 @@
 
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutorService;
@@ -156,8 +162,8 @@
                       GroupStoreIdMapKey.class,
                       GroupStoreMapKey.class
                     )
-            .register(URI.class)
-            .register(DeviceId.class)
+            .register(new URISerializer(), URI.class)
+            .register(new DeviceIdSerializer(), DeviceId.class)
             .register(PortNumber.class)
             .register(DefaultApplicationId.class)
             .register(DefaultTrafficTreatment.class,
@@ -207,7 +213,8 @@
                 .withClockService(new GroupStoreLogicalClockManager<>())
                 .build();
         groupStoreEntriesByKey.addListener(new GroupStoreKeyMapListener());
-        log.trace("Current size {}", groupStoreEntriesByKey.size());
+        log.debug("Current size of groupstorekeymap:{}",
+                  groupStoreEntriesByKey.size());
 
         log.debug("Creating EC map pendinggroupkeymap");
         EventuallyConsistentMapBuilder<GroupStoreKeyMapKey, StoredGroupEntry>
@@ -218,7 +225,8 @@
                 .withSerializer(kryoBuilder)
                 .withClockService(new GroupStoreLogicalClockManager<>())
                 .build();
-        log.trace("Current size {}", auditPendingReqQueue.size());
+        log.debug("Current size of pendinggroupkeymap:{}",
+                  auditPendingReqQueue.size());
 
         log.info("Started");
     }
@@ -305,13 +313,21 @@
     @Override
     public Iterable<Group> getGroups(DeviceId deviceId) {
         // flatten and make iterator unmodifiable
-        log.trace("getGroups: for device {} total number of groups {}",
+        log.debug("getGroups: for device {} total number of groups {}",
                   deviceId, getGroupStoreKeyMap().values().size());
         return FluentIterable.from(getGroupStoreKeyMap().values())
                 .filter(input -> input.deviceId().equals(deviceId))
                 .transform(input -> input);
     }
 
+    private Iterable<StoredGroupEntry> getStoredGroups(DeviceId deviceId) {
+        // flatten and make iterator unmodifiable
+        log.debug("getGroups: for device {} total number of groups {}",
+                  deviceId, getGroupStoreKeyMap().values().size());
+        return FluentIterable.from(getGroupStoreKeyMap().values())
+                .filter(input -> input.deviceId().equals(deviceId));
+    }
+
     /**
      * Returns the stored group entry.
      *
@@ -359,6 +375,7 @@
                 break;
             }
         }
+        log.debug("getFreeGroupIdValue: Next Free ID is {}", freeId);
         return freeId;
     }
 
@@ -369,7 +386,7 @@
      */
     @Override
     public void storeGroupDescription(GroupDescription groupDesc) {
-        log.trace("In storeGroupDescription");
+        log.debug("In storeGroupDescription");
         // Check if a group is existing with the same key
         if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) {
             log.warn("Group already exists with the same key {}",
@@ -380,8 +397,15 @@
         // Check if group to be created by a remote instance
         if (mastershipService.getLocalRole(
                      groupDesc.deviceId()) != MastershipRole.MASTER) {
-            log.debug("Device {} local role is not MASTER",
+            log.debug("storeGroupDescription: Device {} local role is not MASTER",
                       groupDesc.deviceId());
+            if (mastershipService.getMasterFor(groupDesc.deviceId()) == null) {
+                log.error("No Master for device {}..."
+                        + "Can not perform add group operation",
+                        groupDesc.deviceId());
+                //TODO: Send Group operation failure event
+                return;
+            }
             GroupStoreMessage groupOp = GroupStoreMessage.
                     createGroupAddRequestMsg(groupDesc.deviceId(),
                                              groupDesc);
@@ -394,9 +418,9 @@
                          groupOp,
                          mastershipService.getMasterFor(groupDesc.deviceId()));
                 //TODO: Send Group operation failure event
+                return;
             }
-            log.debug("Sent Group operation request for device {} "
-                    + "to remote MASTER {}",
+            log.debug("Sent Group operation request for device {} to remote MASTER {}",
                       groupDesc.deviceId(),
                       mastershipService.getMasterFor(groupDesc.deviceId()));
             return;
@@ -417,8 +441,7 @@
             // Device group audit has not completed yet
             // Add this group description to pending group key table
             // Create a group entry object with Dummy Group ID
-            log.debug("storeGroupDescriptionInternal: Device {} AUDIT "
-                    + "pending...Queuing Group ADD request",
+            log.debug("storeGroupDescriptionInternal: Device {} AUDIT pending...Queuing Group ADD request",
                     groupDesc.deviceId());
             StoredGroupEntry group = new DefaultGroup(dummyGroupId, groupDesc);
             group.setState(GroupState.WAITING_AUDIT_COMPLETE);
@@ -447,6 +470,9 @@
         // avoid any chances of duplication in group id generation
         getGroupIdTable(groupDesc.deviceId()).
             put(id, group);
+        log.debug("storeGroupDescriptionInternal: Processing Group ADD request for Id {} in device {}",
+                id,
+                groupDesc.deviceId());
         notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
                                       group));
     }
@@ -470,6 +496,15 @@
         // Check if group update to be done by a remote instance
         if (mastershipService.getMasterFor(deviceId) != null &&
                 mastershipService.getLocalRole(deviceId) != MastershipRole.MASTER) {
+            log.debug("updateGroupDescription: Device {} local role is not MASTER",
+                      deviceId);
+            if (mastershipService.getMasterFor(deviceId) == null) {
+                log.error("No Master for device {}..."
+                        + "Can not perform update group operation",
+                        deviceId);
+                //TODO: Send Group operation failure event
+                return;
+            }
             GroupStoreMessage groupOp = GroupStoreMessage.
                     createGroupUpdateRequestMsg(deviceId,
                                                 oldAppCookie,
@@ -488,6 +523,8 @@
             }
             return;
         }
+        log.debug("updateGroupDescription for device {} is getting handled locally",
+                  deviceId);
         updateGroupDescriptionInternal(deviceId,
                                        oldAppCookie,
                                        type,
@@ -503,6 +540,7 @@
         // Check if a group is existing with the provided key
         Group oldGroup = getGroup(deviceId, oldAppCookie);
         if (oldGroup == null) {
+            log.warn("updateGroupDescriptionInternal: Group not found...strange");
             return;
         }
 
@@ -522,6 +560,10 @@
                     oldGroup.appId());
             StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(),
                                                          updatedGroupDesc);
+            log.debug("updateGroupDescriptionInternal: group entry {} in device {} moving from {} to PENDING_UPDATE",
+                    oldGroup.id(),
+                    oldGroup.deviceId(),
+                    oldGroup.state());
             newGroup.setState(GroupState.PENDING_UPDATE);
             newGroup.setLife(oldGroup.life());
             newGroup.setPackets(oldGroup.packets());
@@ -529,10 +571,15 @@
             //Update the group entry in groupkey based map.
             //Update to groupid based map will happen in the
             //groupkey based map update listener
+            log.debug("updateGroupDescriptionInternal with type {}: Group updated with buckets",
+                      type);
             getGroupStoreKeyMap().
                 put(new GroupStoreKeyMapKey(newGroup.deviceId(),
                                             newGroup.appCookie()), newGroup);
             notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_REQUESTED, newGroup));
+        } else {
+            log.warn("updateGroupDescriptionInternal with type {}: No "
+                    + "change in the buckets in update", type);
         }
     }
 
@@ -583,6 +630,15 @@
         // Check if group to be deleted by a remote instance
         if (mastershipService.
                 getLocalRole(deviceId) != MastershipRole.MASTER) {
+            log.debug("deleteGroupDescription: Device {} local role is not MASTER",
+                      deviceId);
+            if (mastershipService.getMasterFor(deviceId) == null) {
+                log.error("No Master for device {}..."
+                        + "Can not perform delete group operation",
+                        deviceId);
+                //TODO: Send Group operation failure event
+                return;
+            }
             GroupStoreMessage groupOp = GroupStoreMessage.
                     createGroupDeleteRequestMsg(deviceId,
                                                 appCookie);
@@ -598,6 +654,8 @@
             }
             return;
         }
+        log.debug("deleteGroupDescription in device {} is getting handled locally",
+                  deviceId);
         deleteGroupDescriptionInternal(deviceId, appCookie);
     }
 
@@ -609,9 +667,15 @@
             return;
         }
 
+        log.debug("deleteGroupDescriptionInternal: group entry {} in device {} moving from {} to PENDING_DELETE",
+                existing.id(),
+                existing.deviceId(),
+                existing.state());
         synchronized (existing) {
             existing.setState(GroupState.PENDING_DELETE);
         }
+        log.debug("deleteGroupDescriptionInternal: in device {} issuing GROUP_REMOVE_REQUESTED",
+                  deviceId);
         notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, existing));
     }
 
@@ -628,8 +692,7 @@
         GroupEvent event = null;
 
         if (existing != null) {
-            log.trace("addOrUpdateGroupEntry: updating group "
-                    + "entry {} in device {}",
+            log.debug("addOrUpdateGroupEntry: updating group entry {} in device {}",
                     group.id(),
                     group.deviceId());
             synchronized (existing) {
@@ -653,10 +716,18 @@
                 existing.setPackets(group.packets());
                 existing.setBytes(group.bytes());
                 if (existing.state() == GroupState.PENDING_ADD) {
+                    log.debug("addOrUpdateGroupEntry: group entry {} in device {} moving from {} to ADDED",
+                            existing.id(),
+                            existing.deviceId(),
+                            GroupState.PENDING_ADD);
                     existing.setState(GroupState.ADDED);
                     existing.setIsGroupStateAddedFirstTime(true);
                     event = new GroupEvent(Type.GROUP_ADDED, existing);
                 } else {
+                    log.debug("addOrUpdateGroupEntry: group entry {} in device {} moving from {} to ADDED",
+                            existing.id(),
+                            existing.deviceId(),
+                            GroupState.PENDING_UPDATE);
                     existing.setState(GroupState.ADDED);
                     existing.setIsGroupStateAddedFirstTime(false);
                     event = new GroupEvent(Type.GROUP_UPDATED, existing);
@@ -687,8 +758,7 @@
                                                         group.id());
 
         if (existing != null) {
-            log.trace("removeGroupEntry: removing group "
-                    + "entry {} in device {}",
+            log.debug("removeGroupEntry: removing group entry {} in device {}",
                     group.id(),
                     group.deviceId());
             //Removal from groupid based map will happen in the
@@ -696,6 +766,11 @@
             getGroupStoreKeyMap().remove(new GroupStoreKeyMapKey(existing.deviceId(),
                                                                  existing.appCookie()));
             notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing));
+        } else {
+            log.warn("removeGroupEntry for {} in device{} is "
+                    + "not existing in our maps",
+                    group.id(),
+                    group.deviceId());
         }
     }
 
@@ -704,8 +779,8 @@
                                             boolean completed) {
         synchronized (deviceAuditStatus) {
             if (completed) {
-                log.debug("deviceInitialAuditCompleted: AUDIT "
-                                  + "completed for device {}", deviceId);
+                log.debug("AUDIT completed for device {}",
+                          deviceId);
                 deviceAuditStatus.put(deviceId, true);
                 // Execute all pending group requests
                 List<StoredGroupEntry> pendingGroupRequests =
@@ -713,9 +788,7 @@
                         .stream()
                         .filter(g-> g.deviceId().equals(deviceId))
                         .collect(Collectors.toList());
-                log.trace("deviceInitialAuditCompleted: processing "
-                        + "pending group add requests for device {} and "
-                        + "number of pending requests {}",
+                log.debug("processing pending group add requests for device {} and number of pending requests {}",
                         deviceId,
                         pendingGroupRequests.size());
                 for (Group group:pendingGroupRequests) {
@@ -733,8 +806,7 @@
             } else {
                 Boolean audited = deviceAuditStatus.get(deviceId);
                 if (audited != null && audited) {
-                    log.debug("deviceInitialAuditCompleted: Clearing AUDIT "
-                                      + "status for device {}", deviceId);
+                    log.debug("Clearing AUDIT status for device {}", deviceId);
                     deviceAuditStatus.put(deviceId, false);
                 }
             }
@@ -760,9 +832,22 @@
             return;
         }
 
+        log.warn("groupOperationFailed: group operation {} failed"
+                + "for group {} in device {}",
+                operation.opType(),
+                existing.id(),
+                existing.deviceId());
         switch (operation.opType()) {
             case ADD:
                 notifyDelegate(new GroupEvent(Type.GROUP_ADD_FAILED, existing));
+                log.warn("groupOperationFailed: cleaningup "
+                        + "group {} from store in device {}....",
+                        existing.id(),
+                        existing.deviceId());
+                //Removal from groupid based map will happen in the
+                //map update listener
+                getGroupStoreKeyMap().remove(new GroupStoreKeyMapKey(existing.deviceId(),
+                                                                     existing.appCookie()));
                 break;
             case MODIFY:
                 notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_FAILED, existing));
@@ -773,17 +858,11 @@
             default:
                 log.warn("Unknown group operation type {}", operation.opType());
         }
-
-        //Removal from groupid based map will happen in the
-        //map update listener
-        getGroupStoreKeyMap().remove(new GroupStoreKeyMapKey(existing.deviceId(),
-                                                             existing.appCookie()));
     }
 
     @Override
     public void addOrUpdateExtraneousGroupEntry(Group group) {
-        log.trace("addOrUpdateExtraneousGroupEntry: add/update extraneous "
-                + "group entry {} in device {}",
+        log.debug("add/update extraneous group entry {} in device {}",
                 group.id(),
                 group.deviceId());
         ConcurrentMap<GroupId, Group> extraneousIdTable =
@@ -791,8 +870,7 @@
         extraneousIdTable.put(group.id(), group);
         // Check the reference counter
         if (group.referenceCount() == 0) {
-            log.trace("addOrUpdateExtraneousGroupEntry: Flow reference "
-                    + "counter is zero and triggering remove",
+            log.debug("Flow reference counter is zero and triggering remove",
                     group.id(),
                     group.deviceId());
             notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group));
@@ -801,8 +879,7 @@
 
     @Override
     public void removeExtraneousGroupEntry(Group group) {
-        log.trace("removeExtraneousGroupEntry: remove extraneous "
-                + "group entry {} of device {} from store",
+        log.debug("remove extraneous group entry {} of device {} from store",
                 group.id(),
                 group.deviceId());
         ConcurrentMap<GroupId, Group> extraneousIdTable =
@@ -842,29 +919,47 @@
         public void event(EventuallyConsistentMapEvent<GroupStoreKeyMapKey,
                                   StoredGroupEntry> mapEvent) {
             GroupEvent groupEvent = null;
+            GroupStoreKeyMapKey key = mapEvent.key();
             StoredGroupEntry group = mapEvent.value();
-            log.trace("GroupStoreKeyMapListener: received groupid map event {}",
-                      mapEvent.type());
+            if ((key == null) && (group == null)) {
+                log.error("GroupStoreKeyMapListener: Received "
+                        + "event {} with null entry", mapEvent.type());
+                return;
+            } else if (group == null) {
+                group = getGroupIdTable(key.deviceId()).values()
+                        .stream()
+                        .filter((storedGroup) -> (storedGroup.appCookie().equals(key.appCookie)))
+                        .findFirst().get();
+                if (group == null) {
+                    log.error("GroupStoreKeyMapListener: Received "
+                            + "event {} with null entry... can not process", mapEvent.type());
+                    return;
+                }
+            }
+            log.trace("received groupid map event {} for id {} in device {}",
+                      mapEvent.type(),
+                      group.id(),
+                      key.deviceId());
             if (mapEvent.type() == EventuallyConsistentMapEvent.Type.PUT) {
-                log.trace("GroupStoreKeyMapListener: Received PUT event");
                 // Update the group ID table
                 getGroupIdTable(group.deviceId()).put(group.id(), group);
                 if (mapEvent.value().state() == Group.GroupState.ADDED) {
                     if (mapEvent.value().isGroupStateAddedFirstTime()) {
                         groupEvent = new GroupEvent(Type.GROUP_ADDED,
                                                     mapEvent.value());
-                        log.trace("GroupStoreKeyMapListener: Received first time "
-                                + "GROUP_ADDED state update");
+                        log.trace("Received first time GROUP_ADDED state update for id {} in device {}",
+                                group.id(),
+                                group.deviceId());
                     } else {
                         groupEvent = new GroupEvent(Type.GROUP_UPDATED,
                                                     mapEvent.value());
-                        log.trace("GroupStoreKeyMapListener: Received following "
-                                + "GROUP_ADDED state update");
+                        log.trace("Received following GROUP_ADDED state update for id {} in device {}",
+                                group.id(),
+                                group.deviceId());
                     }
                 }
             } else if (mapEvent.type() == EventuallyConsistentMapEvent.Type.REMOVE) {
-                log.trace("GroupStoreKeyMapListener: Received REMOVE event");
-                groupEvent = new GroupEvent(Type.GROUP_REMOVED, mapEvent.value());
+                groupEvent = new GroupEvent(Type.GROUP_REMOVED, group);
                 // Remove the entry from the group ID table
                 getGroupIdTable(group.deviceId()).remove(group.id(), group);
             }
@@ -882,37 +977,35 @@
                     implements ClusterMessageHandler {
         @Override
         public void handle(ClusterMessage message) {
-            log.trace("ClusterGroupMsgHandler: received remote group message");
-            if (message.subject() ==
-                    GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST) {
+            if (message.subject().equals(
+                    GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST)) {
                 GroupStoreMessage groupOp = kryoBuilder.
                         build().deserialize(message.payload());
-                log.trace("received remote group operation request");
-                if (!(mastershipService.
+                log.debug("received remote group operation {} request for device {}",
+                          groupOp.type(),
+                          groupOp.deviceId());
+                if (mastershipService.
                         getLocalRole(groupOp.deviceId()) !=
-                        MastershipRole.MASTER)) {
+                        MastershipRole.MASTER) {
                     log.warn("ClusterGroupMsgHandler: This node is not "
                             + "MASTER for device {}", groupOp.deviceId());
                     return;
                 }
                 if (groupOp.type() == GroupStoreMessage.Type.ADD) {
-                    log.trace("processing remote group "
-                            + "add operation request");
                     storeGroupDescriptionInternal(groupOp.groupDesc());
                 } else if (groupOp.type() == GroupStoreMessage.Type.UPDATE) {
-                    log.trace("processing remote group "
-                            + "update operation request");
                     updateGroupDescriptionInternal(groupOp.deviceId(),
                                                    groupOp.appCookie(),
                                                    groupOp.updateType(),
                                                    groupOp.updateBuckets(),
                                                    groupOp.newAppCookie());
                 } else if (groupOp.type() == GroupStoreMessage.Type.DELETE) {
-                    log.trace("processing remote group "
-                            + "delete operation request");
                     deleteGroupDescriptionInternal(groupOp.deviceId(),
                                                    groupOp.appCookie());
                 }
+            } else {
+                log.warn("ClusterGroupMsgHandler: Unknown remote message type {}",
+                         message.subject());
             }
         }
     }
@@ -927,6 +1020,10 @@
             this.deviceId = deviceId;
         }
 
+        public DeviceId deviceId() {
+            return deviceId;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (this == o) {
@@ -1010,4 +1107,127 @@
             return result;
         }
     }
+
+    @Override
+    public void pushGroupMetrics(DeviceId deviceId,
+                                 Collection<Group> groupEntries) {
+        boolean deviceInitialAuditStatus =
+                deviceInitialAuditStatus(deviceId);
+        Set<Group> southboundGroupEntries =
+                Sets.newHashSet(groupEntries);
+        Set<StoredGroupEntry> storedGroupEntries =
+                Sets.newHashSet(getStoredGroups(deviceId));
+        Set<Group> extraneousStoredEntries =
+                Sets.newHashSet(getExtraneousGroups(deviceId));
+
+        log.trace("pushGroupMetrics: Displaying all ({}) southboundGroupEntries for device {}",
+                  southboundGroupEntries.size(),
+                  deviceId);
+        for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
+            Group group = it.next();
+            log.trace("Group {} in device {}", group, deviceId);
+        }
+
+        log.trace("Displaying all ({}) stored group entries for device {}",
+                  storedGroupEntries.size(),
+                  deviceId);
+        for (Iterator<StoredGroupEntry> it1 = storedGroupEntries.iterator();
+                it1.hasNext();) {
+            Group group = it1.next();
+            log.trace("Stored Group {} for device {}", group, deviceId);
+        }
+
+        for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
+            Group group = it2.next();
+            if (storedGroupEntries.remove(group)) {
+                // we both have the group, let's update some info then.
+                log.trace("Group AUDIT: group {} exists in both planes for device {}",
+                        group.id(), deviceId);
+                groupAdded(group);
+                it2.remove();
+            }
+        }
+        for (Group group : southboundGroupEntries) {
+            if (getGroup(group.deviceId(), group.id()) != null) {
+                // There is a group existing with the same id
+                // It is possible that group update is
+                // in progress while we got a stale info from switch
+                if (!storedGroupEntries.remove(getGroup(
+                             group.deviceId(), group.id()))) {
+                    log.warn("Group AUDIT: Inconsistent state:"
+                            + "Group exists in ID based table while "
+                            + "not present in key based table");
+                }
+            } else {
+                // there are groups in the switch that aren't in the store
+                log.debug("Group AUDIT: extraneous group {} exists in data plane for device {}",
+                        group.id(), deviceId);
+                extraneousStoredEntries.remove(group);
+                extraneousGroup(group);
+            }
+        }
+        for (Group group : storedGroupEntries) {
+            // there are groups in the store that aren't in the switch
+            log.debug("Group AUDIT: group {} missing in data plane for device {}",
+                    group.id(), deviceId);
+            groupMissing(group);
+        }
+        for (Group group : extraneousStoredEntries) {
+            // there are groups in the extraneous store that
+            // aren't in the switch
+            log.debug("Group AUDIT: clearing extransoeus group {} from store for device {}",
+                    group.id(), deviceId);
+            removeExtraneousGroupEntry(group);
+        }
+
+        if (!deviceInitialAuditStatus) {
+            log.debug("Group AUDIT: Setting device {} initial AUDIT completed",
+                      deviceId);
+            deviceInitialAuditCompleted(deviceId, true);
+        }
+    }
+
+    private void groupMissing(Group group) {
+        switch (group.state()) {
+            case PENDING_DELETE:
+                log.debug("Group {} delete confirmation from device {}",
+                          group, group.deviceId());
+                removeGroupEntry(group);
+                break;
+            case ADDED:
+            case PENDING_ADD:
+            case PENDING_UPDATE:
+                log.debug("Group {} is in store but not on device {}",
+                          group, group.deviceId());
+                StoredGroupEntry existing =
+                        getStoredGroupEntry(group.deviceId(), group.id());
+                log.debug("groupMissing: group entry {} in device {} moving from {} to PENDING_ADD",
+                        existing.id(),
+                        existing.deviceId(),
+                        existing.state());
+                existing.setState(Group.GroupState.PENDING_ADD);
+                //Re-PUT map entries to trigger map update events
+                getGroupStoreKeyMap().
+                    put(new GroupStoreKeyMapKey(existing.deviceId(),
+                                                existing.appCookie()), existing);
+                notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
+                                              group));
+                break;
+            default:
+                log.debug("Group {} has not been installed.", group);
+                break;
+        }
+    }
+
+    private void extraneousGroup(Group group) {
+        log.debug("Group {} is on device {} but not in store.",
+                  group, group.deviceId());
+        addOrUpdateExtraneousGroupEntry(group);
+    }
+
+    private void groupAdded(Group group) {
+        log.trace("Group {} Added or Updated in device {}",
+                  group, group.deviceId());
+        addOrUpdateGroupEntry(group);
+    }
 }
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index fd2b4d6..7220fdb 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -315,6 +315,7 @@
                     Instructions.DropInstruction.class,
                     Instructions.OutputInstruction.class,
                     Instructions.GroupInstruction.class,
+                    Instructions.TableTypeTransition.class,
                     L0ModificationInstruction.class,
                     L0ModificationInstruction.L0SubType.class,
                     L0ModificationInstruction.ModLambdaInstruction.class,
diff --git a/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleGroupStore.java b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleGroupStore.java
index 5e6c084..18117ca 100644
--- a/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleGroupStore.java
+++ b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleGroupStore.java
@@ -19,9 +19,12 @@
 import static org.slf4j.LoggerFactory.getLogger;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -54,6 +57,7 @@
 
 import com.google.common.base.Function;
 import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Sets;
 
 /**
  * Manages inventory of group entries using trivial in-memory implementation.
@@ -583,4 +587,131 @@
                   getExtraneousGroupIdTable(deviceId).values());
     }
 
+    @Override
+    public void pushGroupMetrics(DeviceId deviceId,
+                                 Collection<Group> groupEntries) {
+        boolean deviceInitialAuditStatus =
+                deviceInitialAuditStatus(deviceId);
+        Set<Group> southboundGroupEntries =
+                Sets.newHashSet(groupEntries);
+        Set<Group> storedGroupEntries =
+                Sets.newHashSet(getGroups(deviceId));
+        Set<Group> extraneousStoredEntries =
+                Sets.newHashSet(getExtraneousGroups(deviceId));
+
+        log.trace("pushGroupMetrics: Displaying all ({}) "
+                + "southboundGroupEntries for device {}",
+                  southboundGroupEntries.size(),
+                  deviceId);
+        for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
+            Group group = it.next();
+            log.trace("Group {} in device {}", group, deviceId);
+        }
+
+        log.trace("Displaying all ({}) stored group entries for device {}",
+                  storedGroupEntries.size(),
+                  deviceId);
+        for (Iterator<Group> it1 = storedGroupEntries.iterator();
+                it1.hasNext();) {
+            Group group = it1.next();
+            log.trace("Stored Group {} for device {}", group, deviceId);
+        }
+
+        for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
+            Group group = it2.next();
+            if (storedGroupEntries.remove(group)) {
+                // we both have the group, let's update some info then.
+                log.trace("Group AUDIT: group {} exists "
+                        + "in both planes for device {}",
+                        group.id(), deviceId);
+                groupAdded(group);
+                it2.remove();
+            }
+        }
+        for (Group group : southboundGroupEntries) {
+            if (getGroup(group.deviceId(), group.id()) != null) {
+                // There is a group existing with the same id
+                // It is possible that group update is
+                // in progress while we got a stale info from switch
+                if (!storedGroupEntries.remove(getGroup(
+                             group.deviceId(), group.id()))) {
+                    log.warn("Group AUDIT: Inconsistent state:"
+                            + "Group exists in ID based table while "
+                            + "not present in key based table");
+                }
+            } else {
+                // there are groups in the switch that aren't in the store
+                log.trace("Group AUDIT: extraneous group {} exists "
+                        + "in data plane for device {}",
+                        group.id(), deviceId);
+                extraneousStoredEntries.remove(group);
+                extraneousGroup(group);
+            }
+        }
+        for (Group group : storedGroupEntries) {
+            // there are groups in the store that aren't in the switch
+            log.trace("Group AUDIT: group {} missing "
+                    + "in data plane for device {}",
+                    group.id(), deviceId);
+            groupMissing(group);
+        }
+        for (Group group : extraneousStoredEntries) {
+            // there are groups in the extraneous store that
+            // aren't in the switch
+            log.trace("Group AUDIT: clearing extransoeus group {} "
+                    + "from store for device {}",
+                    group.id(), deviceId);
+            removeExtraneousGroupEntry(group);
+        }
+
+        if (!deviceInitialAuditStatus) {
+            log.debug("Group AUDIT: Setting device {} initial "
+                    + "AUDIT completed", deviceId);
+            deviceInitialAuditCompleted(deviceId, true);
+        }
+    }
+
+    private void groupMissing(Group group) {
+        switch (group.state()) {
+            case PENDING_DELETE:
+                log.debug("Group {} delete confirmation from device {}",
+                          group, group.deviceId());
+                removeGroupEntry(group);
+                break;
+            case ADDED:
+            case PENDING_ADD:
+            case PENDING_UPDATE:
+                log.debug("Group {} is in store but not on device {}",
+                          group, group.deviceId());
+                StoredGroupEntry existing = (groupEntriesById.get(
+                              group.deviceId()) != null) ?
+                              groupEntriesById.get(group.deviceId()).get(group.id()) :
+                              null;
+                log.trace("groupMissing: group "
+                        + "entry {} in device {} moving "
+                        + "from {} to PENDING_ADD",
+                        existing.id(),
+                        existing.deviceId(),
+                        existing.state());
+                existing.setState(Group.GroupState.PENDING_ADD);
+                notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
+                                              group));
+                break;
+            default:
+                log.debug("Group {} has not been installed.", group);
+                break;
+        }
+    }
+
+    private void extraneousGroup(Group group) {
+        log.debug("Group {} is on device {} but not in store.",
+                  group, group.deviceId());
+        addOrUpdateExtraneousGroupEntry(group);
+    }
+
+    private void groupAdded(Group group) {
+        log.trace("Group {} Added or Updated in device {}",
+                  group, group.deviceId());
+        addOrUpdateGroupEntry(group);
+    }
 }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
index 5424558..bb2315d 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
@@ -195,11 +195,17 @@
                     @Override
                     public void onSuccess(FlowRuleOperations ops) {
                         pass(fwd);
+                        log.debug("Provisioned tables in {} with "
+                                + "forwarding rules for segment "
+                                + "router", deviceId);
                     }
 
                     @Override
                     public void onError(FlowRuleOperations ops) {
                         fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
+                        log.warn("Failed to provision tables in {} with "
+                                + "forwarding rules for segment router",
+                                deviceId);
                     }
                 }));
 
@@ -228,6 +234,8 @@
     }
 
     private void removeGroup(NextObjective nextObjective) {
+        log.debug("removeGroup in {}: for next objective id {}",
+                  deviceId, nextObjective.id());
         final GroupKey key = new DefaultGroupKey(
                 appKryo.serialize(nextObjective.id()));
         groupService.removeGroup(deviceId, key, appId);
@@ -293,6 +301,8 @@
     }
 
     private void addBucketToGroup(NextObjective nextObjective) {
+        log.debug("addBucketToGroup in {}: for next objective id {}",
+                  deviceId, nextObjective.id());
         Collection<TrafficTreatment> treatments = nextObjective.next();
         TrafficTreatment treatment = treatments.iterator().next();
         final GroupKey key = new DefaultGroupKey(
@@ -317,6 +327,8 @@
     }
 
     private void removeBucketFromGroup(NextObjective nextObjective) {
+        log.debug("removeBucketFromGroup in {}: for next objective id {}",
+                  deviceId, nextObjective.id());
         NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
         if (nextGroup != null) {
             Collection<TrafficTreatment> treatments = nextObjective.next();
@@ -369,7 +381,7 @@
         if ((ethType == null) ||
                 ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) &&
                 (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) {
-            log.debug("processSpecific: Unsupported "
+            log.warn("processSpecific: Unsupported "
                     + "forwarding objective criteraia");
             fail(fwd, ObjectiveError.UNSUPPORTED);
             return Collections.emptySet();
@@ -424,6 +436,10 @@
                 }
                 treatmentBuilder.group(group.id());
                 log.debug("Adding OUTGROUP action");
+            } else {
+                log.warn("processSpecific: No associated next objective object");
+                fail(fwd, ObjectiveError.GROUPMISSING);
+                return Collections.emptySet();
             }
         }
 
@@ -485,15 +501,39 @@
         return rules;
     }
 
+    protected List<FlowRule> processVlanIdFilter(Criterion c,
+                                                 FilteringObjective filt,
+                                                 ApplicationId applicationId) {
+        List<FlowRule> rules = new ArrayList<FlowRule>();
+        VlanIdCriterion v = (VlanIdCriterion) c;
+        log.debug("adding rule for VLAN: {}", v.vlanId());
+        TrafficSelector.Builder selector = DefaultTrafficSelector
+                .builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment
+                .builder();
+        PortCriterion p = (PortCriterion) filt.key();
+        if (v.vlanId() != VlanId.NONE) {
+            selector.matchVlanId(v.vlanId());
+            selector.matchInPort(p.port());
+            treatment.deferred().popVlan();
+        }
+        treatment.transition(tmacTableId);
+        FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(filt.priority()).fromApp(applicationId)
+                .makePermanent().forTable(vlanTableId).build();
+        rules.add(rule);
+
+        return rules;
+    }
+
     private void processFilter(FilteringObjective filt, boolean install,
                                ApplicationId applicationId) {
         // This driver only processes filtering criteria defined with switch
         // ports as the key
-        PortCriterion p;
-        if (!filt.key().equals(Criteria.dummy())
-                && filt.key().type() == Criterion.Type.IN_PORT) {
-            p = (PortCriterion) filt.key();
-        } else {
+        if (filt.key().equals(Criteria.dummy())
+                || filt.key().type() != Criterion.Type.IN_PORT) {
             log.warn("No key defined in filtering objective from app: {}. Not"
                     + "processing filtering objective", applicationId);
             fail(filt, ObjectiveError.UNKNOWN);
@@ -509,24 +549,11 @@
                     ops = install ? ops.add(rule) : ops.remove(rule);
                 }
             } else if (c.type() == Criterion.Type.VLAN_VID) {
-                VlanIdCriterion v = (VlanIdCriterion) c;
-                log.debug("adding rule for VLAN: {}", v.vlanId());
-                TrafficSelector.Builder selector = DefaultTrafficSelector
-                        .builder();
-                TrafficTreatment.Builder treatment = DefaultTrafficTreatment
-                        .builder();
-                if (v.vlanId() != VlanId.NONE) {
-                    selector.matchVlanId(v.vlanId());
-                    selector.matchInPort(p.port());
-                    treatment.deferred().popVlan();
+                for (FlowRule rule : processVlanIdFilter(c,
+                                                         filt,
+                                                         applicationId)) {
+                    ops = install ? ops.add(rule) : ops.remove(rule);
                 }
-                treatment.transition(tmacTableId);
-                FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
-                        .withSelector(selector.build())
-                        .withTreatment(treatment.build())
-                        .withPriority(filt.priority()).fromApp(applicationId)
-                        .makePermanent().forTable(vlanTableId).build();
-                ops = install ? ops.add(rule) : ops.remove(rule);
             } else if (c.type() == Criterion.Type.IPV4_DST) {
                 IPCriterion ip = (IPCriterion) c;
                 log.debug("adding rule for IP: {}", ip.ip());
@@ -554,13 +581,15 @@
             @Override
             public void onSuccess(FlowRuleOperations ops) {
                 pass(filt);
-                log.info("Provisioned tables for segment router");
+                log.debug("Provisioned tables in {} with fitering "
+                        + "rules for segment router", deviceId);
             }
 
             @Override
             public void onError(FlowRuleOperations ops) {
                 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
-                log.info("Failed to provision tables for segment router");
+                log.warn("Failed to provision tables in {} with "
+                        + "fitering rules for segment router", deviceId);
             }
         }));
     }
@@ -618,6 +647,8 @@
         @Override
         public void event(GroupEvent event) {
             if (event.type() == GroupEvent.Type.GROUP_ADDED) {
+                log.debug("InnerGroupListener: Group ADDED "
+                        + "event received in device {}", deviceId);
                 GroupKey key = event.subject().appCookie();
 
                 NextObjective obj = pendingGroups.getIfPresent(key);
@@ -628,6 +659,9 @@
                     pass(obj);
                     pendingGroups.invalidate(key);
                 }
+            } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
+                log.warn("InnerGroupListener: Group ADD "
+                        + "failed event received in device {}", deviceId);
             }
         }
     }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
index 4a817bf..f68a665 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.driver.pipeline;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -145,6 +144,10 @@
                 }
                 treatmentBuilder.group(group.id());
                 log.debug("Adding OUTGROUP action");
+            } else {
+                log.warn("processSpecific: No associated next objective object");
+                fail(fwd, ObjectiveError.GROUPMISSING);
+                return Collections.emptySet();
             }
         }
 
@@ -175,43 +178,23 @@
     protected List<FlowRule> processEthDstFilter(Criterion c,
                                                  FilteringObjective filt,
                                                  ApplicationId applicationId) {
-        List<FlowRule> rules = new ArrayList<FlowRule>();
-        EthCriterion e = (EthCriterion) c;
-        TrafficSelector.Builder selectorIp = DefaultTrafficSelector
-                .builder();
-        TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
-                .builder();
-
         // Store device termination Mac to be used in IP flow entries
+        EthCriterion e = (EthCriterion) c;
         deviceTMac = e.mac();
 
-        selectorIp.matchEthDst(e.mac());
-        selectorIp.matchEthType(Ethernet.TYPE_IPV4);
-        treatmentIp.transition(ipv4UnicastTableId);
-        FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
-                .withSelector(selectorIp.build())
-                .withTreatment(treatmentIp.build())
-                .withPriority(filt.priority()).fromApp(applicationId)
-                .makePermanent().forTable(tmacTableId).build();
-        log.debug("adding IP ETH rule for MAC: {}", e.mac());
-        rules.add(ruleIp);
+        log.debug("For now not adding any TMAC rules "
+                + "into Dell switches as it is ignoring");
 
-        TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
-                .builder();
-        TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
-                .builder();
-        selectorMpls.matchEthDst(e.mac());
-        selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
-        treatmentMpls.transition(mplsTableId);
-        FlowRule ruleMpls = DefaultFlowRule.builder()
-                .forDevice(deviceId).withSelector(selectorMpls.build())
-                .withTreatment(treatmentMpls.build())
-                .withPriority(filt.priority()).fromApp(applicationId)
-                .makePermanent().forTable(tmacTableId).build();
-        log.debug("adding MPLS ETH rule for MAC: {}", e.mac());
-        rules.add(ruleMpls);
-
-        return rules;
+        return Collections.emptyList();
     }
 
+    @Override
+    protected List<FlowRule> processVlanIdFilter(Criterion c,
+                                                 FilteringObjective filt,
+                                                 ApplicationId applicationId) {
+        log.debug("For now not adding any VLAN rules "
+                + "into Dell switches as it is ignoring");
+
+        return Collections.emptyList();
+    }
 }
\ No newline at end of file
diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml
index 19db8b0..7500657 100644
--- a/drivers/src/main/resources/onos-drivers.xml
+++ b/drivers/src/main/resources/onos-drivers.xml
@@ -37,13 +37,6 @@
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
                    impl="org.onosproject.driver.pipeline.SpringOpenTTPDell"/>
     </driver>
-    <driver name="cpqd" manufacturer="Stanford University, Ericsson Research and CPqD Research"
-            hwVersion="OpenFlow 1.3 Reference Userspace Switch" swVersion=".*">
-        <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.SpringOpenTTP"/>
-        <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
-                   impl="org.onosproject.driver.handshaker.OFSwitchImplSpringOpenTTP"/>
-    </driver>
     <driver name="linc-oe" extends="default"
             manufacturer="FlowForwarding.org" hwVersion="Unknown" swVersion="LINC-OE OpenFlow Software Switch 1.1">
         <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
diff --git a/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java b/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
index 3907ec6..2f29822 100644
--- a/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
+++ b/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
@@ -295,7 +295,7 @@
                     return;
                 }
                 if (m.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
-                    log.warn("Stats reply indicates more stats from sw {} for "
+                    log.debug("Stats reply indicates more stats from sw {} for "
                             + "port description",
                             h.getSwitchInfoString());
                     h.portDescReplies.add((OFPortDescStatsReply)m);