[ONOS-6465] gRPC Protocol and controller
Change-Id: I0ae997f234ce95a78db2db1917f2cbbe3696ccfd
diff --git a/drivers/bmv2/BUCK b/drivers/bmv2/BUCK
index 95b2d44..33d4d66 100644
--- a/drivers/bmv2/BUCK
+++ b/drivers/bmv2/BUCK
@@ -1,5 +1,8 @@
COMPILE_DEPS = [
'//lib:CORE_DEPS',
+ '//protocols/grpc/api:onos-protocols-grpc-api',
+ '//lib:grpc-core-1.3.0',
+ '//lib:grpc-stub-1.3.0'
]
TEST_DEPS = [
@@ -9,9 +12,12 @@
BUNDLES = [
':onos-drivers-bmv2',
+ '//lib:grpc-core-1.3.0',
+ '//lib:grpc-stub-1.3.0',
+ '//protocols/grpc/api:onos-protocols-grpc-api',
]
-osgi_jar_with_tests (
+osgi_jar_with_tests(
deps = COMPILE_DEPS,
test_deps = TEST_DEPS,
resources_root = 'src/main/resources',
@@ -20,10 +26,12 @@
onos_app (
app_name = 'org.onosproject.drivers.bmv2',
- title = 'bmv2 Device Drivers',
+ title = 'BMv2 Device Drivers',
category = 'Drivers',
url = 'http://onosproject.org',
description = 'ONOS BMv2 Device Drivers application.',
included_bundles = BUNDLES,
- required_apps = [ 'org.onosproject.generaldeviceprovider' ],
+ required_apps = [
+ 'org.onosproject.generaldeviceprovider'
+ ],
)
diff --git a/drivers/bmv2/pom.xml b/drivers/bmv2/pom.xml
index f99f555..8227337 100644
--- a/drivers/bmv2/pom.xml
+++ b/drivers/bmv2/pom.xml
@@ -27,8 +27,15 @@
<artifactId>onos-drivers-bmv2</artifactId>
<packaging>bundle</packaging>
-
+
<description>BMv2 device drivers</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-grpc-protocol-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
<properties>
<onos.app.name>org.onosproject.drivers.bmv2</onos.app.name>
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Handshaker.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Handshaker.java
index 06f9c9e..8774c09 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Handshaker.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Handshaker.java
@@ -16,6 +16,11 @@
package org.onosproject.drivers.bmv2;
+import org.onosproject.grpc.api.GrpcChannelId;
+import org.onosproject.grpc.api.GrpcController;
+import org.onosproject.grpc.api.GrpcServiceId;
+import org.onosproject.grpc.api.GrpcStreamObserverId;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.device.DeviceHandshaker;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
@@ -29,7 +34,7 @@
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Implementation of the DeviceHandshaker for the bmv2 softswitch.
+ * Implementation of the DeviceHandshaker for the BMv2 softswitch.
*/
//TODO consider abstract class with empty connect method and
//the implementation into a protected one for reusability.
@@ -41,6 +46,9 @@
@Override
public CompletableFuture<Boolean> connect() {
+ GrpcController controller = handler().get(GrpcController.class);
+ DeviceId deviceId = handler().data().deviceId();
+
CompletableFuture<Boolean> result = new CompletableFuture<>();
DeviceKeyService deviceKeyService = handler().get(DeviceKeyService.class);
DriverData data = data();
@@ -54,6 +62,13 @@
deviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(data.value("gnmi_key")))
.asUsernamePassword().username());
result.complete(true);
+
+ //we know we need packet in so we register the observer.
+ GrpcChannelId channelId = GrpcChannelId.of(deviceId, "bmv2");
+ GrpcServiceId serviceId = GrpcServiceId.of(channelId, "p4runtime");
+ GrpcStreamObserverId observerId = GrpcStreamObserverId.of(serviceId,
+ Bmv2PacketProgrammable.class.getSimpleName());
+ controller.addObserver(observerId, new Bmv2PacketInObserverHandler());
return result;
}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketInObserverHandler.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketInObserverHandler.java
new file mode 100644
index 0000000..3b9e145
--- /dev/null
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketInObserverHandler.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.bmv2;
+
+import io.grpc.ManagedChannel;
+import io.grpc.stub.StreamObserver;
+import org.onosproject.grpc.api.GrpcObserverHandler;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Sample Implementation of a PacketInObserverHandler.
+ * TODO refactor and actually use.
+ */
+public class Bmv2PacketInObserverHandler implements GrpcObserverHandler {
+
+ private final Logger log = getLogger(getClass());
+
+ //private final AbstractStub asyncStub;
+
+ //FIXME put at object due to p4Runtime compilation problems to be fixed.
+ private StreamObserver<Object> requestStreamObserver;
+
+ @Override
+ public void bindObserver(ManagedChannel channel) {
+
+ //asyncStub = ProtoGeneratedClass.newStub(channel);
+
+ //reqeustStreamObserver = asyncStub.MethodName(new PacketInObserver());
+
+ }
+
+ @Override
+ public Optional<StreamObserver> requestStreamObserver() {
+ return Optional.of(requestStreamObserver);
+ }
+
+ @Override
+ public void removeObserver() {
+ //this should complete the two way streaming
+ requestStreamObserver.onCompleted();
+ }
+
+ private class PacketInObserver implements StreamObserver<Object> {
+
+ @Override
+ public void onNext(Object o) {
+ log.info("onNext: {}", o.toString());
+
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+
+ }
+
+ @Override
+ public void onCompleted() {
+
+ }
+ }
+}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java
new file mode 100644
index 0000000..4b76067
--- /dev/null
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.bmv2;
+
+import io.grpc.stub.StreamObserver;
+import org.onosproject.grpc.api.GrpcChannelId;
+import org.onosproject.grpc.api.GrpcController;
+import org.onosproject.grpc.api.GrpcObserverHandler;
+import org.onosproject.grpc.api.GrpcServiceId;
+import org.onosproject.grpc.api.GrpcStreamObserverId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketProgrammable;
+
+import java.util.Optional;
+
+/**
+ * Packet Programmable behaviour for BMv2 devices.
+ */
+public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable {
+ @Override
+ public void emit(OutboundPacket packet) {
+ DriverHandler handler = handler();
+ GrpcController controller = handler.get(GrpcController.class);
+ DeviceId deviceId = handler.data().deviceId();
+ GrpcChannelId channelId = GrpcChannelId.of(deviceId, "bmv2");
+ GrpcServiceId serviceId = GrpcServiceId.of(channelId, "p4runtime");
+ GrpcStreamObserverId observerId = GrpcStreamObserverId.of(serviceId,
+ this.getClass().getSimpleName());
+ Optional<GrpcObserverHandler> manager = controller.getObserverManager(observerId);
+ if (!manager.isPresent()) {
+ //this is the first time the behaviour is called
+ controller.addObserver(observerId, new Bmv2PacketInObserverHandler());
+ }
+ //other already registered the observer for us.
+ Optional<StreamObserver> observer = manager.get().requestStreamObserver();
+ observer.ifPresent(objectStreamObserver -> objectStreamObserver.onNext(packet));
+ }
+}
diff --git a/drivers/bmv2/src/main/resources/bmv2-drivers.xml b/drivers/bmv2/src/main/resources/bmv2-drivers.xml
index 7f0d3f2..bc343e0 100644
--- a/drivers/bmv2/src/main/resources/bmv2-drivers.xml
+++ b/drivers/bmv2/src/main/resources/bmv2-drivers.xml
@@ -15,9 +15,11 @@
~ limitations under the License.
-->
<drivers>
- <driver name="bmv2" manufacturer="barefoot" hwVersion="1.0.0" swVersion="1.0.0">
+ <driver name="bmv2" manufacturer="p4.org" hwVersion="master" swVersion="master">
<behaviour api="org.onosproject.net.device.DeviceHandshaker"
impl="org.onosproject.drivers.bmv2.Bmv2Handshaker"/>
+ <behaviour api="org.onosproject.net.packet.PacketProgrammable"
+ impl="org.onosproject.drivers.bmv2.Bmv2PacketProgrammable"/>
</driver>
</drivers>
diff --git a/drivers/p4runtime/proto/BUCK b/drivers/p4runtime/proto/BUCK
new file mode 100644
index 0000000..2c8ebdd
--- /dev/null
+++ b/drivers/p4runtime/proto/BUCK
@@ -0,0 +1,163 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+]
+
+
+PI_BASEURL = 'https://github.com/p4lang/PI.git'
+PROTOBUF_BASEURL = 'https://github.com/google/protobuf.git'
+
+PROTOC_VER = '3.3.0'
+GRPC_VER = '1.3.0'
+
+PROTOC_EXE_BASEURL = 'http://central.maven.org/maven2/com/google/protobuf/protoc/'
+GRPC_JAVA_BASEURL = 'http://central.maven.org/maven2/io/grpc/protoc-gen-grpc-java/'
+
+
+PROTOC_SHA1S = {
+ 'protoc-3.3.0-linux-x86_64.exe':'e6a95fc7477c602cc402ed976d3edbd82c841879',
+ 'protoc-3.3.0-osx-x86_64.exe':'3070e439f9557bb72fb04df631f29d7556c9029c'
+}
+
+GRPC_JAVA_SHA1S = {
+ 'protoc-gen-grpc-java-1.3.0-linux-x86_64.exe':'44a0fa3e6074852ea84f93d258233b3f4f6d9e53',
+ 'protoc-gen-grpc-java-1.3.0-osx-x86_64.exe':'61a1b81b9f0af7d0900c314a4201972b52fb5f12'
+}
+
+
+GRPC_DEPS = [
+ '//lib:grpc-core-' + GRPC_VER,
+ '//lib:grpc-protobuf-' + GRPC_VER,
+ '//lib:grpc-stub-' + GRPC_VER,
+ '//lib:grpc-netty-' + GRPC_VER,
+ '//lib:grpc-auth-' + GRPC_VER,
+ '//lib:protobuf-java-' + PROTOC_VER,
+]
+
+
+def get_arch():
+ import platform
+ os_name = platform.system().lower()
+ if os_name == 'darwin':
+ os_name = 'osx'
+ arch = '%s-%s' % (os_name, platform.machine())
+ return arch
+
+# TODO: defs to download prebuilt protoc and grpc java plugin should visible by other BUCK files.
+
+def prebuilt_protoc():
+ fname = 'protoc-%s-%s.exe' % (PROTOC_VER, get_arch())
+ if fname not in PROTOC_SHA1S:
+ raise Exception('Cannot download %s, architecture not supported' % fname)
+ remote_file(
+ name = 'protoc-binary',
+ out = 'protoc.binary',
+ url = PROTOC_EXE_BASEURL + PROTOC_VER + '/' + fname,
+ sha1 = PROTOC_SHA1S[fname],
+ )
+ genrule (
+ name = 'protoc-exe',
+ srcs = [ ':protoc-binary' ],
+ bash = 'cp $(location :protoc-binary) $OUT && chmod +x $OUT',
+ executable = True,
+ out = 'protoc.exe'
+ )
+
+
+def prebuilt_protoc_java_plugin():
+ arch = get_arch()
+ fname = 'protoc-gen-grpc-java-%s-%s.exe' % (GRPC_VER, get_arch())
+ if fname not in GRPC_JAVA_SHA1S:
+ raise Exception('Cannot download %s, architecture not supported' % fname)
+ remote_file(
+ name = 'grpc-java-binary',
+ out = 'grpc-java.binary',
+ url = GRPC_JAVA_BASEURL + GRPC_VER + '/' + fname,
+ sha1 = GRPC_JAVA_SHA1S[fname],
+ )
+ genrule (
+ name = 'grpc-java-exe',
+ srcs = [ ':grpc-java-binary' ],
+ bash = 'cp $(location :grpc-java-binary) $OUT && chmod +x $OUT',
+ executable = True,
+ out = 'grpc-java.exe'
+ )
+
+prebuilt_protoc()
+prebuilt_protoc_java_plugin()
+
+genrule (
+ name = 'p4lang-pi-repo',
+ # FIXME: should download a specific commit id/tag of p4runtime, right now we get the master.
+ bash = 'git clone --quiet ' + PI_BASEURL + ' $OUT > /dev/null && cd $OUT && '
+ + 'git submodule update --quiet --init --recursive > /dev/null',
+ out = 'repo',
+)
+
+genrule (
+ name = 'protoc-repo',
+ bash = 'git clone --quiet ' + PROTOBUF_BASEURL + ' $OUT > /dev/null && cd $OUT && '
+ + 'git checkout --quiet -b x tags/v' + PROTOC_VER + ' > /dev/null',
+ out = 'repo',
+)
+
+def protoc_gen(
+ name,
+ proto_file,
+ out_pkg,
+ ):
+ genrule(
+ name = name + '-gen',
+ cmd = '$(exe :protoc-exe) --plugin=protoc-gen-grpc-java=$(location :grpc-java-exe) '
+ + '--grpc-java_out=$SRCDIR/../' + name + '-gen '
+ + '--java_out=$SRCDIR/../' + name + '-gen '
+ + '-I$(location :p4lang-pi-repo)/proto '
+ + '-I$(location :protoc-repo)/src '
+ + proto_file,
+ out = out_pkg,
+ )
+ zip_file(
+ name = name,
+ out = name + '.src.zip',
+ srcs = [':'+name+'-gen']
+ )
+
+# Wondering which .proto files to build? Check p4runtime's Makefile:
+# https://github.com/p4lang/PI/blob/master/proto/Makefile.am
+protoc_gen(
+ name = 'p4runtime',
+ proto_file = '$(location :p4lang-pi-repo)/proto/p4/p4runtime.proto',
+ out_pkg = 'p4',
+)
+protoc_gen(
+ name = 'p4info',
+ proto_file = '$(location :p4lang-pi-repo)/proto/p4/config/p4info.proto',
+ out_pkg = 'p4',
+)
+protoc_gen(
+ name = 'google-rpc-status',
+ proto_file = '$(location :p4lang-pi-repo)/proto/google/rpc/status.proto',
+ out_pkg = 'com',
+)
+protoc_gen(
+ name = 'google-rpc-code',
+ proto_file = '$(location :p4lang-pi-repo)/proto/google/rpc/code.proto',
+ out_pkg = 'com',
+)
+protoc_gen(
+ name = 'p4config',
+ proto_file = '$(location :p4lang-pi-repo)/proto/p4/tmp/p4config.proto',
+ out_pkg = 'p4',
+)
+
+
+osgi_jar(
+ srcs = [':p4runtime', ':p4info', ':google-rpc-status', ':google-rpc-code', ':p4config'],
+ deps = COMPILE_DEPS + GRPC_DEPS,
+ do_javadocs = False,
+ do_checkstyle = False
+)
+
+
+project_config(
+ src_target = ':onos-drivers-p4runtime-proto'
+)
\ No newline at end of file
diff --git a/modules.defs b/modules.defs
index 9aa0cbe..d52b2e4 100644
--- a/modules.defs
+++ b/modules.defs
@@ -58,6 +58,8 @@
'//protocols/tl1/ctl:onos-protocols-tl1-ctl',
'//protocols/restconf/client/api:onos-protocols-restconf-client-api',
'//protocols/restconf/client/ctl:onos-protocols-restconf-client-ctl',
+ '//protocols/grpc/api:onos-protocols-grpc-api',
+ '//protocols/grpc/ctl:onos-protocols-grpc-ctl',
'//drivers/utilities:onos-drivers-utilities',
diff --git a/protocols/grpc/api/BUCK b/protocols/grpc/api/BUCK
new file mode 100644
index 0000000..66efde3
--- /dev/null
+++ b/protocols/grpc/api/BUCK
@@ -0,0 +1,12 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+ '//lib:grpc-core-1.3.0',
+ '//lib:grpc-protobuf-1.3.0',
+ '//lib:grpc-stub-1.3.0',
+ '//lib:grpc-netty-1.3.0',
+ '//lib:grpc-auth-1.3.0',
+]
+
+osgi_jar_with_tests (
+ deps = COMPILE_DEPS,
+)
diff --git a/protocols/grpc/api/pom.xml b/protocols/grpc/api/pom.xml
new file mode 100644
index 0000000..4841ca3
--- /dev/null
+++ b/protocols/grpc/api/pom.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>onos-grpc-protocol</artifactId>
+ <groupId>org.onosproject</groupId>
+ <version>1.11.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <packaging>bundle</packaging>
+
+ <artifactId>onos-grpc-protocol-api</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-core-serializers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-stub</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcChannelId.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcChannelId.java
new file mode 100644
index 0000000..c1fdbf1
--- /dev/null
+++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcChannelId.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.grpc.api;
+
+import com.google.common.annotations.Beta;
+import org.onlab.util.Identifier;
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * gRPCChannel identifier suitable as an external key.
+ * <p>
+ * This class is immutable.</p>
+ */
+@Beta
+public final class GrpcChannelId extends Identifier<String> {
+
+ private final DeviceId deviceId;
+
+ private final String channelName;
+
+ /**
+ * Instantiates a new GrpcChannel id.
+ *
+ * @param deviceId the device id
+ * @param channelName the name of the channel
+ */
+ private GrpcChannelId(DeviceId deviceId, String channelName) {
+ super(deviceId.toString() + ":" + channelName);
+ checkNotNull(deviceId, "device id must not be null");
+ checkNotNull(channelName, "channel name must not be null");
+ checkArgument(!channelName.isEmpty(), "channel name must not be empty");
+ this.deviceId = deviceId;
+ this.channelName = channelName;
+ }
+
+ /**
+ * Returns the deviceId of the device that uses this channel.
+ *
+ * @return the device Id
+ */
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ /**
+ * Returns the channel name.
+ *
+ * @return the channel name
+ */
+ public String channelName() {
+ return channelName;
+ }
+
+ /**
+ * Creates a grpc channel identifier from the specified device id and name provided.
+ *
+ * @param id device id
+ * @param channelName name of the channel
+ * @return channel name
+ */
+ public static GrpcChannelId of(DeviceId id, String channelName) {
+ return new GrpcChannelId(id, channelName);
+ }
+}
diff --git a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcController.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcController.java
new file mode 100644
index 0000000..f1e279a
--- /dev/null
+++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcController.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.grpc.api;
+
+import com.google.common.annotations.Beta;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import org.onosproject.net.DeviceId;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Abstraction of a gRPC controller. Serves as a one stop shop for obtaining
+ * gRCP ManagedChannels to interact with devices and (un)register observers on event streams from the device.
+ */
+@Beta
+public interface GrpcController {
+
+ /**
+ * Adds a StreamObserver on a channel specific for a device.
+ *
+ * @param observerId the id of the observer
+ * @param grpcObserverHandler the manager for the stream.
+ */
+ void addObserver(GrpcStreamObserverId observerId, GrpcObserverHandler grpcObserverHandler);
+
+ /**
+ * Removes the StreamObserver on a channel specific for a device.
+ *
+ * @param observerId the id of the observer
+ */
+ void removeObserver(GrpcStreamObserverId observerId);
+
+ /**
+ * If present returns the stream observer manager previously added for the given device.
+ *
+ * @param observerId the id of the observer.
+ * @return the ObserverManager
+ */
+ Optional<GrpcObserverHandler> getObserverManager(GrpcStreamObserverId observerId);
+
+ /**
+ * Tries to connect to a specific gRPC device, if the connection is successful
+ * returns the ManagedChannel. This method blocks until the channel is setup or a timeout expires.
+ * By default the timeout is 20 seconds. If the timeout expires and thus the channel can't be set up
+ * a IOException is thrown.
+ *
+ * @param channelId the id of the channel
+ * @param channelBuilder the builder for the managed channel.
+ * @return the ManagedChannel created.
+ * @throws IOException if channel can't be setup.
+ */
+ ManagedChannel connectChannel(GrpcChannelId channelId, ManagedChannelBuilder<?> channelBuilder) throws IOException;
+
+ /**
+ * Disconnects a gRPC device by removing it's ManagedChannel from this controller.
+ *
+ * @param channelId id of the service to remove
+ */
+ void disconnectChannel(GrpcChannelId channelId);
+
+ /**
+ * Gets all ManagedChannels for the gRPC devices.
+ *
+ * @return Map of all the ManagedChannels with their identifier saved in this controller
+ */
+ Map<GrpcChannelId, ManagedChannel> getChannels();
+
+ /**
+ * Returns all ManagedChannels associated to the given device identifier.
+ *
+ * @param deviceId the device for which we are interested.
+ * @return collection of all the ManagedChannels saved in this controller
+ */
+ Collection<ManagedChannel> getChannels(DeviceId deviceId);
+
+ /**
+ * If present, returns the managed channel associated with the given identifier.
+ *
+ * @param channelId the id of the channel
+ * @return the ManagedChannel of the device.
+ */
+ Optional<ManagedChannel> getChannel(GrpcChannelId channelId);
+
+}
diff --git a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcObserverHandler.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcObserverHandler.java
new file mode 100644
index 0000000..46a3967
--- /dev/null
+++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcObserverHandler.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.grpc.api;
+
+import com.google.common.annotations.Beta;
+import io.grpc.ManagedChannel;
+import io.grpc.stub.StreamObserver;
+
+import java.util.Optional;
+
+/**
+ * Implementation to add or remove an observer to the managed channel.
+ *
+ */
+@Beta
+public interface GrpcObserverHandler {
+ /**
+ * The implementation of this method adds an
+ * observer on a stub generated on the specific channel.
+ * This method will be called by the gRPC controller.
+ *
+ * @param channel the channel from which to derive the stub.
+ */
+ void bindObserver(ManagedChannel channel);
+
+ /**
+ * The implementation of this method returns the request stream
+ * observer, if any, on a stub generated on the specific channel.
+ *
+ * @return the observer on the stub, empty if observer is server-side unidirectional.
+ */
+ Optional<StreamObserver> requestStreamObserver();
+
+ /**
+ * The implementation of this method removes an
+ * observer on a stub generated on the specific channel.
+ * This method will be called by the gRPC controller.
+ */
+ void removeObserver();
+}
diff --git a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcServiceId.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcServiceId.java
new file mode 100644
index 0000000..203ade6
--- /dev/null
+++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcServiceId.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.grpc.api;
+
+import com.google.common.annotations.Beta;
+import org.onlab.util.Identifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * gRPCService identifier suitable as an external key.
+ * <p>
+ * This class is immutable.</p>
+ */
+@Beta
+public final class GrpcServiceId extends Identifier<String> {
+
+ private final GrpcChannelId channelId;
+
+ private final String serviceName;
+
+ /**
+ * Instantiates a new gRPC Service id.
+ *
+ * @param channelId the channel id
+ * @param serviceName the name of the service on that channel
+ */
+ private GrpcServiceId(GrpcChannelId channelId, String serviceName) {
+ super(channelId.toString() + ":" + serviceName);
+ checkNotNull(channelId, "channel id must not be null");
+ checkNotNull(serviceName, "service name must not be null");
+ checkArgument(!serviceName.isEmpty(), "service name must not be empty");
+ this.channelId = channelId;
+ this.serviceName = serviceName;
+ }
+
+ /**
+ * Returns the id of the channel that this service uses.
+ *
+ * @return the channel Id
+ */
+ public GrpcChannelId channelId() {
+ return channelId;
+ }
+
+ /**
+ * Returns the name of this service.
+ *
+ * @return the service name
+ */
+ public String serviceName() {
+ return serviceName;
+ }
+
+ /**
+ * Creates a gRPC Service identifier from the specified device id and
+ * service name provided.
+ *
+ * @param id channel id
+ * @param serviceName name of the service
+ * @return service name
+ */
+ public static GrpcServiceId of(GrpcChannelId id, String serviceName) {
+ return new GrpcServiceId(id, serviceName);
+ }
+}
diff --git a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcStreamObserverId.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcStreamObserverId.java
new file mode 100644
index 0000000..911705a
--- /dev/null
+++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcStreamObserverId.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.grpc.api;
+
+import com.google.common.annotations.Beta;
+import org.onlab.util.Identifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * GrpcStreamObserver identifier suitable as an external key.
+ * <p>
+ * This class is immutable.</p>
+ */
+@Beta
+public final class GrpcStreamObserverId extends Identifier<String> {
+
+ private GrpcServiceId serviceId;
+ private String streamName;
+
+ /**
+ * Instantiates a new GrpcStreamObserver id.
+ *
+ * @param serviceId the service id
+ * @param streamName the name of the stream on that device
+ */
+ private GrpcStreamObserverId(GrpcServiceId serviceId, String streamName) {
+ super(serviceId.toString() + ":" + streamName);
+ checkNotNull(serviceId, "service id must not be null");
+ checkNotNull(streamName, "stream name must not be null");
+ checkArgument(!streamName.isEmpty(), "stream name must not be empty");
+ this.serviceId = serviceId;
+ this.streamName = streamName;
+ }
+
+ /**
+ * Returns the id of the service that this stream observer uses.
+ *
+ * @return the service Id
+ */
+ public GrpcServiceId serviceId() {
+ return serviceId;
+ }
+
+ /**
+ * Returns the name of this stream.
+ *
+ * @return the stream name
+ */
+ public String streamName() {
+ return streamName;
+ }
+
+ /**
+ * Creates a gRPC Stream Observer identifier from the specified service id and
+ * stream name provided.
+ *
+ * @param id service id
+ * @param streamName stream name
+ * @return stream name
+ */
+ public static GrpcStreamObserverId of(GrpcServiceId id, String streamName) {
+ return new GrpcStreamObserverId(id, streamName);
+ }
+}
diff --git a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/package-info.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/package-info.java
new file mode 100644
index 0000000..c3251db
--- /dev/null
+++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * gRPC protocol API.
+ */
+package org.onosproject.grpc.api;
\ No newline at end of file
diff --git a/protocols/grpc/ctl/BUCK b/protocols/grpc/ctl/BUCK
new file mode 100644
index 0000000..764d980
--- /dev/null
+++ b/protocols/grpc/ctl/BUCK
@@ -0,0 +1,20 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+ '//protocols/grpc/api:onos-protocols-grpc-api',
+ '//lib:grpc-core-1.3.0',
+ '//lib:grpc-protobuf-1.3.0',
+ '//lib:grpc-stub-1.3.0',
+ '//lib:grpc-netty-1.3.0',
+ '//lib:grpc-auth-1.3.0',
+]
+
+TEST_DEPS = [
+ '//lib:TEST_ADAPTERS',
+ '//utils/osgi:onlab-osgi-tests',
+]
+
+osgi_jar_with_tests (
+ deps = COMPILE_DEPS,
+ test_deps = TEST_DEPS,
+)
+
diff --git a/protocols/grpc/ctl/pom.xml b/protocols/grpc/ctl/pom.xml
new file mode 100644
index 0000000..eb327f9
--- /dev/null
+++ b/protocols/grpc/ctl/pom.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>onos-grpc-protocol</artifactId>
+ <groupId>org.onosproject</groupId>
+ <version>1.11.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>onos-grpc-protocol-ctl</artifactId>
+
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-grpc-protocol-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
new file mode 100644
index 0000000..4ce097d
--- /dev/null
+++ b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.grpc.ctl;
+
+import com.google.common.collect.ImmutableSet;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.grpc.api.GrpcChannelId;
+import org.onosproject.grpc.api.GrpcController;
+import org.onosproject.grpc.api.GrpcObserverHandler;
+import org.onosproject.grpc.api.GrpcStreamObserverId;
+import org.onosproject.net.DeviceId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Default implementation of the GrpcController.
+ */
+@Component(immediate = true)
+@Service
+public class GrpcControllerImpl implements GrpcController {
+
+ public static final Logger log = LoggerFactory
+ .getLogger(GrpcControllerImpl.class);
+
+ private Map<GrpcStreamObserverId, GrpcObserverHandler> observers;
+ private Map<GrpcChannelId, ManagedChannel> channels;
+ private Map<GrpcChannelId, ManagedChannelBuilder<?>> channelBuilders;
+
+ @Activate
+ public void activate() {
+ observers = new ConcurrentHashMap<>();
+ channels = new ConcurrentHashMap<>();
+ channelBuilders = new ConcurrentHashMap<>();
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ channels.values().forEach(ManagedChannel::shutdown);
+ observers.clear();
+ channels.clear();
+ channelBuilders.clear();
+ log.info("Stopped");
+ }
+
+ @Override
+ public void addObserver(GrpcStreamObserverId observerId, GrpcObserverHandler grpcObserverHandler) {
+ grpcObserverHandler.bindObserver(channels.get(observerId.serviceId().channelId()));
+ observers.put(observerId, grpcObserverHandler);
+ }
+
+ @Override
+ public void removeObserver(GrpcStreamObserverId observerId) {
+ observers.get(observerId).removeObserver();
+ observers.remove(observerId);
+ }
+
+ @Override
+ public Optional<GrpcObserverHandler> getObserverManager(GrpcStreamObserverId observerId) {
+ return Optional.ofNullable(observers.get(observerId));
+ }
+
+ @Override
+ public ManagedChannel connectChannel(GrpcChannelId channelId, ManagedChannelBuilder<?> channelBuilder) {
+ ManagedChannel channel = channelBuilder.build();
+
+ channel.getState(true);
+ channelBuilders.put(channelId, channelBuilder);
+ channels.put(channelId, channel);
+ return channel;
+ }
+
+ @Override
+ public void disconnectChannel(GrpcChannelId channelId) {
+ channels.get(channelId).shutdown();
+ channels.remove(channelId);
+ channelBuilders.remove(channelId);
+ }
+
+ @Override
+ public Map<GrpcChannelId, ManagedChannel> getChannels() {
+ return channels;
+ }
+
+ @Override
+ public Collection<ManagedChannel> getChannels(final DeviceId deviceId) {
+ final Set<ManagedChannel> deviceChannels = new HashSet<>();
+ channels.forEach((k, v) -> {
+ if (k.deviceId().equals(deviceId)) {
+ deviceChannels.add(v);
+ }
+ });
+
+ return ImmutableSet.copyOf(deviceChannels);
+ }
+
+ @Override
+ public Optional<ManagedChannel> getChannel(GrpcChannelId channelId) {
+ return Optional.ofNullable(channels.get(channelId));
+ }
+}
diff --git a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/package-info.java b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/package-info.java
new file mode 100644
index 0000000..c29204a
--- /dev/null
+++ b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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 for gRPC protocol implementations.
+ */
+package org.onosproject.grpc.ctl;
\ No newline at end of file
diff --git a/protocols/grpc/pom.xml b/protocols/grpc/pom.xml
new file mode 100644
index 0000000..eca6143
--- /dev/null
+++ b/protocols/grpc/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>onos-protocols</artifactId>
+ <groupId>org.onosproject</groupId>
+ <version>1.11.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>onos-grpc-protocol</artifactId>
+
+ <modules>
+ <module>api</module>
+ <module>ctl</module>
+ </modules>
+
+ <packaging>pom</packaging>
+
+ <description>gRPC protocol subsystem</description>
+
+</project>
\ No newline at end of file
diff --git a/protocols/pom.xml b/protocols/pom.xml
index b823f9c..23b428b 100644
--- a/protocols/pom.xml
+++ b/protocols/pom.xml
@@ -43,6 +43,7 @@
<module>lisp</module>
<module>restconf</module>
<module>tl1</module>
+ <module>grpc</module>
</modules>
<dependencies>