Adding mechanism for device subsystem & providers to trigger device
reconnect in support of ONOS-7645 (device driver change)

- added device listener to OpenFlowDeviceProvider to properly disconnect switch
- removed device listener from OpenFlowControllerImpl
- augmented DriverManager to consult NetworkConfigService as a primary source

Change-Id: I1aa8e9cc7e81ff3af7a72145f4e51f3e32022806
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index c9f09e5..cce89b0 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -52,9 +52,12 @@
 import org.onosproject.net.device.DefaultPortDescription;
 import org.onosproject.net.device.DefaultPortStatistics;
 import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceProvider;
 import org.onosproject.net.device.DeviceProviderRegistry;
 import org.onosproject.net.device.DeviceProviderService;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.device.PortDescription;
 import org.onosproject.net.device.PortStatistics;
 import org.onosproject.net.driver.Driver;
@@ -129,9 +132,11 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static org.onlab.util.Tools.get;
+import static org.onosproject.net.Device.Type.CONTROLLER;
 import static org.onosproject.net.DeviceId.deviceId;
 import static org.onosproject.net.Port.Type.COPPER;
 import static org.onosproject.net.Port.Type.FIBER;
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
 import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
 import static org.onosproject.net.optical.device.OduCltPortHelper.oduCltPortDescription;
 import static org.onosproject.net.optical.device.OmsPortHelper.omsPortDescription;
@@ -426,11 +431,15 @@
     private static final Frequency FREQ4_4 = Frequency.ofGHz(4_400);
 
     private static final long C = 299792458; // speed of light in m/s
+    public static final String SCHEME = "of";
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceProviderRegistry providerRegistry;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenFlowController controller;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -442,6 +451,7 @@
     private DeviceProviderService providerService;
 
     private final InternalDeviceProvider listener = new InternalDeviceProvider();
+    private final InternalDeviceListener deviceListener = new InternalDeviceListener();
 
     private static final String POLL_PROP_NAME = "portStatsPollFrequency";
     private static final int POLL_INTERVAL = 5;
@@ -463,13 +473,14 @@
      * Creates an OpenFlow device provider.
      */
     public OpenFlowDeviceProvider() {
-        super(new ProviderId("of", "org.onosproject.provider.openflow"));
+        super(new ProviderId(SCHEME, "org.onosproject.provider.openflow"));
     }
 
     @Activate
     public void activate(ComponentContext context) {
         cfgService.registerProperties(getClass());
         providerService = providerRegistry.register(this);
+        deviceService.addListener(deviceListener);
         controller.addListener(listener);
         controller.addEventListener(listener);
 
@@ -483,6 +494,7 @@
     public void deactivate(ComponentContext context) {
         cfgService.unregisterProperties(getClass(), false);
         listener.disable();
+        deviceService.removeListener(deviceListener);
         controller.removeListener(listener);
         providerRegistry.unregister(this);
         collectors.values().forEach(PortStatsCollector::stop);
@@ -1520,5 +1532,27 @@
         }
     }
 
+    class InternalDeviceListener implements DeviceListener {
 
+        @Override
+        public boolean isRelevant(DeviceEvent event) {
+            return event.subject().type() != CONTROLLER && event.type() == DEVICE_REMOVED
+                    && event.subject().id().uri().getScheme().equals(SCHEME);
+        }
+
+        @Override
+        public void event(DeviceEvent event) {
+            DeviceId deviceId = event.subject().id();
+            Dpid dpid = dpid(deviceId.uri());
+            OpenFlowSwitch sw = controller.getSwitch(dpid);
+            if (sw != null) {
+                LOG.debug("Forcing disconnect for device {}", deviceId);
+                PortStatsCollector portStatsCollector = collectors.remove(dpid);
+                if (portStatsCollector != null) {
+                    portStatsCollector.stop();
+                }
+                sw.disconnectSwitch();
+            }
+        }
+    }
 }