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
This commit is contained in:
Yi Tseng 2018-10-31 15:34:30 -07:00 committed by Carmelo Cascone
parent 597315d1b6
commit d771648025
25 changed files with 410 additions and 126 deletions

View File

@ -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",

View File

@ -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;

View File

@ -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

View File

@ -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<String, DefaultPortDescription.Builder> ports = Maps.newHashMap();
Map<String, DefaultAnnotations.Builder> annotations = Maps.newHashMap();
final Map<String, DefaultPortDescription.Builder> ports = Maps.newHashMap();
final Map<String, DefaultAnnotations.Builder> 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<PortDescription> portDescriptionList = Lists.newArrayList();
final List<PortDescription> 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<PathElem> elems = path.getElemList();
Gnmi.TypedValue val = update.getVal();
final Path path = update.getPath();
final List<PathElem> 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;
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -118,7 +118,7 @@ public class P4RuntimeFlowRuleProgrammable
pipelineModel = pipeconf.pipelineModel();
tableMirror = handler().get(P4RuntimeTableMirror.class);
translator = piTranslationService.flowRuleTranslator();
translator = translationService.flowRuleTranslator();
return true;
}

View File

@ -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;

View File

@ -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;
}

25
drivers/stratum/BUILD Normal file
View File

@ -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",
)

View File

@ -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");
}
}

View File

@ -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<Boolean> 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<Boolean> connect() {
return p4RuntimeHandshaker.connect()
.thenCombine(gnmiHandshaker.connect(), Boolean::logicalAnd);
}
@Override
public boolean isConnected() {
final CompletableFuture<Boolean> p4runtimeConnected =
CompletableFuture.supplyAsync(p4RuntimeHandshaker::isConnected);
final CompletableFuture<Boolean> 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<Boolean> disconnect() {
return p4RuntimeHandshaker.disconnect()
.thenCombine(gnmiHandshaker.disconnect(), Boolean::logicalAnd);
}
}

View File

@ -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<PiPipeconf> getDefaultPipeconf() {
return Optional.of(PipeconfLoader.BASIC_PIPECONF);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2017-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.
-->
<drivers>
<driver name="stratum" manufacturer="Open Networking Foundation"
hwVersion="master" swVersion="Stratum" extends="p4runtime,gnmi">
<behaviour api="org.onosproject.net.device.DeviceHandshaker"
impl="org.onosproject.drivers.stratum.StratumHandshaker"/>
</driver>
<driver name="stratum-dummy" manufacturer="Open Networking Foundation"
hwVersion="Dummy" swVersion="Stratum" extends="stratum">
<behaviour api="org.onosproject.net.behaviour.PiPipelineProgrammable"
impl="org.onosproject.drivers.stratum.dummy.StratumDummyPipelineProgrammable"/>
<property name="tableReadFromMirror">true</property>
<property name="actionGroupReadFromMirror">true</property>
</driver>
</drivers>

View File

@ -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<CapabilityResponse> 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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 <K> the gRPC client key
* @param <C> the gRPC client type
@ -30,19 +30,19 @@ import org.onosproject.net.DeviceId;
public interface GrpcClientController<K extends GrpcClientKey, C extends GrpcClient> {
/**
* 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.
* <p>
* 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<K extends GrpcClientKey, C extends GrpcCli
C getClient(DeviceId deviceId);
/**
* Removes the gRPC client for the given device. If no client
* exists for the given device, the result is a no-op.
* Removes the gRPC client for the given device. If no client exists for the
* given device, the result is a no-op.
*
* @param deviceId the device identifier
*/
@ -64,15 +64,15 @@ public interface GrpcClientController<K extends GrpcClientKey, C extends GrpcCli
/**
* Check reachability of the gRPC server running on the given device.
* Reachability can be tested only if a client is previously created
* using {@link #createClient(GrpcClientKey)}.
* Note that this only checks the reachability instead of checking service
* availability, different gRPC client checks service availability with
* Reachability can be tested only if a client is previously created using
* {@link #createClient(GrpcClientKey)}. Note that this only checks the
* reachability instead of checking service availability, different
* service-specific gRPC clients might check service availability in a
* different way.
*
* @param deviceId the device identifier
* @return true if client was created and is able to contact the gNMI server;
* false otherwise
* @return true if client was created and is able to contact the gNMI
* server; false otherwise
*/
boolean isReachable(DeviceId deviceId);
}

View File

@ -17,7 +17,6 @@
package org.onosproject.grpc.ctl;
import io.grpc.Context;
import io.grpc.ManagedChannel;
import io.grpc.StatusRuntimeException;
import org.onlab.util.SharedExecutors;
import org.onosproject.grpc.api.GrpcClient;
@ -25,7 +24,6 @@ import org.onosproject.grpc.api.GrpcClientKey;
import org.onosproject.net.DeviceId;
import org.slf4j.Logger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@ -45,26 +43,24 @@ import static org.slf4j.LoggerFactory.getLogger;
public abstract class AbstractGrpcClient implements GrpcClient {
// Timeout in seconds to obtain the request lock.
protected static final int LOCK_TIMEOUT = 60;
private static final int LOCK_TIMEOUT = 60;
private static final int DEFAULT_THREAD_POOL_SIZE = 10;
protected final Logger log = getLogger(getClass());
protected final Lock requestLock = new ReentrantLock();
protected final Context.CancellableContext cancellableContext =
private final Lock requestLock = new ReentrantLock();
private final Context.CancellableContext cancellableContext =
Context.current().withCancellation();
private final Executor contextExecutor;
protected final ExecutorService executorService;
protected final Executor contextExecutor;
protected final DeviceId deviceId;
protected ManagedChannel channel;
protected DeviceId deviceId;
protected AbstractGrpcClient(GrpcClientKey clientKey, ManagedChannel channel) {
protected AbstractGrpcClient(GrpcClientKey clientKey) {
this.deviceId = clientKey.deviceId();
this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE, groupedThreads(
"onos-grpc-" + clientKey.serviceName() + "-client-" + deviceId.toString(), "%d"));
this.contextExecutor = this.cancellableContext.fixedContextExecutor(executorService);
this.channel = channel;
}
@Override
@ -112,7 +108,7 @@ public abstract class AbstractGrpcClient implements GrpcClient {
* @param executor the executor to execute this supplier
* @return CompletableFuture includes the result of supplier
*/
protected <U> CompletableFuture<U> supplyWithExecutor(
private <U> CompletableFuture<U> supplyWithExecutor(
Supplier<U> supplier, String opDescription, Executor executor) {
return CompletableFuture.supplyAsync(() -> {
// TODO: explore a more relaxed locking strategy.

View File

@ -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)) {

View File

@ -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;

View File

@ -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<PortDescription> getPortDetails(DeviceId deviceId) {

View File

@ -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 = [