Initial gNOI implementation added. Introduced system Time and Reboot RPC

Change-Id: I8accdcc6c1ff247408ce54490ceff3972fdf850f
diff --git a/drivers/gnoi/BUILD b/drivers/gnoi/BUILD
new file mode 100644
index 0000000..3a710a8
--- /dev/null
+++ b/drivers/gnoi/BUILD
@@ -0,0 +1,33 @@
+COMPILE_DEPS = CORE_DEPS + KRYO + [
+    "@com_google_protobuf//:protobuf_java",
+    "@io_grpc_grpc_java//core",
+    "@io_grpc_grpc_java//netty",
+    "@io_grpc_grpc_java//stub",
+    "//protocols/gnoi/stub:onos-protocols-gnoi-stub",
+    "//protocols/gnoi/api:onos-protocols-gnoi-api",
+    "//protocols/grpc/api:onos-protocols-grpc-api",
+]
+
+BUNDLES = [
+    ":onos-drivers-gnoi",
+]
+
+osgi_jar(
+    resources = glob(["src/main/resources/**"]),
+    resources_root = "src/main/resources",
+    deps = COMPILE_DEPS,
+)
+
+onos_app(
+    app_name = "org.onosproject.drivers.gnoi",
+    category = "Drivers",
+    description = "Adds support for devices using gNOI protocol based on " +
+                  " openconfig proto definitions: https://github.com/openconfig/gnoi/ .",
+    included_bundles = BUNDLES,
+    required_apps = [
+        "org.onosproject.generaldeviceprovider",
+        "org.onosproject.protocols.gnoi",
+    ],
+    title = "gNOI Drivers",
+    url = "https://github.com/openconfig/gnoi/",
+)
diff --git a/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/AbstractGnoiHandlerBehaviour.java b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/AbstractGnoiHandlerBehaviour.java
new file mode 100644
index 0000000..23181b4
--- /dev/null
+++ b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/AbstractGnoiHandlerBehaviour.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019-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.gnoi;
+
+import com.google.common.base.Strings;
+import org.onosproject.gnoi.api.GnoiClient;
+import org.onosproject.gnoi.api.GnoiClientKey;
+import org.onosproject.gnoi.api.GnoiController;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Abstract implementation of a behaviour handler for a gNOI device.
+ */
+public class AbstractGnoiHandlerBehaviour extends AbstractHandlerBehaviour {
+
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected DeviceId deviceId;
+    protected DeviceService deviceService;
+    protected Device device;
+    protected GnoiController controller;
+    protected GnoiClient client;
+
+    protected boolean setupBehaviour() {
+        deviceId = handler().data().deviceId();
+        deviceService = handler().get(DeviceService.class);
+        controller = handler().get(GnoiController.class);
+        client = controller.getClient(deviceId);
+
+        if (client == null) {
+            log.warn("Unable to find client for {}, aborting operation", deviceId);
+            return false;
+        }
+
+        return true;
+    }
+
+    GnoiClient getClientByKey() {
+        final GnoiClientKey clientKey = clientKey();
+        if (clientKey == null) {
+            return null;
+        }
+        return handler().get(GnoiController.class).getClient(clientKey);
+    }
+
+    protected GnoiClientKey clientKey() {
+        deviceId = handler().data().deviceId();
+
+        final BasicDeviceConfig cfg = handler().get(NetworkConfigService.class)
+                .getConfig(deviceId, BasicDeviceConfig.class);
+        if (cfg == null || Strings.isNullOrEmpty(cfg.managementAddress())) {
+            log.error("Missing or invalid config for {}, cannot derive " +
+                    "gNOI server endpoints", deviceId);
+            return null;
+        }
+
+        try {
+            return new GnoiClientKey(
+                    deviceId, new URI(cfg.managementAddress()));
+        } catch (URISyntaxException e) {
+            log.error("Management address of {} is not a valid URI: {}",
+                    deviceId, cfg.managementAddress());
+            return null;
+        }
+    }
+}
diff --git a/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiBasicSystemOperationsImpl.java b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiBasicSystemOperationsImpl.java
new file mode 100644
index 0000000..411a8bf
--- /dev/null
+++ b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiBasicSystemOperationsImpl.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019-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.gnoi;
+
+import gnoi.system.SystemOuterClass.RebootRequest;
+import gnoi.system.SystemOuterClass.RebootResponse;
+import gnoi.system.SystemOuterClass.RebootMethod;
+import org.onosproject.net.behaviour.BasicSystemOperations;
+import java.util.concurrent.CompletableFuture;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of the BasicSystemOperations behavior for gNOI-enabled devices.
+ */
+public class GnoiBasicSystemOperationsImpl
+        extends AbstractGnoiHandlerBehaviour implements BasicSystemOperations {
+
+    private static final Logger log = LoggerFactory
+            .getLogger(GnoiBasicSystemOperationsImpl.class);
+
+    @Override
+    public CompletableFuture<Boolean> reboot() {
+        if (!setupBehaviour()) {
+            return CompletableFuture.completedFuture(false);
+        }
+
+        final RebootRequest.Builder requestMsg = RebootRequest.newBuilder().setMethod(RebootMethod.COLD);
+        final CompletableFuture<Boolean> future = client.reboot(requestMsg.build())
+                .handle((response, error) -> {
+                    if (error == null) {
+                        log.debug("gNOI reboot() for device {} returned {}", deviceId, response);
+                        return RebootResponse.getDefaultInstance().equals(response);
+                    } else {
+                        log.error("Exception while performing gNOI reboot() for device " + deviceId, error);
+                        return false;
+                    }
+                });
+
+        return future;
+    }
+
+    @Override
+    public CompletableFuture<Long> time() {
+        if (!setupBehaviour()) {
+            return CompletableFuture.completedFuture(0L);
+        }
+        final CompletableFuture<Long> future = client.time()
+                .handle((response, error) -> {
+                    if (error == null) {
+                        log.debug("gNOI time() for device {} returned {}", deviceId.uri(), response.getTime());
+                        return response.getTime();
+                    } else {
+                        log.error("Exception while performing gNOI time() for device " + deviceId, error);
+                        return 0L;
+                    }
+                });
+
+        return future;
+    }
+}
diff --git a/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiDeviceDescriptionDiscovery.java b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiDeviceDescriptionDiscovery.java
new file mode 100644
index 0000000..3c308d6
--- /dev/null
+++ b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiDeviceDescriptionDiscovery.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019-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.gnoi;
+
+import org.onlab.packet.ChassisId;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.Device;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.device.PortDescription;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Implementation of DeviceDescriptionDiscovery for gNOI devices.
+ */
+public class GnoiDeviceDescriptionDiscovery
+        extends AbstractGnoiHandlerBehaviour implements DeviceDescriptionDiscovery {
+
+    private static final String UNKNOWN = "unknown";
+
+    @Override
+    public DeviceDescription discoverDeviceDetails() {
+
+        return new DefaultDeviceDescription(
+                data().deviceId().uri(),
+                Device.Type.SWITCH,
+                data().driver().manufacturer(),
+                data().driver().hwVersion(),
+                data().driver().swVersion(),
+                UNKNOWN,
+                new ChassisId(),
+                false,
+                DefaultAnnotations.builder()
+                        .set(AnnotationKeys.PROTOCOL, "gNOI")
+                        .build());
+    }
+
+
+    @Override
+    public List<PortDescription> discoverPortDetails() {
+        return Collections.emptyList();
+    }
+}
diff --git a/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiDriversLoader.java b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiDriversLoader.java
new file mode 100644
index 0000000..2758176
--- /dev/null
+++ b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiDriversLoader.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019-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.gnoi;
+
+import org.osgi.service.component.annotations.Component;
+import org.onosproject.net.driver.AbstractDriverLoader;
+
+/**
+ * Loader for gNOI device drivers.
+ */
+@Component(immediate = true)
+public class GnoiDriversLoader extends AbstractDriverLoader {
+
+    public GnoiDriversLoader() {
+        super("/gnoi-drivers.xml");
+    }
+
+    @Override
+    public void activate() {
+        super.activate();
+    }
+}
diff --git a/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiHandshaker.java b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiHandshaker.java
new file mode 100644
index 0000000..36a4971
--- /dev/null
+++ b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/GnoiHandshaker.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019-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.gnoi;
+
+import org.onosproject.gnoi.api.GnoiClient;
+import org.onosproject.gnoi.api.GnoiClientKey;
+import org.onosproject.gnoi.api.GnoiController;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.device.DeviceHandshaker;
+
+import java.util.concurrent.CompletableFuture;
+
+import static java.util.concurrent.CompletableFuture.completedFuture;
+
+/**
+ * Implementation of DeviceHandshaker for gNOI.
+ */
+public class GnoiHandshaker extends AbstractGnoiHandlerBehaviour implements DeviceHandshaker {
+
+    @Override
+    public boolean isReachable() {
+        final GnoiClient client = getClientByKey();
+        return client != null && client.isServerReachable();
+    }
+
+    @Override
+    public CompletableFuture<Boolean> probeReachability() {
+        final GnoiClient client = getClientByKey();
+        if (client == null) {
+            return completedFuture(false);
+        }
+        return client.probeService();
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return isReachable();
+    }
+
+    @Override
+    public CompletableFuture<Boolean> probeAvailability() {
+        return probeReachability();
+    }
+
+    @Override
+    public void roleChanged(MastershipRole newRole) {
+        throw new UnsupportedOperationException("Mastership operation not supported");
+    }
+
+    @Override
+    public MastershipRole getRole() {
+        throw new UnsupportedOperationException("Mastership operation not supported");
+    }
+
+    @Override
+    public CompletableFuture<Boolean> connect() {
+        return CompletableFuture.supplyAsync(this::createClient);
+    }
+
+    private boolean createClient() {
+        GnoiClientKey clientKey = clientKey();
+        if (clientKey == null) {
+            return false;
+        }
+        if (!handler().get(GnoiController.class).createClient(clientKey)) {
+            log.warn("Unable to create client for {}",
+                    handler().data().deviceId());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isConnected() {
+        return getClientByKey() != null;
+    }
+
+    @Override
+    public void disconnect() {
+        handler().get(GnoiController.class)
+                .removeClient(handler().data().deviceId());
+    }
+}
diff --git a/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/package-info.java b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/package-info.java
new file mode 100644
index 0000000..fde5c57
--- /dev/null
+++ b/drivers/gnoi/src/main/java/org/onosproject/drivers/gnoi/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-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 for gNOI device drivers.
+ */
+package org.onosproject.drivers.gnoi;
diff --git a/drivers/gnoi/src/main/resources/gnoi-drivers.xml b/drivers/gnoi/src/main/resources/gnoi-drivers.xml
new file mode 100644
index 0000000..891fcd7
--- /dev/null
+++ b/drivers/gnoi/src/main/resources/gnoi-drivers.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2019-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="gnoi" manufacturer="gnoi" hwVersion="master" swVersion="master">
+        <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
+                   impl="org.onosproject.drivers.gnoi.GnoiDeviceDescriptionDiscovery"/>
+        <behaviour api="org.onosproject.net.behaviour.BasicSystemOperations"
+                   impl="org.onosproject.drivers.gnoi.GnoiBasicSystemOperationsImpl"/>
+        <behaviour api="org.onosproject.net.device.DeviceHandshaker"
+                   impl="org.onosproject.drivers.gnoi.GnoiHandshaker"/>
+    </driver>
+</drivers>
diff --git a/drivers/stratum/BUILD b/drivers/stratum/BUILD
index c075491..1d19c3c 100644
--- a/drivers/stratum/BUILD
+++ b/drivers/stratum/BUILD
@@ -2,6 +2,7 @@
     "@io_grpc_grpc_java//core",
     "//drivers/p4runtime:onos-drivers-p4runtime",
     "//drivers/gnmi:onos-drivers-gnmi",
+    "//drivers/gnoi:onos-drivers-gnoi",
     "//pipelines/basic:onos-pipelines-basic",
 ]
 
@@ -18,6 +19,7 @@
     required_apps = [
         "org.onosproject.generaldeviceprovider",
         "org.onosproject.drivers.gnmi",
+        "org.onosproject.drivers.gnoi",
         "org.onosproject.drivers.p4runtime",
         "org.onosproject.pipelines.basic",
     ],
diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/AbstractStratumBehaviour.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/AbstractStratumBehaviour.java
index b7c56e9..a9a7e2f 100644
--- a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/AbstractStratumBehaviour.java
+++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/AbstractStratumBehaviour.java
@@ -32,10 +32,12 @@
 
     protected B p4runtime;
     protected B gnmi;
+    protected B gnoi;
 
-    public AbstractStratumBehaviour(B p4runtime, B gnmi) {
+    public AbstractStratumBehaviour(B p4runtime, B gnmi, B gnoi) {
         this.p4runtime = p4runtime;
         this.gnmi = gnmi;
+        this.gnoi = gnoi;
     }
 
     @Override
@@ -43,6 +45,7 @@
         super.setHandler(handler);
         p4runtime.setHandler(handler);
         gnmi.setHandler(handler);
+        gnoi.setHandler(handler);
     }
 
     @Override
@@ -50,5 +53,6 @@
         super.setData(data);
         p4runtime.setData(data);
         gnmi.setData(data);
+        gnoi.setData(data);
     }
 }
diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDeviceDescriptionDiscovery.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDeviceDescriptionDiscovery.java
index 4a65e26..f2e6e8d 100644
--- a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDeviceDescriptionDiscovery.java
+++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDeviceDescriptionDiscovery.java
@@ -17,6 +17,7 @@
 package org.onosproject.drivers.stratum;
 
 import org.onosproject.drivers.gnmi.OpenConfigGnmiDeviceDescriptionDiscovery;
+import org.onosproject.drivers.gnoi.GnoiDeviceDescriptionDiscovery;
 import org.onosproject.drivers.p4runtime.P4RuntimeDeviceDescriptionDiscovery;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
@@ -42,12 +43,14 @@
 
     public StratumDeviceDescriptionDiscovery() {
         super(new P4RuntimeDeviceDescriptionDiscovery(),
-              new OpenConfigGnmiDeviceDescriptionDiscovery());
+              new OpenConfigGnmiDeviceDescriptionDiscovery(),
+              new GnoiDeviceDescriptionDiscovery());
     }
 
     @Override
     public DeviceDescription discoverDeviceDetails() {
         final DeviceDescription p4Descr = p4runtime.discoverDeviceDetails();
+        final DeviceDescription gnoiDescr = gnoi.discoverDeviceDetails();
         final DeviceDescription gnmiDescr = gnmi.discoverDeviceDetails();
         return new DefaultDeviceDescription(
                 data().deviceId().uri(),
@@ -61,8 +64,9 @@
                 p4Descr.isDefaultAvailable(),
                 DefaultAnnotations.builder()
                         .set(AnnotationKeys.PROTOCOL, format(
-                                "%s, %s",
+                                "%s, %s, %s",
                                 p4Descr.annotations().value(AnnotationKeys.PROTOCOL),
+                                gnoiDescr.annotations().value(AnnotationKeys.PROTOCOL),
                                 gnmiDescr.annotations().value(AnnotationKeys.PROTOCOL)))
                         .build());
     }
diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java
index 8ce68d7..d512d3b 100644
--- a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java
+++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java
@@ -17,6 +17,7 @@
 package org.onosproject.drivers.stratum;
 
 import org.onosproject.drivers.gnmi.GnmiHandshaker;
+import org.onosproject.drivers.gnoi.GnoiHandshaker;
 import org.onosproject.drivers.p4runtime.P4RuntimeHandshaker;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.device.DeviceAgentListener;
@@ -33,7 +34,7 @@
         implements DeviceHandshaker {
 
     public StratumHandshaker() {
-        super(new P4RuntimeHandshaker(), new GnmiHandshaker());
+        super(new P4RuntimeHandshaker(), new GnmiHandshaker(), new GnoiHandshaker());
     }
 
     @Override
@@ -89,17 +90,19 @@
     @Override
     public CompletableFuture<Boolean> connect() {
         // We should execute connections in parallel.
-        return p4runtime.connect().thenCombine(gnmi.connect(), Boolean::logicalAnd);
+        return p4runtime.connect().thenCombine(gnmi.connect(), Boolean::logicalAnd)
+                .thenCombine(gnoi.connect(), Boolean::logicalAnd);
     }
 
     @Override
     public boolean isConnected() {
-        return p4runtime.isConnected() && gnmi.isConnected();
+        return p4runtime.isConnected() && gnmi.isConnected() && gnoi.isConnected();
     }
 
     @Override
     public void disconnect() {
         p4runtime.disconnect();
         gnmi.disconnect();
+        gnoi.disconnect();
     }
 }
diff --git a/drivers/stratum/src/main/resources/stratum-drivers.xml b/drivers/stratum/src/main/resources/stratum-drivers.xml
index f854d5f..72e224b 100644
--- a/drivers/stratum/src/main/resources/stratum-drivers.xml
+++ b/drivers/stratum/src/main/resources/stratum-drivers.xml
@@ -16,7 +16,7 @@
   -->
 <drivers>
     <driver name="stratum" manufacturer="Open Networking Foundation"
-            hwVersion="master" swVersion="Stratum" extends="p4runtime,gnmi">
+            hwVersion="master" swVersion="Stratum" extends="p4runtime,gnmi,gnoi">
         <behaviour api="org.onosproject.net.device.DeviceHandshaker"
                    impl="org.onosproject.drivers.stratum.StratumHandshaker"/>
         <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"