trigger device query after mastership reelection

Change-Id: Ibf8b32ed1de2a904289731596a28bd5524d6ea25

Conflicts:
	core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
diff --git a/core/api/src/main/java/org/onlab/onos/net/device/DeviceProvider.java b/core/api/src/main/java/org/onlab/onos/net/device/DeviceProvider.java
index 9934b8d..ec73ce5 100644
--- a/core/api/src/main/java/org/onlab/onos/net/device/DeviceProvider.java
+++ b/core/api/src/main/java/org/onlab/onos/net/device/DeviceProvider.java
@@ -13,7 +13,7 @@
 
     /**
      * Triggers an asynchronous probe of the specified device, intended to
-     * determine whether the host is present or not. An indirect result of this
+     * determine whether the device is present or not. An indirect result of this
      * should be invocation of
      * {@link org.onlab.onos.net.device.DeviceProviderService#deviceConnected} )} or
      * {@link org.onlab.onos.net.device.DeviceProviderService#deviceDisconnected}
diff --git a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
index fd47dc7..a157e50 100644
--- a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
@@ -161,6 +161,17 @@
         }
     }
 
+    // Queries a device for port information.
+    private void queryPortInfo(DeviceId deviceId) {
+        Device device = store.getDevice(deviceId);
+        // FIXME: Device might not be there yet. (eventual consistent)
+        if (device == null) {
+            return;
+        }
+        DeviceProvider provider = getProvider(device.providerId());
+        provider.triggerProbe(device);
+    }
+
     @Override
     public void removeDevice(DeviceId deviceId) {
         checkNotNull(deviceId, DEVICE_ID_NULL);
@@ -210,8 +221,6 @@
             log.info("Device {} connected", deviceId);
             // check my Role
             MastershipRole role = mastershipService.requestRoleFor(deviceId);
-            log.info("## - our role for {} is {} [master is {}]", deviceId, role,
-                    mastershipService.getMasterFor(deviceId));
             if (role != MastershipRole.MASTER) {
                 // TODO: Do we need to explicitly tell the Provider that
                 // this instance is no longer the MASTER? probably not
@@ -265,7 +274,6 @@
             // but if I was the last STANDBY connection, etc. and no one else
             // was there to mark the device offline, this instance may need to
             // temporarily request for Master Role and mark offline.
-            log.info("## for {} role is {}", deviceId, mastershipService.getLocalRole(deviceId));
             if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) {
                 log.debug("Device {} disconnected, but I am not the master", deviceId);
                 //let go of ability to be backup
@@ -373,7 +381,6 @@
             final DeviceId did = event.subject();
             final NodeId myNodeId = clusterService.getLocalNode().id();
 
-            log.info("## got Mastershipevent for dev {}", did);
             if (myNodeId.equals(event.roleInfo().master())) {
                 MastershipTerm term = termService.getMastershipTerm(did);
 
@@ -384,7 +391,6 @@
                     return;
                 }
 
-                log.info("## setting term for CPS as new master for {}", did);
                 // only set the new term if I am the master
                 deviceClockProviderService.setMastershipTerm(did, term);
 
@@ -404,6 +410,7 @@
                                     device.serialNumber(), device.chassisId()));
                 }
                 //TODO re-collect device information to fix potential staleness
+                queryPortInfo(did);
                 applyRole(did, MastershipRole.MASTER);
             } else if (event.roleInfo().backups().contains(myNodeId)) {
                 applyRole(did, MastershipRole.STANDBY);
diff --git a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
index 6fd02bc..1375a20 100644
--- a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
+++ b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
@@ -110,8 +110,7 @@
      *
      * @param role the failed role
      */
-    void returnRoleAssertFailure(RoleState role);
-
+    public void returnRoleAssertFailure(RoleState role);
 
     /**
      * Indicates if this switch is optical.
@@ -120,5 +119,4 @@
      */
     public boolean isOptical();
 
-
 }
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OFChannelHandler.java b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OFChannelHandler.java
index 009cd3f..d15d9f1 100644
--- a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OFChannelHandler.java
+++ b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OFChannelHandler.java
@@ -608,6 +608,12 @@
                 h.dispatchMessage(m);
             }
 
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m) {
+                // TODO verify this leads to right behavior.
+                h.dispatchMessage(m);
+            }
+
         };
 
         private final boolean handshakeComplete;
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
index 565ccb9..46b8be6 100644
--- a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -142,6 +142,7 @@
     public void processPacket(Dpid dpid, OFMessage msg) {
         switch (msg.getType()) {
         case PORT_STATUS:
+        case FEATURES_REPLY:
             for (OpenFlowSwitchListener l : ofSwitchListener) {
                 l.portChanged(dpid, (OFPortStatus) msg);
             }
diff --git a/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
index fcc7810..1cdc5d1 100644
--- a/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -23,7 +23,9 @@
 import org.onlab.onos.openflow.controller.OpenFlowSwitch;
 import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
 import org.onlab.onos.openflow.controller.RoleState;
+import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriver;
 import org.onlab.packet.ChassisId;
+import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortState;
@@ -89,6 +91,28 @@
     @Override
     public void triggerProbe(Device device) {
         LOG.info("Triggering probe on device {}", device.id());
+
+        // 1. check device liveness
+        // FIXME if possible, we might want this to be part of
+        // OpenFlowSwitch interface so the driver interface isn't misused.
+        OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri()));
+        if (!((OpenFlowSwitchDriver) sw).isConnected()) {
+            providerService.deviceDisconnected(device.id());
+            return;
+        }
+
+        // 2. Prompt an update of port information. Do we have an XID for this?
+        OFFactory fact = sw.factory();
+        switch (fact.getVersion()) {
+            case OF_10:
+                sw.sendMsg(fact.buildFeaturesRequest().setXid(0).build());
+                break;
+            case OF_13:
+                sw.sendMsg(fact.buildPortDescStatsRequest().setXid(0).build());
+                break;
+            default:
+                LOG.warn("Unhandled protocol version");
+        }
     }
 
     @Override