Add support for enabling/disabling ports for gNMI devices

This change also includes:
- Refactoring of gNMI protocol+driver to take advantage of the recent
changes to the gRPC protocol subsystem (e.g. no more locking, start RPC
with timeouts, etc.).
- Fixed Stratum driver to work after GeneralDeviceProvider refactoring
- Updated bmv2.py to generate ChassisConfig for stratum_bmv2
- Fixed portstate command to use the same port name as in the store

Change-Id: I0dad3bc73e4b6d907b5cf6b7b9a2852943226be7
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/client/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/client/P4RuntimeClientImpl.java
index d06e3fc..d54ef97 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/client/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/client/P4RuntimeClientImpl.java
@@ -42,7 +42,6 @@
 import java.util.function.Consumer;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static java.lang.String.format;
 import static p4.v1.P4RuntimeOuterClass.GetForwardingPipelineConfigRequest.ResponseType.COOKIE_ONLY;
 
 /**
@@ -96,9 +95,9 @@
     }
 
     @Override
-    protected Void doShutdown() {
+    public void shutdown() {
         streamClient.closeSession();
-        return super.doShutdown();
+        super.shutdown();
     }
 
     @Override
@@ -191,6 +190,22 @@
         return future;
     }
 
+    @Override
+    protected void handleRpcError(Throwable throwable, String opDescription) {
+        if (throwable instanceof StatusRuntimeException) {
+            checkGrpcException((StatusRuntimeException) throwable);
+        }
+        super.handleRpcError(throwable, opDescription);
+    }
+
+    private void checkGrpcException(StatusRuntimeException sre) {
+        if (sre.getStatus().getCode() == Status.Code.PERMISSION_DENIED) {
+            // Notify upper layers that this node is not master.
+            controller.postEvent(new DeviceAgentEvent(
+                    DeviceAgentEvent.Type.NOT_MASTER, deviceId));
+        }
+    }
+
     /**
      * Returns the P4Runtime-internal device ID associated with this client.
      *
@@ -252,38 +267,4 @@
         runInCancellableContext(() -> stubConsumer.accept(
                 P4RuntimeGrpc.newStub(channel)));
     }
-
-    /**
-     * Logs the error and checks it for any condition that might be of interest
-     * for the controller.
-     *
-     * @param throwable     throwable
-     * @param opDescription operation description for logging
-     */
-    void handleRpcError(Throwable throwable, String opDescription) {
-        if (throwable instanceof StatusRuntimeException) {
-            final StatusRuntimeException sre = (StatusRuntimeException) throwable;
-            checkGrpcException(sre);
-            final String logMsg;
-            if (sre.getCause() == null) {
-                logMsg = sre.getMessage();
-            } else {
-                logMsg = format("%s (%s)", sre.getMessage(), sre.getCause().toString());
-            }
-            log.warn("Error while performing {} on {}: {}",
-                     opDescription, deviceId, logMsg);
-            log.debug("", throwable);
-            return;
-        }
-        log.error(format("Exception while performing %s on %s",
-                         opDescription, deviceId), throwable);
-    }
-
-    private void checkGrpcException(StatusRuntimeException sre) {
-        if (sre.getStatus().getCode() == Status.Code.PERMISSION_DENIED) {
-            // Notify upper layers that this node is not master.
-            controller.postEvent(new DeviceAgentEvent(
-                    DeviceAgentEvent.Type.NOT_MASTER, deviceId));
-        }
-    }
 }