From d771648025bbc73c180eea52dcc382b5df7024dd Mon Sep 17 00:00:00 2001 From: Yi Tseng Date: Wed, 31 Oct 2018 15:34:30 -0700 Subject: [PATCH] Cherry pick gNMI and Stratum related changes to this branch Cherry picked commits: 20211 Update gNMI version and build script 20247 [ONOS-7829] Implement AbstractGrpcClient and AbstractGrpcClientControl 20233 [ONOS-7141][ONOS-7142] Add GnmiClient and GnmiController 20234 Refactor OpenConfig gNMI device description descovery 20260 [ONOS-7831] Implement GnmiHandshaker 20270 Add Stratum driver Change-Id: I81ad8bce45251af5909cfcac0edbcfd11c8ebf1d --- drivers/gnmi/BUILD | 1 - .../gnmi/AbstractGnmiHandlerBehaviour.java | 14 +- .../drivers/gnmi/GnmiHandshaker.java | 4 +- ...nConfigGnmiDeviceDescriptionDiscovery.java | 73 ++++------ .../AbstractP4RuntimeHandlerBehaviour.java | 16 +-- .../P4RuntimeActionGroupProgrammable.java | 2 +- .../P4RuntimeFlowRuleProgrammable.java | 2 +- .../p4runtime/P4RuntimeMeterProgrammable.java | 2 +- .../P4RuntimeMulticastGroupProgrammable.java | 2 +- drivers/stratum/BUILD | 25 ++++ .../drivers/stratum/StratumDriversLoader.java | 31 ++++ .../drivers/stratum/StratumHandshaker.java | 135 ++++++++++++++++++ .../StratumDummyPipelineProgrammable.java | 44 ++++++ .../drivers/stratum/dummy/package-info.java | 21 +++ .../drivers/stratum/package-info.java | 20 +++ .../src/main/resources/stratum-drivers.xml | 32 +++++ .../org/onosproject/gnmi/api/GnmiClient.java | 8 +- .../onosproject/gnmi/api/GnmiClientKey.java | 7 +- .../onosproject/gnmi/ctl/GnmiClientImpl.java | 9 +- .../grpc/api/GrpcClientController.java | 40 +++--- .../grpc/ctl/AbstractGrpcClient.java | 20 ++- .../ctl/AbstractGrpcClientController.java | 5 +- .../p4runtime/ctl/P4RuntimeClientImpl.java | 2 +- .../device/impl/GeneralDeviceProvider.java | 20 ++- tools/build/bazel/modules.bzl | 1 + 25 files changed, 410 insertions(+), 126 deletions(-) create mode 100644 drivers/stratum/BUILD create mode 100644 drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDriversLoader.java create mode 100644 drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java create mode 100644 drivers/stratum/src/main/java/org/onosproject/drivers/stratum/dummy/StratumDummyPipelineProgrammable.java create mode 100644 drivers/stratum/src/main/java/org/onosproject/drivers/stratum/dummy/package-info.java create mode 100644 drivers/stratum/src/main/java/org/onosproject/drivers/stratum/package-info.java create mode 100644 drivers/stratum/src/main/resources/stratum-drivers.xml diff --git a/drivers/gnmi/BUILD b/drivers/gnmi/BUILD index 4a4c10077c..efc3f0805e 100644 --- a/drivers/gnmi/BUILD +++ b/drivers/gnmi/BUILD @@ -28,7 +28,6 @@ onos_app( included_bundles = BUNDLES, required_apps = [ "org.onosproject.generaldeviceprovider", - "org.onosproject.protocols.grpc", "org.onosproject.protocols.gnmi", ], title = "gNMI Drivers", 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 index e6d8b163ca..3bfca46f44 100644 --- a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/AbstractGnmiHandlerBehaviour.java +++ b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/AbstractGnmiHandlerBehaviour.java @@ -41,9 +41,8 @@ public class AbstractGnmiHandlerBehaviour extends AbstractHandlerBehaviour { private static final String DEVICE_REQ_TIMEOUT = "deviceRequestTimeout"; private static final int DEFAULT_DEVICE_REQ_TIMEOUT = 60; - public static final String GNMI_SERVER_ADDR_KEY = "gnmi_ip"; - public static final String GNMI_SERVER_PORT_KEY = "gnmi_port"; - private static final String GNMI_SERVICE_NAME = "gnmi"; + private static final String GNMI_SERVER_ADDR_KEY = "gnmi_ip"; + private static final String GNMI_SERVER_PORT_KEY = "gnmi_port"; protected final Logger log = LoggerFactory.getLogger(getClass()); protected DeviceId deviceId; @@ -66,7 +65,7 @@ public class AbstractGnmiHandlerBehaviour extends AbstractHandlerBehaviour { return true; } - protected GnmiClient createClient() { + GnmiClient createClient() { deviceId = handler().data().deviceId(); controller = handler().get(GnmiController.class); @@ -74,7 +73,7 @@ public class AbstractGnmiHandlerBehaviour extends AbstractHandlerBehaviour { final String serverPortString = this.data().value(GNMI_SERVER_PORT_KEY); if (serverAddr == null || serverPortString == null) { - log.warn("Unable to create client for {}, missing driver data key (required is {}, {}, and {})", + log.warn("Unable to create client for {}, missing driver data key (required is {} and {})", deviceId, GNMI_SERVER_ADDR_KEY, GNMI_SERVER_PORT_KEY); return null; } @@ -83,11 +82,10 @@ public class AbstractGnmiHandlerBehaviour extends AbstractHandlerBehaviour { try { serverPort = Integer.parseUnsignedInt(serverPortString); } catch (NumberFormatException e) { - log.error("{} is not a valid gNMI port number", serverPortString); + log.error("{} is not a valid port number", serverPortString); return null; } - GnmiClientKey clientKey = - new GnmiClientKey(GNMI_SERVICE_NAME, deviceId, serverAddr, serverPort); + GnmiClientKey clientKey = new GnmiClientKey(deviceId, serverAddr, serverPort); if (!controller.createClient(clientKey)) { log.warn("Unable to create client for {}, aborting operation", deviceId); 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 d1ee1b8a52..c4434601ad 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 @@ -77,7 +77,9 @@ public class GnmiHandshaker extends AbstractGnmiHandlerBehaviour implements Devi return false; } - return getFutureWithDeadline(client.isServiceAvailable(), "getting availability", false); + return getFutureWithDeadline( + client.isServiceAvailable(), + "checking if gNMI service is available", false); } @Override 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 f9d223668d..526c333763 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 @@ -30,13 +30,9 @@ import org.onosproject.net.device.PortDescription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.nio.charset.Charset; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import static gnmi.Gnmi.Path; import static gnmi.Gnmi.PathElem; @@ -50,8 +46,6 @@ public class OpenConfigGnmiDeviceDescriptionDiscovery extends AbstractGnmiHandlerBehaviour implements DeviceDescriptionDiscovery { - private static final int REQUEST_TIMEOUT_SECONDS = 5; - private static final Logger log = LoggerFactory .getLogger(OpenConfigGnmiDeviceDescriptionDiscovery.class); @@ -67,18 +61,12 @@ public class OpenConfigGnmiDeviceDescriptionDiscovery } log.debug("Discovering port details on device {}", handler().data().deviceId()); - GetResponse response; - try { - response = client.get(buildPortStateRequest()) - .get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - log.warn("Unable to discover ports from {}: {}", deviceId, e.getMessage()); - log.debug("{}", e); - return Collections.emptyList(); - } + final GetResponse response = getFutureWithDeadline( + client.get(buildPortStateRequest()), + "getting port details", GetResponse.getDefaultInstance()); - Map ports = Maps.newHashMap(); - Map annotations = Maps.newHashMap(); + final Map ports = Maps.newHashMap(); + final Map annotations = Maps.newHashMap(); // Creates port descriptions with port name and port number response.getNotificationList() @@ -86,19 +74,18 @@ public class OpenConfigGnmiDeviceDescriptionDiscovery .flatMap(notification -> notification.getUpdateList().stream()) .forEach(update -> { // /interfaces/interface[name=ifName]/state/... - String ifName = update.getPath().getElem(1).getKeyMap().get("name"); + final String ifName = update.getPath().getElem(1) + .getKeyMap().get("name"); if (!ports.containsKey(ifName)) { ports.put(ifName, DefaultPortDescription.builder()); annotations.put(ifName, DefaultAnnotations.builder()); } - - - DefaultPortDescription.Builder builder = ports.get(ifName); - DefaultAnnotations.Builder annotationsBuilder = annotations.get(ifName); + final DefaultPortDescription.Builder builder = ports.get(ifName); + final DefaultAnnotations.Builder annotationsBuilder = annotations.get(ifName); parseInterfaceInfo(update, ifName, builder, annotationsBuilder); }); - List portDescriptionList = Lists.newArrayList(); + final List portDescriptionList = Lists.newArrayList(); ports.forEach((key, value) -> { DefaultAnnotations annotation = annotations.get(key).build(); portDescriptionList.add(value.annotations(annotation).build()); @@ -122,7 +109,7 @@ public class OpenConfigGnmiDeviceDescriptionDiscovery /** * Parses the interface information. * - * @param update the update received + * @param update the update received */ private void parseInterfaceInfo(Update update, String ifName, @@ -130,45 +117,32 @@ public class OpenConfigGnmiDeviceDescriptionDiscovery DefaultAnnotations.Builder annotationsBuilder) { - Path path = update.getPath(); - List elems = path.getElemList(); - Gnmi.TypedValue val = update.getVal(); + final Path path = update.getPath(); + final List elems = path.getElemList(); + final Gnmi.TypedValue val = update.getVal(); if (elems.size() == 4) { // /interfaces/interface/state/ifindex // /interfaces/interface/state/oper-status - String pathElemName = elems.get(3).getName(); + final String pathElemName = elems.get(3).getName(); switch (pathElemName) { case "ifindex": // port number builder.withPortNumber(PortNumber.portNumber(val.getUintVal(), ifName)); - break; + return; case "oper-status": builder.isEnabled(parseOperStatus(val.getStringVal())); - break; + return; default: - String valueString = val.toByteString().toString(Charset.defaultCharset()).trim(); - if (!valueString.isEmpty()) { - annotationsBuilder.set(pathElemName, valueString); - } - log.debug("Unknown path: {}", path); break; } - } - if (elems.size() == 5) { + } else if (elems.size() == 5) { // /interfaces/interface/ethernet/config/port-speed - String pathElemName = elems.get(4).getName(); - switch (pathElemName) { - case "port-speed": - builder.portSpeed(parsePortSpeed(val.getStringVal())); - break; - default: - String valueString = val.toByteString().toString(Charset.defaultCharset()).trim(); - if (!valueString.isEmpty()) { - annotationsBuilder.set(pathElemName, valueString); - } - log.debug("Unknown path: {}", path); - break; + final String pathElemName = elems.get(4).getName(); + if (pathElemName.equals("port-speed")) { + builder.portSpeed(parsePortSpeed(val.getStringVal())); + return; } } + log.debug("Unknown path when parsing interface info: {}", path); } private boolean parseOperStatus(String operStatus) { @@ -201,6 +175,7 @@ public class OpenConfigGnmiDeviceDescriptionDiscovery case "SPEED_100GB": return 100000; default: + log.warn("Unrecognized port speed string '{}'", speed); return 1000; } } diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java index 90e7a31cf0..7f9c8c6610 100644 --- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java +++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java @@ -48,9 +48,9 @@ public class AbstractP4RuntimeHandlerBehaviour extends AbstractHandlerBehaviour private static final String DEVICE_REQ_TIMEOUT = "deviceRequestTimeout"; private static final int DEFAULT_DEVICE_REQ_TIMEOUT = 60; - public static final String P4RUNTIME_SERVER_ADDR_KEY = "p4runtime_ip"; - public static final String P4RUNTIME_SERVER_PORT_KEY = "p4runtime_port"; - public static final String P4RUNTIME_DEVICE_ID_KEY = "p4runtime_deviceId"; + private static final String P4RUNTIME_SERVER_ADDR_KEY = "p4runtime_ip"; + private static final String P4RUNTIME_SERVER_PORT_KEY = "p4runtime_port"; + private static final String P4RUNTIME_DEVICE_ID_KEY = "p4runtime_deviceId"; protected final Logger log = LoggerFactory.getLogger(getClass()); @@ -61,7 +61,7 @@ public class AbstractP4RuntimeHandlerBehaviour extends AbstractHandlerBehaviour protected P4RuntimeController controller; protected PiPipeconf pipeconf; protected P4RuntimeClient client; - protected PiTranslationService piTranslationService; + protected PiTranslationService translationService; /** * Initializes this behaviour attributes. Returns true if the operation was @@ -102,7 +102,7 @@ public class AbstractP4RuntimeHandlerBehaviour extends AbstractHandlerBehaviour } pipeconf = piPipeconfService.getPipeconf(pipeconfId).get(); - piTranslationService = handler().get(PiTranslationService.class); + translationService = handler().get(PiTranslationService.class); return true; } @@ -158,8 +158,8 @@ public class AbstractP4RuntimeHandlerBehaviour extends AbstractHandlerBehaviour return null; } - P4RuntimeClientKey clientKey = new - P4RuntimeClientKey(deviceId, serverAddr, serverPort, p4DeviceId); + final P4RuntimeClientKey clientKey = new P4RuntimeClientKey( + deviceId, serverAddr, serverPort, p4DeviceId); if (!controller.createClient(clientKey)) { log.warn("Unable to create client for {}, aborting operation", deviceId); return null; @@ -176,7 +176,7 @@ public class AbstractP4RuntimeHandlerBehaviour extends AbstractHandlerBehaviour * @param defaultVal default value * @return boolean */ - protected boolean driverBoolProperty(String propName, boolean defaultVal) { + boolean driverBoolProperty(String propName, boolean defaultVal) { checkNotNull(propName); if (handler().driver().getProperty(propName) == null) { return defaultVal; diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeActionGroupProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeActionGroupProgrammable.java index 45be79eb52..c20c899724 100644 --- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeActionGroupProgrammable.java +++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeActionGroupProgrammable.java @@ -96,7 +96,7 @@ public class P4RuntimeActionGroupProgrammable groupMirror = this.handler().get(P4RuntimeGroupMirror.class); memberMirror = this.handler().get(P4RuntimeActionProfileMemberMirror.class); groupStore = handler().get(GroupStore.class); - groupTranslator = piTranslationService.groupTranslator(); + groupTranslator = translationService.groupTranslator(); return true; } diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java index 5a233ef40b..693353f1bf 100644 --- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java +++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java @@ -118,7 +118,7 @@ public class P4RuntimeFlowRuleProgrammable pipelineModel = pipeconf.pipelineModel(); tableMirror = handler().get(P4RuntimeTableMirror.class); - translator = piTranslationService.flowRuleTranslator(); + translator = translationService.flowRuleTranslator(); return true; } diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMeterProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMeterProgrammable.java index 39ed84dc4f..f2dff80d9f 100644 --- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMeterProgrammable.java +++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMeterProgrammable.java @@ -74,7 +74,7 @@ public class P4RuntimeMeterProgrammable extends AbstractP4RuntimeHandlerBehaviou return false; } - translator = piTranslationService.meterTranslator(); + translator = translationService.meterTranslator(); meterMirror = handler().get(P4RuntimeMeterMirror.class); pipelineModel = pipeconf.pipelineModel(); return true; diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMulticastGroupProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMulticastGroupProgrammable.java index a5c353897e..ecdda0825e 100644 --- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMulticastGroupProgrammable.java +++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMulticastGroupProgrammable.java @@ -66,7 +66,7 @@ public class P4RuntimeMulticastGroupProgrammable } mcGroupMirror = this.handler().get(P4RuntimeMulticastGroupMirror.class); groupStore = handler().get(GroupStore.class); - mcGroupTranslator = piTranslationService.multicastGroupTranslator(); + mcGroupTranslator = translationService.multicastGroupTranslator(); return true; } diff --git a/drivers/stratum/BUILD b/drivers/stratum/BUILD new file mode 100644 index 0000000000..41db9f1988 --- /dev/null +++ b/drivers/stratum/BUILD @@ -0,0 +1,25 @@ +COMPILE_DEPS = CORE_DEPS + KRYO + JACKSON + [ + "@io_grpc_grpc_java//core", + "//drivers/p4runtime:onos-drivers-p4runtime", + "//drivers/gnmi:onos-drivers-gnmi", + "//pipelines/basic:onos-pipelines-basic", +] + +osgi_jar( + resources = glob(["src/main/resources/**"]), + resources_root = "src/main/resources", + deps = COMPILE_DEPS, +) + +onos_app( + app_name = "org.onosproject.drivers.stratum", + category = "Drivers", + description = "Adds support for Stratum-based devices", + required_apps = [ + "org.onosproject.generaldeviceprovider", + "org.onosproject.drivers.gnmi", + "org.onosproject.drivers.p4runtime", + ], + title = "Stratum Drivers", + url = "http://onosproject.org", +) diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDriversLoader.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDriversLoader.java new file mode 100644 index 0000000000..a68729ad4a --- /dev/null +++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDriversLoader.java @@ -0,0 +1,31 @@ +/* + * 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.stratum; + +import org.onosproject.net.driver.AbstractDriverLoader; +import org.osgi.service.component.annotations.Component; + +/** + * Loader for Stratum Switch device drivers. + */ +@Component(immediate = true) +public class StratumDriversLoader extends AbstractDriverLoader { + + public StratumDriversLoader() { + super("/stratum-drivers.xml"); + } +} diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java new file mode 100644 index 0000000000..4e169a5e08 --- /dev/null +++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java @@ -0,0 +1,135 @@ +/* + * 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.stratum; + +import io.grpc.StatusRuntimeException; +import org.onosproject.drivers.gnmi.GnmiHandshaker; +import org.onosproject.drivers.p4runtime.P4RuntimeHandshaker; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.device.DeviceAgentListener; +import org.onosproject.net.device.DeviceHandshaker; +import org.onosproject.net.driver.AbstractHandlerBehaviour; +import org.onosproject.net.driver.DriverData; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.provider.ProviderId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * Implementation of DeviceHandshaker for Stratum device. + */ +public class StratumHandshaker extends AbstractHandlerBehaviour implements DeviceHandshaker { + + private static final Logger log = LoggerFactory.getLogger(StratumHandshaker.class); + private static final int DEFAULT_DEVICE_REQ_TIMEOUT = 10; + + private P4RuntimeHandshaker p4RuntimeHandshaker; + private GnmiHandshaker gnmiHandshaker; + private DeviceId deviceId; + + public StratumHandshaker() { + p4RuntimeHandshaker = new P4RuntimeHandshaker(); + gnmiHandshaker = new GnmiHandshaker(); + } + + @Override + public void setHandler(DriverHandler handler) { + super.setHandler(handler); + p4RuntimeHandshaker.setHandler(handler); + gnmiHandshaker.setHandler(handler); + } + + @Override + public void setData(DriverData data) { + super.setData(data); + p4RuntimeHandshaker.setData(data); + gnmiHandshaker.setData(data); + deviceId = data.deviceId(); + } + + @Override + public CompletableFuture isReachable() { + return p4RuntimeHandshaker.isReachable() + .thenCombine(gnmiHandshaker.isReachable(), Boolean::logicalAnd); + } + + @Override + public void roleChanged(MastershipRole newRole) { + p4RuntimeHandshaker.roleChanged(newRole); + // gNMI doesn't support mastership handling. + } + + @Override + public MastershipRole getRole() { + return p4RuntimeHandshaker.getRole(); + } + + @Override + public void addDeviceAgentListener(ProviderId providerId, DeviceAgentListener listener) { + p4RuntimeHandshaker.addDeviceAgentListener(providerId, listener); + } + + @Override + public void removeDeviceAgentListener(ProviderId providerId) { + p4RuntimeHandshaker.removeDeviceAgentListener(providerId); + } + + @Override + public CompletableFuture connect() { + return p4RuntimeHandshaker.connect() + .thenCombine(gnmiHandshaker.connect(), Boolean::logicalAnd); + } + + @Override + public boolean isConnected() { + final CompletableFuture p4runtimeConnected = + CompletableFuture.supplyAsync(p4RuntimeHandshaker::isConnected); + final CompletableFuture gnmiConnected = + CompletableFuture.supplyAsync(gnmiHandshaker::isConnected); + + try { + return p4runtimeConnected + .thenCombine(gnmiConnected, Boolean::logicalAnd) + .get(DEFAULT_DEVICE_REQ_TIMEOUT, TimeUnit.SECONDS); + } catch (InterruptedException e) { + log.error("Exception while checking connectivity on {}", data().deviceId()); + } catch (ExecutionException e) { + final Throwable cause = e.getCause(); + if (cause instanceof StatusRuntimeException) { + final StatusRuntimeException grpcError = (StatusRuntimeException) cause; + log.warn("Error while checking connectivity on {}: {}", deviceId, grpcError.getMessage()); + } else { + log.error("Exception while checking connectivity on {}", deviceId, e.getCause()); + } + } catch (TimeoutException e) { + log.error("Operation TIMEOUT while checking connectivity on {}", deviceId); + } + return false; + } + + @Override + public CompletableFuture disconnect() { + return p4RuntimeHandshaker.disconnect() + .thenCombine(gnmiHandshaker.disconnect(), Boolean::logicalAnd); + } +} diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/dummy/StratumDummyPipelineProgrammable.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/dummy/StratumDummyPipelineProgrammable.java new file mode 100644 index 0000000000..e07e3b3672 --- /dev/null +++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/dummy/StratumDummyPipelineProgrammable.java @@ -0,0 +1,44 @@ +/* + * 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.stratum.dummy; + +import org.onosproject.drivers.p4runtime.AbstractP4RuntimePipelineProgrammable; +import org.onosproject.net.behaviour.PiPipelineProgrammable; +import org.onosproject.net.pi.model.PiPipeconf; +import org.onosproject.pipelines.basic.PipeconfLoader; + +import java.nio.ByteBuffer; +import java.util.Optional; + +/** + * Implementation of the PiPipelineProgrammable behavior for Dummy Stratum Switch. + */ +public class StratumDummyPipelineProgrammable + extends AbstractP4RuntimePipelineProgrammable + implements PiPipelineProgrammable { + + @Override + public ByteBuffer createDeviceDataBuffer(PiPipeconf pipeconf) { + // No pipeline binary needed + return ByteBuffer.allocate(1); + } + + @Override + public Optional getDefaultPipeconf() { + return Optional.of(PipeconfLoader.BASIC_PIPECONF); + } +} diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/dummy/package-info.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/dummy/package-info.java new file mode 100644 index 0000000000..7633706b4e --- /dev/null +++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/dummy/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Behaviours for Dummy Stratum Device. + */ + +package org.onosproject.drivers.stratum.dummy; diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/package-info.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/package-info.java new file mode 100644 index 0000000000..145022a557 --- /dev/null +++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/package-info.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** + * Driver for Stratum devices. + */ +package org.onosproject.drivers.stratum; diff --git a/drivers/stratum/src/main/resources/stratum-drivers.xml b/drivers/stratum/src/main/resources/stratum-drivers.xml new file mode 100644 index 0000000000..83fea1d629 --- /dev/null +++ b/drivers/stratum/src/main/resources/stratum-drivers.xml @@ -0,0 +1,32 @@ + + + + + + + + + + true + true + + + diff --git a/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClient.java b/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClient.java index 242bc94b0e..5beb238e58 100644 --- a/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClient.java +++ b/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClient.java @@ -17,10 +17,9 @@ package org.onosproject.gnmi.api; import com.google.common.annotations.Beta; - import gnmi.Gnmi.CapabilityResponse; -import gnmi.Gnmi.GetResponse; import gnmi.Gnmi.GetRequest; +import gnmi.Gnmi.GetResponse; import gnmi.Gnmi.SetRequest; import gnmi.Gnmi.SetResponse; import org.onosproject.grpc.api.GrpcClient; @@ -34,15 +33,14 @@ import java.util.concurrent.CompletableFuture; public interface GnmiClient extends GrpcClient { /** - * Gets capability from a target. This allows device driver behavior - * to validate the service version and models which gNMI device supported. + * Gets capability from a target. * * @return the capability response */ CompletableFuture capability(); /** - * Retrieve a snapshot of data from the device. + * Retrieves a snapshot of data from the device. * * @param request the get request * @return the snapshot of data from the device diff --git a/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClientKey.java b/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClientKey.java index 26ce1136f0..bc18b9aaab 100644 --- a/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClientKey.java +++ b/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClientKey.java @@ -26,15 +26,16 @@ import org.onosproject.net.DeviceId; @Beta public class GnmiClientKey extends GrpcClientKey { + private static final String GNMI = "gnmi"; + /** * Creates a new gNMI client key. * - * @param serviceName gNMI service name of the client * @param deviceId ONOS device ID * @param serverAddr gNMI server address * @param serverPort gNMI server port */ - public GnmiClientKey(String serviceName, DeviceId deviceId, String serverAddr, int serverPort) { - super(serviceName, deviceId, serverAddr, serverPort); + public GnmiClientKey(DeviceId deviceId, String serverAddr, int serverPort) { + super(GNMI, deviceId, serverAddr, serverPort); } } diff --git a/protocols/gnmi/ctl/src/main/java/org/onosproject/gnmi/ctl/GnmiClientImpl.java b/protocols/gnmi/ctl/src/main/java/org/onosproject/gnmi/ctl/GnmiClientImpl.java index b8179a950d..22b226b185 100644 --- a/protocols/gnmi/ctl/src/main/java/org/onosproject/gnmi/ctl/GnmiClientImpl.java +++ b/protocols/gnmi/ctl/src/main/java/org/onosproject/gnmi/ctl/GnmiClientImpl.java @@ -27,10 +27,10 @@ import gnmi.gNMIGrpc; import io.grpc.ManagedChannel; import io.grpc.Status; import io.grpc.StatusRuntimeException; +import org.onosproject.gnmi.api.GnmiClient; import org.onosproject.gnmi.api.GnmiClientKey; import org.onosproject.grpc.ctl.AbstractGrpcClient; import org.slf4j.Logger; -import org.onosproject.gnmi.api.GnmiClient; import java.util.concurrent.CompletableFuture; @@ -46,8 +46,8 @@ public class GnmiClientImpl extends AbstractGrpcClient implements GnmiClient { private final Logger log = getLogger(getClass()); private final gNMIGrpc.gNMIBlockingStub blockingStub; - public GnmiClientImpl(GnmiClientKey clientKey, ManagedChannel managedChannel) { - super(clientKey, managedChannel); + GnmiClientImpl(GnmiClientKey clientKey, ManagedChannel managedChannel) { + super(clientKey); this.blockingStub = gNMIGrpc.newBlockingStub(managedChannel); } @@ -101,8 +101,7 @@ public class GnmiClientImpl extends AbstractGrpcClient implements GnmiClient { private boolean doServiceAvailable() { try { - blockingStub.get(DUMMY_REQUEST); - return true; + return blockingStub.get(DUMMY_REQUEST) != null; } catch (StatusRuntimeException e) { // This gRPC call should throw INVALID_ARGUMENT status exception // since "/onos-gnmi-test" path does not exists in any config model diff --git a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcClientController.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcClientController.java index 2e3ea5d0fd..3cdbcd1395 100644 --- a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcClientController.java +++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcClientController.java @@ -20,8 +20,8 @@ import com.google.common.annotations.Beta; import org.onosproject.net.DeviceId; /** - * Abstraction of a gRPC controller which controls specific gRPC - * client {@link C} with specific client key {@link K}. + * Abstraction of a gRPC controller which controls specific gRPC client {@link + * C} with specific client key {@link K}. * * @param the gRPC client key * @param the gRPC client type @@ -30,19 +30,19 @@ import org.onosproject.net.DeviceId; public interface GrpcClientController { /** - * Instantiates a new client to operate on a gRPC server identified by - * the given information. As a result of this method, a client can be later + * Instantiates a new client to operate on a gRPC server identified by the + * given information. As a result of this method, a client can be later * obtained by invoking {@link #getClient(DeviceId)}. - * - * Only one client can exist for the same device ID. Calls to this method are - * idempotent fot the same client key, i.e. returns true - * if such client already exists but a new one is not created. - * If there exists a client with same device ID but different address and port, - * removes old one and recreate new one. + *

+ * Only one client can exist for the same device ID. Calls to this method + * are idempotent fot the same client key, i.e. returns true if such client + * already exists but a new one is not created. If there exists a client + * with same device ID but different address and port, removes old one and + * recreate new one. * * @param clientKey the client key - * @return true if the client was created and the channel to the server is open; - * false otherwise + * @return true if the client was created and the channel to the server is + * open; false otherwise */ boolean createClient(K clientKey); @@ -55,8 +55,8 @@ public interface GrpcClientController CompletableFuture supplyWithExecutor( + private CompletableFuture supplyWithExecutor( Supplier supplier, String opDescription, Executor executor) { return CompletableFuture.supplyAsync(() -> { // TODO: explore a more relaxed locking strategy. diff --git a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/AbstractGrpcClientController.java b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/AbstractGrpcClientController.java index 36e453c2d6..bf2bbf1ae6 100644 --- a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/AbstractGrpcClientController.java +++ b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/AbstractGrpcClientController.java @@ -21,7 +21,6 @@ import com.google.common.util.concurrent.Striped; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.netty.NettyChannelBuilder; - import org.onosproject.event.AbstractListenerManager; import org.onosproject.event.Event; import org.onosproject.event.EventListener; @@ -152,7 +151,7 @@ public abstract class AbstractGrpcClientController return withDeviceLock(() -> doGetClient(deviceId), deviceId); } - protected C doGetClient(DeviceId deviceId) { + private C doGetClient(DeviceId deviceId) { if (!clientKeys.containsKey(deviceId)) { return null; } @@ -183,7 +182,7 @@ public abstract class AbstractGrpcClientController return withDeviceLock(() -> doIsReachable(deviceId), deviceId); } - protected boolean doIsReachable(DeviceId deviceId) { + private boolean doIsReachable(DeviceId deviceId) { // Default behaviour checks only the gRPC channel, should // check according to different gRPC service if (!clientKeys.containsKey(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 53f7668841..d5080ae251 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 @@ -138,7 +138,7 @@ final class P4RuntimeClientImpl extends AbstractGrpcClient implements P4RuntimeC P4RuntimeClientImpl(P4RuntimeClientKey clientKey, ManagedChannel channel, P4RuntimeControllerImpl controller) { - super(clientKey, channel); + super(clientKey); this.p4DeviceId = clientKey.p4DeviceId(); this.controller = controller; 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 4374089ef5..3ca56ee664 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 @@ -106,7 +106,12 @@ import static java.util.concurrent.Executors.newScheduledThreadPool; import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; import static org.onlab.util.Tools.groupedThreads; import static org.onosproject.net.device.DeviceEvent.Type; -import static org.onosproject.provider.general.device.impl.OsgiPropertyConstants.*; +import static org.onosproject.provider.general.device.impl.OsgiPropertyConstants.OP_TIMEOUT_SHORT; +import static org.onosproject.provider.general.device.impl.OsgiPropertyConstants.OP_TIMEOUT_SHORT_DEFAULT; +import static org.onosproject.provider.general.device.impl.OsgiPropertyConstants.PROBE_FREQUENCY; +import static org.onosproject.provider.general.device.impl.OsgiPropertyConstants.PROBE_FREQUENCY_DEFAULT; +import static org.onosproject.provider.general.device.impl.OsgiPropertyConstants.STATS_POLL_FREQUENCY; +import static org.onosproject.provider.general.device.impl.OsgiPropertyConstants.STATS_POLL_FREQUENCY_DEFAULT; import static org.slf4j.LoggerFactory.getLogger; /** @@ -498,13 +503,16 @@ public class GeneralDeviceProvider extends AbstractProvider // Get one from driver or forge. final DeviceDescriptionDiscovery deviceDiscovery = getBehaviour( deviceId, DeviceDescriptionDiscovery.class); - if (deviceDiscovery != null) { - // Enforce defaultAvailable flag over the one obtained from driver. - final DeviceDescription d = deviceDiscovery.discoverDeviceDetails(); - return new DefaultDeviceDescription(d, defaultAvailable, d.annotations()); - } else { + if (deviceDiscovery == null) { return forgeDeviceDescription(deviceId, defaultAvailable); } + + final DeviceDescription d = deviceDiscovery.discoverDeviceDetails(); + if (d == null) { + return forgeDeviceDescription(deviceId, defaultAvailable); + } + // Enforce defaultAvailable flag over the one obtained from driver. + return new DefaultDeviceDescription(d, defaultAvailable, d.annotations()); } private List getPortDetails(DeviceId deviceId) { diff --git a/tools/build/bazel/modules.bzl b/tools/build/bazel/modules.bzl index 330d9fd404..12a54e9d0f 100644 --- a/tools/build/bazel/modules.bzl +++ b/tools/build/bazel/modules.bzl @@ -109,6 +109,7 @@ ONOS_DRIVERS = [ "//drivers/polatis/netconf:onos-drivers-polatis-netconf-oar", "//drivers/polatis/openflow:onos-drivers-polatis-openflow-oar", "//drivers/odtn-driver:onos-drivers-odtn-driver-oar", + "//drivers/stratum:onos-drivers-stratum-oar", ] ONOS_PROVIDERS = [