Attempt to fix Link vanishing after mastership change

- LLDPLinkProvider: handle DeviceUpdate event
- DeviceManager: publish Device events caused by Mastership change
- DeviceManager: Always try to markOffLine on deviceDisconnected
- GossipDeviceStore: Silently ignore failure to get Timestamp on port events

Change-Id: I51fbb3f1924007867512f20e62d6d53090c63640
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
index 21941b5..6fbc034 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
@@ -328,8 +328,8 @@
         final Timestamp timestamp = deviceClockService.getTimestamp(deviceId);
         final DeviceEvent event = markOfflineInternal(deviceId, timestamp);
         if (event != null) {
-            log.info("Notifying peers of a device offline topology event for deviceId: {}",
-                    deviceId);
+            log.info("Notifying peers of a device offline topology event for deviceId: {} {}",
+                    deviceId, timestamp);
             try {
                 notifyPeers(new InternalDeviceOfflineEvent(deviceId, timestamp));
             } catch (IOException e) {
@@ -399,7 +399,24 @@
                                        DeviceId deviceId,
                                        List<PortDescription> portDescriptions) {
 
-        final Timestamp newTimestamp = deviceClockService.getTimestamp(deviceId);
+        final Timestamp newTimestamp;
+        try {
+            newTimestamp = deviceClockService.getTimestamp(deviceId);
+        } catch (IllegalStateException e) {
+            log.info("Timestamp was not available for device {}", deviceId);
+            log.debug("  discarding {}", portDescriptions);
+            // Failed to generate timestamp.
+
+            // Possible situation:
+            //  Device connected and became master for short period of time,
+            // but lost mastership before this instance had the chance to
+            // retrieve term information.
+
+            // Information dropped here is expected to be recoverable by
+            // device probing after mastership change
+
+            return Collections.emptyList();
+        }
         log.info("timestamp for {} {}", deviceId, newTimestamp);
 
         final Timestamped<List<PortDescription>> timestampedInput
@@ -580,7 +597,16 @@
                                                      DeviceId deviceId,
                                                      PortDescription portDescription) {
 
-        final Timestamp newTimestamp = deviceClockService.getTimestamp(deviceId);
+        final Timestamp newTimestamp;
+        try {
+            newTimestamp = deviceClockService.getTimestamp(deviceId);
+        } catch (IllegalStateException e) {
+            log.info("Timestamp was not available for device {}", deviceId);
+            log.debug("  discarding {}", portDescription);
+            // Failed to generate timestamp. Ignoring.
+            // See updatePorts comment
+            return null;
+        }
         final Timestamped<PortDescription> deltaDesc
             = new Timestamped<>(portDescription, newTimestamp);
         final DeviceEvent event;