Relinquish mastership when device reports "permission" denied event

Also reduces default pipeconf watchdog probe interval
Also fixes NPE on GDP when device is unreachable

Change-Id: Ie2fe1874b0883a037596d9a555a2f8cc030a55a6
(cherry picked from commit d797e2c28505fbdbb8597038ebcf977a053bae72)
diff --git a/core/api/src/main/java/org/onosproject/net/device/DeviceAgentEvent.java b/core/api/src/main/java/org/onosproject/net/device/DeviceAgentEvent.java
index 22eab99..d2520b0 100644
--- a/core/api/src/main/java/org/onosproject/net/device/DeviceAgentEvent.java
+++ b/core/api/src/main/java/org/onosproject/net/device/DeviceAgentEvent.java
@@ -64,6 +64,12 @@
          */
         ROLE_NONE,
 
+        /**
+         * Signifies that the agent cannot perform operations on the device
+         * because its role is not master.
+         */
+        NOT_MASTER,
+
     }
 
     /**
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfWatchdogManager.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfWatchdogManager.java
index 8376295..6b41fd5 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfWatchdogManager.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfWatchdogManager.java
@@ -108,7 +108,7 @@
     private ComponentConfigService componentConfigService;
 
     private static final String PROBE_INTERVAL = "probeInterval";
-    private static final int DEFAULT_PROBE_INTERVAL = 30;
+    private static final int DEFAULT_PROBE_INTERVAL = 15;
     @Property(name = PROBE_INTERVAL, intValue = DEFAULT_PROBE_INTERVAL,
             label = "Configure interval in seconds for device pipeconf probing")
     private int probeInterval = DEFAULT_PROBE_INTERVAL;
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeEvent.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeEvent.java
index 0316ed4..4e0ea60b 100644
--- a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeEvent.java
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeEvent.java
@@ -42,7 +42,12 @@
         /**
          * Channel Event.
          */
-        CHANNEL_EVENT
+        CHANNEL_EVENT,
+
+        /**
+         * Permission denied (not master).
+         */
+        PERMISSION_DENIED,
     }
 
     public P4RuntimeEvent(Type type, P4RuntimeEventSubject subject) {
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ArbitrationResponse.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ArbitrationResponse.java
index ea3c24f..f93a4cd 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ArbitrationResponse.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ArbitrationResponse.java
@@ -22,7 +22,7 @@
 /**
  * Default implementation of arbitration in P4Runtime.
  */
-class ArbitrationResponse implements P4RuntimeEventSubject {
+final class ArbitrationResponse implements P4RuntimeEventSubject {
 
     private DeviceId deviceId;
     private boolean isMaster;
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/BaseP4RuntimeEventSubject.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/BaseP4RuntimeEventSubject.java
new file mode 100644
index 0000000..a78f10c
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/BaseP4RuntimeEventSubject.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.p4runtime.ctl;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.p4runtime.api.P4RuntimeEventSubject;
+
+/**
+ * Base P4Runtime event subject that carries just the device ID that originated
+ * the event.
+ */
+final class BaseP4RuntimeEventSubject implements P4RuntimeEventSubject {
+
+    private DeviceId deviceId;
+
+    /**
+     * Creates an event subject.
+     *
+     * @param deviceId the device
+     */
+    BaseP4RuntimeEventSubject(DeviceId deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    @Override
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
index 443514f..867bfa3 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
@@ -1113,8 +1113,8 @@
             case PERMISSION_DENIED:
                 // Notify upper layers that this node is not master.
                 controller.postEvent(new P4RuntimeEvent(
-                        P4RuntimeEvent.Type.ARBITRATION_RESPONSE,
-                        new ArbitrationResponse(deviceId, false)));
+                        P4RuntimeEvent.Type.PERMISSION_DENIED,
+                        new BaseP4RuntimeEventSubject(deviceId)));
                 break;
             case RESOURCE_EXHAUSTED:
                 break;
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
index 4ca08f1..cb413bc 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
@@ -261,12 +261,20 @@
             case ARBITRATION_RESPONSE:
                 handleArbitrationReply(event);
                 break;
+            case PERMISSION_DENIED:
+                handlePermissionDenied(event);
+                break;
             default:
                 post(event);
                 break;
         }
     }
 
+    private void handlePermissionDenied(P4RuntimeEvent event) {
+        postDeviceAgentEvent(event.subject().deviceId(), new DeviceAgentEvent(
+                DeviceAgentEvent.Type.NOT_MASTER, event.subject().deviceId()));
+    }
+
     private void handleChannelEvent(P4RuntimeEvent event) {
         final ChannelEvent channelEvent = (ChannelEvent) event.subject();
         final DeviceId deviceId = channelEvent.deviceId();
diff --git a/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java b/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
index 42faa0c..e5c321e 100644
--- a/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
+++ b/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
@@ -455,7 +455,7 @@
         // Start connection via handshaker.
         final Boolean connectSuccess = getFutureWithDeadline(
                 handshaker.connect(), "initiating connection",
-                deviceId, null, opTimeoutShort);
+                deviceId, false, opTimeoutShort);
         if (!connectSuccess) {
             log.warn("Unable to connect to {}", deviceId);
         }
@@ -887,6 +887,12 @@
         }
     }
 
+    private void handleNotMaster(DeviceId deviceId) {
+        log.warn("Device {} notified that this node is not master, " +
+                         "relinquishing mastership...", deviceId);
+        mastershipService.relinquishMastership(deviceId);
+    }
+
     private <U> U getFutureWithDeadline(CompletableFuture<U> future, String opDescription,
                                         DeviceId deviceId, U defaultValue, int timeout) {
         try {
@@ -948,6 +954,9 @@
                 case ROLE_NONE:
                     handleMastershipResponse(deviceId, MastershipRole.NONE);
                     break;
+                case NOT_MASTER:
+                    handleNotMaster(deviceId);
+                    break;
                 default:
                     log.warn("Unrecognized device agent event {}", event.type());
             }