mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 12:16:13 +02:00
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:
parent
597315d1b6
commit
d771648025
@ -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",
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ public class P4RuntimeFlowRuleProgrammable
|
||||
|
||||
pipelineModel = pipeconf.pipelineModel();
|
||||
tableMirror = handler().get(P4RuntimeTableMirror.class);
|
||||
translator = piTranslationService.flowRuleTranslator();
|
||||
translator = translationService.flowRuleTranslator();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
25
drivers/stratum/BUILD
Normal 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",
|
||||
)
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
@ -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;
|
||||
32
drivers/stratum/src/main/resources/stratum-drivers.xml
Normal file
32
drivers/stratum/src/main/resources/stratum-drivers.xml
Normal 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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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 = [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user