[ONOS-7143] Add arbitration update support by P4RuntimeClient

Change-Id: I671275576018d50447f969166a7b42a28dd93b1d
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimePipelineProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimePipelineProgrammable.java
index 1272305..911c5ed 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimePipelineProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimePipelineProgrammable.java
@@ -73,19 +73,6 @@
         }
 
         try {
-            if (!client.setPipelineConfig(pipeconf, deviceDataBuffer).get()) {
-                log.warn("Unable to deploy pipeconf {} to {}", pipeconf.id(), deviceId);
-                return false;
-            }
-        } catch (InterruptedException | ExecutionException e) {
-            log.error("Exception while deploying pipeconf to {}", deviceId, e);
-            return false;
-        }
-
-        try {
-            // It would make more sense to init the stream channel once the client
-            // is created, but P4runtime would reject any command if a P4info has
-            // not been set first.
             if (!client.initStreamChannel().get()) {
                 log.warn("Unable to init stream channel to {}.", deviceId);
                 return false;
@@ -95,6 +82,15 @@
             return false;
         }
 
+        try {
+            if (!client.setPipelineConfig(pipeconf, deviceDataBuffer).get()) {
+                log.warn("Unable to deploy pipeconf {} to {}", pipeconf.id(), deviceId);
+                return false;
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            log.error("Exception while deploying pipeconf to {}", deviceId, e);
+            return false;
+        }
         return true;
     }
 
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeHandshaker.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeHandshaker.java
index 8416786..7e41a99 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeHandshaker.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeHandshaker.java
@@ -60,10 +60,30 @@
 
     @Override
     public CompletableFuture<MastershipRole> roleChanged(MastershipRole newRole) {
+        deviceId = handler().data().deviceId();
+        controller = handler().get(P4RuntimeController.class);
         CompletableFuture<MastershipRole> result = new CompletableFuture<>();
-        log.warn("roleChanged not implemented");
-        result.complete(MastershipRole.MASTER);
-        // TODO.
+
+        client = controller.getClient(deviceId);
+        if (client == null || !controller.isReacheable(deviceId)) {
+            result.complete(MastershipRole.STANDBY);
+            return result;
+        }
+        if (newRole.equals(MastershipRole.MASTER)) {
+            client.sendMasterArbitrationUpdate().thenAcceptAsync(success -> {
+                if (!success) {
+                    log.warn("Device {} arbitration failed", deviceId);
+                    result.complete(MastershipRole.STANDBY);
+                } else {
+                    result.complete(MastershipRole.MASTER);
+                }
+            });
+        } else {
+            // Since we don't need to do anything, we can complete it directly
+            // Spec: The client with the highest election id is referred to as the
+            // "master", while all other clients are referred to as "slaves".
+            result.complete(newRole);
+        }
         return result;
     }
 }