Refactor P4Runtime subsystem to implement async connection procedure

This patch is an attempt to solve issues observed when restarting both
switches and ONOS nodes. Most of the issues seemed to depend on a
brittle mastership handling when deploying the pipeline.

With this patch, GDP registers devices to the core with available=false
(i.e. offline) and marks them online only when the P4 pipeline has been
deployed to the device. A new PiPipeconfWatchdogService takes care of
deploying pipelines and producing event when devices are ready.

Moreover, we fix a race condition where pipeconf-related behaviors
were not found. This was caused by GDP enforcing the merged
driver name in the network config, while external entities (e.g.
Mininet) were pushing a JSON blob with the base driver name. This patch
removes the need to rely on such a trick and instead uses
pipeconf-aware logic directly in the driver manager (change #19622).

Finally, we fix issues in P4RuntimeClientImpl that were causing the
stream channel not detecting unreachable devices. The solution is to
follow gRPC APIs and re-instantiate a new channel once the first fails.

Change-Id: I6fbc91859c0fb58a6db3bc197b7081a8fe9f97f7
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/PiPipelineProgrammable.java b/core/api/src/main/java/org/onosproject/net/behaviour/PiPipelineProgrammable.java
index 2373af4..22367ba 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/PiPipelineProgrammable.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/PiPipelineProgrammable.java
@@ -24,21 +24,40 @@
 import java.util.concurrent.CompletableFuture;
 
 /**
- * Behavior to program the pipeline of a device that supports protocol-independence.
+ * Behavior to program the pipeline of a device that supports
+ * protocol-independence.
  */
 @Beta
 public interface PiPipelineProgrammable extends HandlerBehaviour {
     /**
-     * Deploys the given pipeconf to the device.
+     * Writes the given pipeconf to the device, returns a completable future
+     * with true is the operations was successful, false otherwise.
+     * <p>
+     * After the future has been completed, the device is expected to process
+     * data plane packets according to the written pipeconf.
      *
      * @param pipeconf pipeconf
-     * @return true if the operation was successful, false otherwise
+     * @return completable future set to true if the operation was successful,
+     * false otherwise
      */
     // TODO: return an explanation of why things went wrong, and the status of the device.
-    CompletableFuture<Boolean> deployPipeconf(PiPipeconf pipeconf);
+    CompletableFuture<Boolean> setPipeconf(PiPipeconf pipeconf);
 
     /**
-     * Returns the default pipeconf for ths device, to be used when any other pipeconf is not available.
+     * Returns true if the device is configured with the given pipeconf, false
+     * otherwise.
+     * <p>
+     * This method is expected to always return true after successfully calling
+     * {@link #setPipeconf(PiPipeconf)} with the given pipeconf.
+     *
+     * @param pipeconf pipeconf
+     * @return true if the device has the given pipeconf set, false otherwise
+     */
+    boolean isPipeconfSet(PiPipeconf pipeconf);
+
+    /**
+     * Returns the default pipeconf for this device, to be used when any other
+     * pipeconf is not available.
      *
      * @return optional pipeconf
      */