Allow sharing the same gRPC channel between clients
This change introduces a refactoring of the gRPC protocol subsystem that
allows the creation of a gRPC chanel independently of the client, while
allowing multiple clients to share the same channel (e.g. as in Stratum
where we use 3 clients).
Moreover, we refactor the P4RuntimeClient API to support multiple
P4Runtime-internal device ID using the same client. While before the
client was associated to one of such ID.
Finally, we provide an abstract implementation for gRPC-based driver
behaviors, reducing code duplication in P4Runtime, gNMI and gNOI drivers.
Change-Id: I1a46352bbbef1e0d24042f169ae8ba580202944f
diff --git a/drivers/gnmi/BUILD b/drivers/gnmi/BUILD
index efc3f08..f01a9f3 100644
--- a/drivers/gnmi/BUILD
+++ b/drivers/gnmi/BUILD
@@ -7,7 +7,7 @@
"//protocols/gnmi/stub:onos-protocols-gnmi-stub",
"//protocols/gnmi/api:onos-protocols-gnmi-api",
"//protocols/grpc/api:onos-protocols-grpc-api",
- "//protocols/grpc/proto:onos-protocols-grpc-proto",
+ "//protocols/grpc/utils:onos-protocols-grpc-utils",
]
BUNDLES = [
diff --git a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/AbstractGnmiHandlerBehaviour.java b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/AbstractGnmiHandlerBehaviour.java
deleted file mode 100644
index 72233fc..0000000
--- a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/AbstractGnmiHandlerBehaviour.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.drivers.gnmi;
-
-import com.google.common.base.Strings;
-import org.onosproject.gnmi.api.GnmiClient;
-import org.onosproject.gnmi.api.GnmiClientKey;
-import org.onosproject.gnmi.api.GnmiController;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.config.basics.BasicDeviceConfig;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.AbstractHandlerBehaviour;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-/**
- * Abstract implementation of a behaviour handler for a gNMI device.
- */
-public class AbstractGnmiHandlerBehaviour extends AbstractHandlerBehaviour {
-
- protected final Logger log = LoggerFactory.getLogger(getClass());
- protected DeviceId deviceId;
- protected DeviceService deviceService;
- protected GnmiClient client;
-
- protected boolean setupBehaviour(String opName) {
- deviceId = handler().data().deviceId();
- deviceService = handler().get(DeviceService.class);
- client = getClientByKey();
- if (client == null) {
- log.warn("Missing client for {}, aborting {}", deviceId, opName);
- return false;
- }
-
- return true;
- }
-
- GnmiClient getClientByKey() {
- final GnmiClientKey clientKey = clientKey();
- if (clientKey == null) {
- return null;
- }
- return handler().get(GnmiController.class).getClient(clientKey);
- }
-
- protected GnmiClientKey clientKey() {
- deviceId = handler().data().deviceId();
-
- final BasicDeviceConfig cfg = handler().get(NetworkConfigService.class)
- .getConfig(deviceId, BasicDeviceConfig.class);
- if (cfg == null || Strings.isNullOrEmpty(cfg.managementAddress())) {
- log.error("Missing or invalid config for {}, cannot derive " +
- "gNMI server endpoints", deviceId);
- return null;
- }
-
- try {
- return new GnmiClientKey(
- deviceId, new URI(cfg.managementAddress()));
- } catch (URISyntaxException e) {
- log.error("Management address of {} is not a valid URI: {}",
- deviceId, cfg.managementAddress());
- return null;
- }
- }
-}
diff --git a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/GnmiHandshaker.java b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/GnmiHandshaker.java
index a6d0c04..82fc40c 100644
--- a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/GnmiHandshaker.java
+++ b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/GnmiHandshaker.java
@@ -17,33 +17,23 @@
package org.onosproject.drivers.gnmi;
import org.onosproject.gnmi.api.GnmiClient;
-import org.onosproject.gnmi.api.GnmiClientKey;
import org.onosproject.gnmi.api.GnmiController;
+import org.onosproject.grpc.utils.AbstractGrpcHandshaker;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.device.DeviceHandshaker;
import java.util.concurrent.CompletableFuture;
-import static java.util.concurrent.CompletableFuture.completedFuture;
-
/**
* Implementation of DeviceHandshaker for gNMI.
*/
-public class GnmiHandshaker extends AbstractGnmiHandlerBehaviour implements DeviceHandshaker {
+public class GnmiHandshaker
+ extends AbstractGrpcHandshaker<GnmiClient, GnmiController>
+ implements DeviceHandshaker {
- @Override
- public boolean isReachable() {
- final GnmiClient client = getClientByKey();
- return client != null && client.isServerReachable();
- }
- @Override
- public CompletableFuture<Boolean> probeReachability() {
- final GnmiClient client = getClientByKey();
- if (client == null) {
- return completedFuture(false);
- }
- return client.probeService();
+ public GnmiHandshaker() {
+ super(GnmiController.class);
}
@Override
@@ -65,33 +55,4 @@
public MastershipRole getRole() {
throw new UnsupportedOperationException("Mastership operation not supported");
}
-
- @Override
- public CompletableFuture<Boolean> connect() {
- return CompletableFuture.supplyAsync(this::createClient);
- }
-
- private boolean createClient() {
- GnmiClientKey clientKey = clientKey();
- if (clientKey == null) {
- return false;
- }
- if (!handler().get(GnmiController.class).createClient(clientKey)) {
- log.warn("Unable to create client for {}",
- handler().data().deviceId());
- return false;
- }
- return true;
- }
-
- @Override
- public boolean isConnected() {
- return getClientByKey() != null;
- }
-
- @Override
- public void disconnect() {
- handler().get(GnmiController.class)
- .removeClient(handler().data().deviceId());
- }
}
diff --git a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiDeviceDescriptionDiscovery.java b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiDeviceDescriptionDiscovery.java
index a85cdfb..210a237 100644
--- a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiDeviceDescriptionDiscovery.java
+++ b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiDeviceDescriptionDiscovery.java
@@ -23,6 +23,9 @@
import gnmi.Gnmi.GetRequest;
import gnmi.Gnmi.GetResponse;
import org.onlab.packet.ChassisId;
+import org.onosproject.gnmi.api.GnmiClient;
+import org.onosproject.gnmi.api.GnmiController;
+import org.onosproject.grpc.utils.AbstractGrpcHandlerBehaviour;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
@@ -48,7 +51,7 @@
* supports the gNMI protocol and Openconfig models.
*/
public class OpenConfigGnmiDeviceDescriptionDiscovery
- extends AbstractGnmiHandlerBehaviour
+ extends AbstractGrpcHandlerBehaviour<GnmiClient, GnmiController>
implements DeviceDescriptionDiscovery {
private static final Logger log = LoggerFactory
@@ -58,6 +61,10 @@
private static final String UNKNOWN = "unknown";
+ public OpenConfigGnmiDeviceDescriptionDiscovery() {
+ super(GnmiController.class);
+ }
+
@Override
public DeviceDescription discoverDeviceDetails() {
return new DefaultDeviceDescription(
diff --git a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiPortAdminBehaviour.java b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiPortAdminBehaviour.java
index 4f050b0..666d5b1 100644
--- a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiPortAdminBehaviour.java
+++ b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiPortAdminBehaviour.java
@@ -18,6 +18,8 @@
import gnmi.Gnmi;
import org.onosproject.gnmi.api.GnmiClient;
+import org.onosproject.gnmi.api.GnmiController;
+import org.onosproject.grpc.utils.AbstractGrpcHandlerBehaviour;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.PortAdmin;
@@ -29,11 +31,18 @@
* Implementation of PortAdmin for gNMI devices with OpenConfig support.
*/
public class OpenConfigGnmiPortAdminBehaviour
- extends AbstractGnmiHandlerBehaviour
+ extends AbstractGrpcHandlerBehaviour<GnmiClient, GnmiController>
implements PortAdmin {
+ public OpenConfigGnmiPortAdminBehaviour() {
+ super(GnmiController.class);
+ }
+
@Override
public CompletableFuture<Boolean> enable(PortNumber number) {
+ if (!setupBehaviour("enable()")) {
+ return completedFuture(false);
+ }
doEnable(number, true);
// Always returning true is OK assuming this is used only by the
// GeneralDeviceProvider, which ignores the return value and instead
@@ -43,6 +52,9 @@
@Override
public CompletableFuture<Boolean> disable(PortNumber number) {
+ if (!setupBehaviour("disable()")) {
+ return completedFuture(false);
+ }
doEnable(number, false);
return completedFuture(true);
}
@@ -58,11 +70,6 @@
portNumber, deviceId);
return;
}
- final GnmiClient client = getClientByKey();
- if (client == null) {
- log.warn("Cannot update ports on {}, missing gNMI client", deviceId);
- return;
- }
final Gnmi.Path path = Gnmi.Path.newBuilder()
.addElem(Gnmi.PathElem.newBuilder().setName("interfaces").build())
.addElem(Gnmi.PathElem.newBuilder().setName("interface")
diff --git a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiPortStatisticsDiscovery.java b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiPortStatisticsDiscovery.java
index fa7231f..6e361ff 100644
--- a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiPortStatisticsDiscovery.java
+++ b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/OpenConfigGnmiPortStatisticsDiscovery.java
@@ -23,6 +23,9 @@
import gnmi.Gnmi.GetResponse;
import gnmi.Gnmi.Path;
import org.apache.commons.lang3.tuple.Pair;
+import org.onosproject.gnmi.api.GnmiClient;
+import org.onosproject.gnmi.api.GnmiController;
+import org.onosproject.grpc.utils.AbstractGrpcHandlerBehaviour;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
@@ -41,13 +44,18 @@
/**
* Behaviour to get port statistics from device via gNMI.
*/
-public class OpenConfigGnmiPortStatisticsDiscovery extends AbstractGnmiHandlerBehaviour
+public class OpenConfigGnmiPortStatisticsDiscovery
+ extends AbstractGrpcHandlerBehaviour<GnmiClient, GnmiController>
implements PortStatisticsDiscovery {
private static final Map<Pair<DeviceId, PortNumber>, Long> PORT_START_TIMES =
Maps.newConcurrentMap();
private static final String LAST_CHANGE = "last-changed";
+ public OpenConfigGnmiPortStatisticsDiscovery() {
+ super(GnmiController.class);
+ }
+
@Override
public Collection<PortStatistics> discoverPortStatistics() {
if (!setupBehaviour("discoverPortStatistics()")) {