ONOS-7629 - minimal support for Ciena 51xx devices

Change-Id: I19408f558c1766686b8e567ae27e3077db782cf3
diff --git a/drivers/ciena/README.md b/drivers/ciena/README.md
index 7a29a1d..acd1acf 100644
--- a/drivers/ciena/README.md
+++ b/drivers/ciena/README.md
@@ -1,4 +1,4 @@
 There is no BUCK or pom.xml file at this level because each driver 
 should be completely independent of each other. i.e. The will be 
-treated as individual applications. The 'microsemi' folder is only 
-a grouping mechanism at the directory level. 
\ No newline at end of file
+treated as individual applications. The 'ciena' folder is only 
+a grouping mechanism at the directory level. 
diff --git a/drivers/ciena/c5162/BUCK b/drivers/ciena/c5162/BUCK
new file mode 100644
index 0000000..b880a8a
--- /dev/null
+++ b/drivers/ciena/c5162/BUCK
@@ -0,0 +1,46 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+    '//lib:JACKSON',
+    '//lib:javax.ws.rs-api',
+    '//incubator/api:onos-incubator-api',
+    '//utils/rest:onlab-rest',
+    '//drivers/utilities:onos-drivers-utilities',
+    '//drivers/netconf:onos-drivers-netconf',
+    '//protocols/netconf/api:onos-protocols-netconf-api',
+]
+
+TEST_DEPS = [
+    '//lib:TEST_ADAPTERS',
+    '//core/api:onos-api-tests',
+    '//drivers/netconf:onos-drivers-netconf-tests',
+]
+
+BUNDLES = [
+    ':onos-drivers-ciena-c5162',
+    '//drivers/utilities:onos-drivers-utilities',
+    '//drivers/netconf:onos-drivers-netconf',
+]
+
+REQUIRED_APPS = [
+    'org.onosproject.linkdiscovery',
+    'org.onosproject.netconf',
+    'org.onosproject.netconfsb',
+    'org.onosproject.drivers.netconf'
+]
+
+osgi_jar_with_tests (
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+    resources_root = 'src/main/resources',
+    resources = glob(['src/main/resources/**']),
+)
+
+onos_app (
+    app_name = 'org.onosproject.drivers.ciena.c5162',
+    title = 'Ciena 5162 Drivers',
+    category = 'Drivers',
+    url = 'http://onosproject.org',
+    description = 'Adds support for Ciena 5162 devices.',
+    included_bundles = BUNDLES,
+    required_apps = REQUIRED_APPS,
+)
diff --git a/drivers/ciena/c5162/README.md b/drivers/ciena/c5162/README.md
new file mode 100644
index 0000000..6bacced
--- /dev/null
+++ b/drivers/ciena/c5162/README.md
@@ -0,0 +1,66 @@
+# Ciena 5162
+
+This driver allows connection to the Ciena 5162
+
+The User Guide for this product is available on request from Ciena, and gives a full explanation of the theory of operation, functionality and how all functions can be accessed through the REST interface.
+
+Currently only a subset of it's functionality is supported through ONOS, but this will expand to full functionality in future releases.
+
+More information about ONOS's NETCONF support can be found at `https://wiki.onosproject.org/display/ONOS/NETCONF`.
+
+## Compile and Installation
+
+Currently this driver is built using BUCK and uses version 2.1 of onos-yang-tools<br/>
+
+All that is required to activate the driver is to run the following at the ONOS CLI
+
+```bash
+app activate org.onosproject.drivers.ciena.c5162
+```
+
+## Usage
+
+### Creating Devices
+
+Ciena 5162 Devices are not Openflow devices. The connectivity is initiated from ONOS. They have to be created through the network/configuration interface in ONOS.
+
+* The name must follow the format **netconf:ipaddr:port**
+* The **ip** and **port** must correspond to the ip and port in the name (above).
+* The **connect-timeout** and **reply-timeout** are optional and control NETCONF communication timeouts
+* The **name** is optional and allows you to set a human friendly name for the device
+
+```bash
+curl -X POST
+  http://onos-ip:8181/onos/v1/network/configuration
+  -H 'Authorization: Basic b25vczpyb2Nrcw==' \
+  -H 'Content-Type: application/json' \
+  -d '{
+    "devices": {
+      "netconf:10.184.136.186:830": {
+        "netconf": {
+          "port": 830,
+          "ip": "10.184.136.186",
+          "username": "su",
+          "password": "cws",
+          "connect-timeout": 120,
+          "reply-timeout": 640
+        },
+        "basic": {
+          "driver": "ciena-c5162-netconf",
+          "name": "my-switch"
+        }
+      }
+    }
+}'
+```
+
+
+
+#### Verify Connected Device
+
+When the 5162 is configured and connected is should be visible in ONOS through the `devices` command.
+
+```bash 
+onos> devices 
+id=netconf:10.184.136.186:830, available=true, local-status=connected 1s ago, role=MASTER, type=SWITCH, mfr=Ciena, hw=5162, sw=saos-01-01-00-0025, serial=M9258118, driver=ciena-5162-netconf, gridX=null, gridY=null, ipaddress=10.184.136.186, latitude=null, locType=none, longitude=null, name=my-switch, port=830, protocol=NETCONF
+```
diff --git a/drivers/ciena/c5162/features.xml b/drivers/ciena/c5162/features.xml
new file mode 100644
index 0000000..1e78782
--- /dev/null
+++ b/drivers/ciena/c5162/features.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+    <feature name="${project.artifactId}" version="${project.version}"
+             description="${project.description}">
+        <feature>onos-api</feature>
+        <bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-drivers-utilities/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-drivers-netconf/${project.version}</bundle>
+    </feature>
+</features>
diff --git a/drivers/ciena/c5162/pom.xml b/drivers/ciena/c5162/pom.xml
new file mode 100644
index 0000000..abcd0bb
--- /dev/null
+++ b/drivers/ciena/c5162/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ 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. -->
+
+<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-drivers-general</artifactId>
+		<groupId>org.onosproject</groupId>
+		<version>1.14.0-SNAPSHOT</version>
+		<relativePath>../../pom.xml</relativePath>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+
+	<artifactId>onos-drivers-ciena-c5162</artifactId>
+	<packaging>bundle</packaging>
+
+	<description>Ciena 5162 device drivers</description>
+
+	<properties>
+		<onos.app.name>org.onosproject.drivers.ciena.c5162</onos.app.name>
+		<onos.app.origin>ONOS Community</onos.app.origin>
+		<onos.app.title>Ciena 5162 Device Drivers</onos.app.title>
+		<onos.app.category>Drivers</onos.app.category>
+		<onos.app.url>http://onosproject.org</onos.app.url>
+		<onos.app.requires>
+			org.onosproject.netconf
+		</onos.app.requires>
+		<jinjava.version>2.4.0</jinjava.version>
+		<jsoup.version>1.8.1</jsoup.version>
+		<juel.version>2.2.7</juel.version>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.onosproject</groupId>
+			<artifactId>onos-drivers-utilities</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.onosproject</groupId>
+			<artifactId>onos-protocols-netconf-api</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.onosproject</groupId>
+			<artifactId>onos-drivers-netconf</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+	</dependencies>
+
+</project>
diff --git a/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/Ciena5162DriversLoader.java b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/Ciena5162DriversLoader.java
new file mode 100644
index 0000000..338c2f1
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/Ciena5162DriversLoader.java
@@ -0,0 +1,30 @@
+/*
+ * 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.ciena.c5162;
+
+import org.apache.felix.scr.annotations.Component;
+import org.onosproject.net.driver.AbstractDriverLoader;
+
+/**
+ * Loader for Ciena device drivers.
+ */
+@Component(immediate = true)
+public class Ciena5162DriversLoader extends AbstractDriverLoader {
+
+    public Ciena5162DriversLoader() {
+        super("/ciena-5162-drivers.xml");
+    }
+}
diff --git a/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/Ciena5162DeviceDescription.java b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/Ciena5162DeviceDescription.java
new file mode 100644
index 0000000..aeb0d11
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/Ciena5162DeviceDescription.java
@@ -0,0 +1,269 @@
+/*
+ * 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.ciena.c5162.netconf;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.onlab.packet.ChassisId;
+import org.onosproject.drivers.netconf.TemplateManager;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.LinkDiscovery;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.DefaultPortStatistics;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.device.PortStatistics;
+import org.onosproject.net.device.PortStatisticsDiscovery;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.link.DefaultLinkDescription;
+import org.onosproject.net.link.LinkDescription;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Discovers the ports from a Ciena WaveServer Rest device.
+ */
+public class Ciena5162DeviceDescription extends AbstractHandlerBehaviour
+        implements DeviceDescriptionDiscovery, PortStatisticsDiscovery, LinkDiscovery {
+    private static final Logger log = getLogger(Ciena5162DeviceDescription.class);
+    private static final TemplateManager TEMPLATE_MANAGER = new TemplateManager();
+
+    static {
+        TEMPLATE_MANAGER.load(Ciena5162DeviceDescription.class, "/templates/requests/%s.j2", "systemInfo",
+                "softwareVersion", "logicalPorts", "port-stats", "link-info");
+    }
+
+    @Override
+    public DeviceDescription discoverDeviceDetails() {
+
+        DeviceId deviceId = handler().data().deviceId();
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        try {
+            Node systemInfo = TEMPLATE_MANAGER.doRequest(session, "systemInfo");
+            Node softwareVersion = TEMPLATE_MANAGER.doRequest(session, "softwareVersion");
+            XPath xp = XPathFactory.newInstance().newXPath();
+            String mac = xp.evaluate("components/component/properties/property/state/value/text()", systemInfo)
+                    .toUpperCase();
+            return new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH,
+                    xp.evaluate("components/component/state/mfg-name/text()", systemInfo),
+                    xp.evaluate("components/component/state/name/text()", systemInfo),
+                    xp.evaluate("software-state/running-package/package-version/text()", softwareVersion),
+                    xp.evaluate("components/component/state/serial-no/text()", systemInfo),
+                    new ChassisId(Long.valueOf(mac, 16)));
+
+        } catch (XPathExpressionException | NetconfException ne) {
+            log.error("failed to query system info from device {}", handler().data().deviceId(), ne);
+        }
+
+        return new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH, "Ciena", "5162", "Unknown", "Unknown",
+                new ChassisId());
+    }
+
+    /**
+     * Convert the specification of port speed in the of of #unit, i.e. {@10G} to MB
+     * as represented by a Long.
+     *
+     * @param ps
+     *            specification of port speed
+     * @return port speed as MBs
+     */
+    private Long portSpeedToLong(String ps) {
+        String value = ps.trim();
+        StringBuilder digits = new StringBuilder();
+        String unit = "";
+        for (int i = 0; i < value.length(); i += 1) {
+            final char c = value.charAt(i);
+            if (Character.isDigit(c)) {
+                digits.append(c);
+            } else {
+                unit = value.substring(i).toUpperCase().trim();
+                break;
+            }
+        }
+
+        switch (unit) {
+        case "G":
+        case "GB":
+            return Long.valueOf(digits.toString()) * 1000;
+        case "M":
+        case "MB":
+        default:
+            return Long.valueOf(digits.toString());
+        }
+    }
+
+    @Override
+    public List<PortDescription> discoverPortDetails() {
+        List<PortDescription> ports = new ArrayList<PortDescription>();
+        DeviceId deviceId = handler().data().deviceId();
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        if (controller == null || controller.getDevicesMap() == null
+                || controller.getDevicesMap().get(deviceId) == null) {
+            log.warn("NETCONF session to device {} not yet established, will be retried", deviceId);
+            return ports;
+        }
+        NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
+
+        try {
+            Node logicalPorts = TEMPLATE_MANAGER.doRequest(session, "logicalPorts");
+            XPath xp = XPathFactory.newInstance().newXPath();
+            NodeList nl = (NodeList) xp.evaluate("interfaces/interface/config", logicalPorts, XPathConstants.NODESET);
+            int count = nl.getLength();
+            Node node;
+            for (int i = 0; i < count; i += 1) {
+                node = nl.item(i);
+                if (xp.evaluate("type/text()", node).equals("ettp")) {
+                    ports.add(DefaultPortDescription.builder()
+                            .withPortNumber(PortNumber.portNumber(xp.evaluate("name/text()", node)))
+                            .isEnabled(Boolean.valueOf(xp.evaluate("admin-status/text()", node)))
+                            .portSpeed(portSpeedToLong(xp.evaluate("port-speed/text()", node))).type(Port.Type.PACKET)
+                            .build());
+                }
+            }
+        } catch (NetconfException | XPathExpressionException e) {
+            log.error("Unable to retrieve port information for device {}, {}", deviceId, e);
+        }
+        return ports;
+    }
+
+    @Override
+    public Collection<PortStatistics> discoverPortStatistics() {
+        List<PortStatistics> stats = new ArrayList<PortStatistics>();
+
+        DeviceId deviceId = handler().data().deviceId();
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        if (controller == null || controller.getDevicesMap() == null
+                || controller.getDevicesMap().get(deviceId) == null) {
+            log.warn("NETCONF session to device {} not yet established, will be retried", deviceId);
+            return stats;
+        }
+        NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
+
+        try {
+            Node data = TEMPLATE_MANAGER.doRequest(session, "port-stats");
+            XPath xp = XPathFactory.newInstance().newXPath();
+            NodeList interfaces = (NodeList) xp.evaluate("interfaces/interface", data, XPathConstants.NODESET);
+            int count = interfaces.getLength();
+            for (int i = 0; i < count; i += 1) {
+                Node iface = interfaces.item(i);
+                if (xp.evaluate("config/type/text()", iface).equals("ettp")) {
+                    stats.add(DefaultPortStatistics.builder().setDeviceId(deviceId)
+                            .setPort(PortNumber.portNumber(xp.evaluate("name/text()", iface)))
+                            .setBytesReceived(Long.valueOf(xp.evaluate("state/counters/in-octets/text()", iface)))
+                            .setBytesSent(Long.valueOf(xp.evaluate("state/counters/out-octets/text()", iface)))
+                            .setPacketsReceived(Long.valueOf(xp.evaluate("state/counters/in-pkts/text()", iface)))
+                            .setPacketsSent(Long.valueOf(xp.evaluate("state/counters/out-pkts/text()", iface)))
+                            .setPacketsTxErrors(Long.valueOf(xp.evaluate("state/counters/out-errors/text()", iface)))
+                            .setPacketsRxErrors(Long.valueOf(xp.evaluate("state/counters/in-errors/text()", iface)))
+                            .build());
+                }
+            }
+        } catch (NetconfException | XPathExpressionException e) {
+            log.error("Unable to retrieve port statistics for device {}, {}", deviceId, e);
+        }
+
+        return stats;
+    }
+
+    @Override
+    public Set<LinkDescription> getLinks() {
+        log.debug("LINKS CHECKING ...");
+        Set<LinkDescription> links = new HashSet<LinkDescription>();
+        DeviceId deviceId = handler().data().deviceId();
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        if (controller == null || controller.getDevicesMap() == null
+                || controller.getDevicesMap().get(deviceId) == null) {
+            log.warn("NETCONF session to device {} not yet established, cannot load links, will be retried", deviceId);
+            return links;
+        }
+        NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
+        try {
+
+            DeviceService deviceService = this.handler().get(DeviceService.class);
+
+            Iterable<Device> devices = deviceService.getAvailableDevices();
+            Map<String, Device> lookup = new HashMap<String, Device>();
+            for (Device d : devices) {
+                lookup.put(d.chassisId().toString().toUpperCase(), d);
+            }
+
+            Node logicalPorts = TEMPLATE_MANAGER.doRequest(session, "link-info");
+            XPath xp = XPathFactory.newInstance().newXPath();
+            NodeList ifaces = (NodeList) xp.evaluate("interfaces/interface", logicalPorts, XPathConstants.NODESET);
+            int count = ifaces.getLength();
+            Node iface;
+            Node destChassis;
+            for (int i = 0; i < count; i += 1) {
+                iface = ifaces.item(i);
+                if (xp.evaluate("config/type/text()", iface).equals("ettp")) {
+                    destChassis = (Node) xp.evaluate("state/lldp-remote-port-operational/chassis-id", iface,
+                            XPathConstants.NODE);
+
+                    if (destChassis != null) {
+                        Device dest = lookup.get(destChassis.getTextContent().toUpperCase());
+
+                        if (dest != null) {
+
+                            links.add(new DefaultLinkDescription(
+                                    new ConnectPoint(deviceId,
+                                            PortNumber.portNumber(xp.evaluate("name/text()", iface))),
+                                    new ConnectPoint(dest.id(),
+                                            PortNumber.portNumber(xp.evaluate(
+                                                    "state/lldp-remote-port-operational/port-id/text()", iface))),
+                                    Link.Type.DIRECT, true));
+                        } else {
+                            log.error("DEST CHASSIS is NULL for {}", xp.evaluate("name/text()", iface));
+                        }
+                    } else {
+                        log.debug("NO LINK for {}", xp.evaluate("name/text()", iface));
+                    }
+                }
+            }
+        } catch (NetconfException | XPathExpressionException e) {
+            log.error("Unable to retrieve links for device {}, {}", deviceId, e);
+        }
+
+        return links;
+    }
+
+}
diff --git a/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/Ciena5162PortAdmin.java b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/Ciena5162PortAdmin.java
new file mode 100644
index 0000000..6fbf631
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/Ciena5162PortAdmin.java
@@ -0,0 +1,112 @@
+/*
+ * 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.ciena.c5162.netconf;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.onosproject.drivers.netconf.TemplateManager;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.PortAdmin;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.w3c.dom.Node;
+
+/**
+ * Handles port administration for Ciena 5162 devices using the NETCONF
+ * protocol.
+ */
+public class Ciena5162PortAdmin extends AbstractHandlerBehaviour implements PortAdmin {
+
+    private static final Logger log = getLogger(Ciena5162PortAdmin.class);
+    private static final TemplateManager TEMPLATE_MANAGER = new TemplateManager();
+
+    static {
+        TEMPLATE_MANAGER.load(Ciena5162PortAdmin.class, "/templates/requests/%s.j2", "logicalPort", "port-admin-state");
+    }
+
+    /**
+     * Sets the administrative state of the given port to the given value.
+     *
+     * @param number
+     *            port number
+     * @param value
+     *            state, true for enabled, false for disabled
+     * @return true if successfully set
+     */
+    private CompletableFuture<Boolean> setAdminState(PortNumber number, Boolean value) {
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+
+        try {
+            Map<String, Object> templateContext = new HashMap<String, Object>();
+            templateContext.put("port-number", number.toLong());
+            templateContext.put("admin-state", value.toString());
+            Node req = (Node) TEMPLATE_MANAGER.doRequest(session, "port-admin-state", templateContext, "/",
+                    XPathConstants.NODE);
+            XPath xp = XPathFactory.newInstance().newXPath();
+
+            // If OK element exists then it worked.
+            Node ok = (Node) xp.evaluate("/rpc-reply/ok", req, XPathConstants.NODE);
+            return CompletableFuture.completedFuture(ok != null);
+        } catch (XPathExpressionException | NetconfException e) {
+            log.error("Unable to set port admin state for port {} to {}", number, handler().data().deviceId(), value,
+                    e);
+        }
+        return CompletableFuture.completedFuture(false);
+
+    }
+
+    @Override
+    public CompletableFuture<Boolean> enable(PortNumber number) {
+        return setAdminState(number, true);
+    }
+
+    @Override
+    public CompletableFuture<Boolean> disable(PortNumber number) {
+        return setAdminState(number, false);
+    }
+
+    @Override
+    public CompletableFuture<Boolean> isEnabled(PortNumber number) {
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+
+        try {
+            Map<String, Object> templateContext = new HashMap<String, Object>();
+            templateContext.put("port-number", number.toString());
+            Node port = TEMPLATE_MANAGER.doRequest(session, "logicalPort", templateContext);
+            XPath xp = XPathFactory.newInstance().newXPath();
+            return CompletableFuture.completedFuture(Boolean.valueOf(xp.evaluate("admin-status/text()", port)));
+        } catch (XPathExpressionException | NetconfException e) {
+            log.error("Unable to query port state for port {} from device {}", number, handler().data().deviceId(), e);
+        }
+        return CompletableFuture.completedFuture(false);
+    }
+
+}
diff --git a/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/package-info.java b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/package-info.java
new file mode 100644
index 0000000..c83062b
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/netconf/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Ciena device drivers.
+ */
+package org.onosproject.drivers.ciena.c5162.netconf;
diff --git a/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/package-info.java b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/package-info.java
new file mode 100644
index 0000000..54ff1a2
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/java/org/onosproject/drivers/ciena/c5162/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Ciena device drivers.
+ */
+package org.onosproject.drivers.ciena.c5162;
diff --git a/drivers/ciena/c5162/src/main/resources/ciena-5162-drivers.xml b/drivers/ciena/c5162/src/main/resources/ciena-5162-drivers.xml
new file mode 100644
index 0000000..c0bcc4d
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/resources/ciena-5162-drivers.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<drivers>
+    <driver name="ciena-5162-netconf" manufacturer="Ciena" hwVersion="1.0.0" swVersion="1.0.0">
+        <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
+            impl="org.onosproject.drivers.ciena.c5162.netconf.Ciena5162DeviceDescription"/>
+        <behaviour api="org.onosproject.net.behaviour.PortAdmin"
+           impl="org.onosproject.drivers.ciena.c5162.netconf.Ciena5162PortAdmin"/>
+        <behaviour api="org.onosproject.net.device.PortStatisticsDiscovery"
+            impl="org.onosproject.drivers.ciena.c5162.netconf.Ciena5162DeviceDescription"/>
+        <behaviour api="org.onosproject.net.behaviour.LinkDiscovery"
+            impl="org.onosproject.drivers.ciena.c5162.netconf.Ciena5162DeviceDescription"/>
+<!--
+        <behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
+                   impl="org.onosproject.drivers.ciena.c5162.netconf.Ciena5162FlowRuleProgrammable"/>
+        <behaviour api="org.onosproject.net.behaviour.LambdaQuery"
+                   impl="org.onosproject.drivers.ciena.c5162.netconf.Ciena5162LambdaQuery"/>
+        <behaviour api="org.onosproject.incubator.net.faultmanagement.alarm.AlarmConsumer"
+                   impl="org.onosproject.drivers.ciena.c5162.netconf.Ciena5162AlarmConsumer"/>
+-->
+    </driver>
+</drivers>
+
diff --git a/drivers/ciena/c5162/src/main/resources/templates/requests/link-info.j2 b/drivers/ciena/c5162/src/main/resources/templates/requests/link-info.j2
new file mode 100644
index 0000000..b43f85f
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/resources/templates/requests/link-info.j2
@@ -0,0 +1,16 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <oc-if:interfaces xmlns:oc-if="http://openconfig.net/yang/interfaces" xmlns:c-pn="urn:ciena:params:xml:ns:yang:ciena-pn::ciena-ieee-lldp">
+        <oc-if:interface>
+          <oc-if:config>
+            <tt:type xmlns:tt="http://ciena.com/ns/yang/ciena-openconfig-interfaces" />
+          </oc-if:config>
+          <oc-if:state>
+            <c-pn:lldp-remote-port-operational/>
+          </oc-if:state>
+        </oc-if:interface>
+      </oc-if:interfaces>
+    </filter>
+  </get>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5162/src/main/resources/templates/requests/logicalPort.j2 b/drivers/ciena/c5162/src/main/resources/templates/requests/logicalPort.j2
new file mode 100644
index 0000000..2e7223e
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/resources/templates/requests/logicalPort.j2
@@ -0,0 +1,11 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <oc-if:interfaces xmlns:oc-if="http://openconfig.net/yang/interfaces">
+        <oc-if:interface>
+          <oc-if:name>{{port-number}}</oc-if:name>
+        </oc-if:interface>
+      </oc-if:interfaces>
+    </filter>
+  </get>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5162/src/main/resources/templates/requests/logicalPorts.j2 b/drivers/ciena/c5162/src/main/resources/templates/requests/logicalPorts.j2
new file mode 100644
index 0000000..bd2a0c0
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/resources/templates/requests/logicalPorts.j2
@@ -0,0 +1,9 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <oc-if:interfaces xmlns:oc-if="http://openconfig.net/yang/interfaces">
+        <oc-if:interface/>
+      </oc-if:interfaces>
+    </filter>
+  </get>
+</rpc>
diff --git a/drivers/ciena/c5162/src/main/resources/templates/requests/port-admin-state.j2 b/drivers/ciena/c5162/src/main/resources/templates/requests/port-admin-state.j2
new file mode 100644
index 0000000..3d0b02b
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/resources/templates/requests/port-admin-state.j2
@@ -0,0 +1,17 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <running />
+        </target>
+        <config>
+            <interfaces xmlns="http://openconfig.net/yang/interfaces" xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx">
+                <interface>
+                    <name>{{port-number}}</name>
+                    <config>
+                        <admin-status xmlns="http://ciena.com/ns/yang/ciena-openconfig-interfaces">{{admin-state}}</admin-status>
+                    </config>
+                </interface>
+            </interfaces>
+        </config>
+    </edit-config>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5162/src/main/resources/templates/requests/port-stats.j2 b/drivers/ciena/c5162/src/main/resources/templates/requests/port-stats.j2
new file mode 100644
index 0000000..e416a9e
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/resources/templates/requests/port-stats.j2
@@ -0,0 +1,16 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <get>
+        <filter type="subtree">
+            <oc-if:interfaces xmlns:oc-if="http://openconfig.net/yang/interfaces">
+                <oc-if:interface>
+                    <oc-if:config>
+                        <tt:type xmlns:tt="http://ciena.com/ns/yang/ciena-openconfig-interfaces" />
+                    </oc-if:config>
+                    <oc-if:state>
+                        <oc-if:counters />
+                    </oc-if:state>
+                </oc-if:interface>
+            </oc-if:interfaces>
+        </filter>
+    </get>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5162/src/main/resources/templates/requests/softwareVersion.j2 b/drivers/ciena/c5162/src/main/resources/templates/requests/softwareVersion.j2
new file mode 100644
index 0000000..4b17bb4
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/resources/templates/requests/softwareVersion.j2
@@ -0,0 +1,11 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <ciena-software-mgmt:software-state xmlns:ciena-software-mgmt="http://www.ciena.com/ns/yang/ciena-software-mgmt">
+        <ciena-software-mgmt:running-package>
+          <ciena-software-mgmt:package-version/>
+        </ciena-software-mgmt:running-package>
+      </ciena-software-mgmt:software-state>
+    </filter>
+  </get>
+</rpc>
diff --git a/drivers/ciena/c5162/src/main/resources/templates/requests/systemInfo.j2 b/drivers/ciena/c5162/src/main/resources/templates/requests/systemInfo.j2
new file mode 100644
index 0000000..ba8203f
--- /dev/null
+++ b/drivers/ciena/c5162/src/main/resources/templates/requests/systemInfo.j2
@@ -0,0 +1,22 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <oc-platform:components xmlns:oc-platform="http://openconfig.net/yang/platform">
+        <oc-platform:component>
+          <oc-platform:name>5162</oc-platform:name>
+          <oc-platform:state>
+            <oc-platform:name/>
+            <oc-platform:mfg-name/>
+            <oc-platform:serial-no/>
+            <oc-platform:version/>
+          </oc-platform:state>
+          <oc-platform:properties>
+            <oc-platform:property>
+                <oc-platform:name>base-mac</oc-platform:name>
+            </oc-platform:property>
+          </oc-platform:properties>
+        </oc-platform:component>
+      </oc-platform:components>
+    </filter>
+  </get>
+</rpc>
diff --git a/drivers/ciena/c5170/BUCK b/drivers/ciena/c5170/BUCK
new file mode 100644
index 0000000..8c4ea6e
--- /dev/null
+++ b/drivers/ciena/c5170/BUCK
@@ -0,0 +1,46 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+    '//lib:JACKSON',
+    '//lib:javax.ws.rs-api',
+    '//incubator/api:onos-incubator-api',
+    '//utils/rest:onlab-rest',
+    '//drivers/utilities:onos-drivers-utilities',
+    '//drivers/netconf:onos-drivers-netconf',
+    '//protocols/netconf/api:onos-protocols-netconf-api',
+]
+
+TEST_DEPS = [
+    '//lib:TEST_ADAPTERS',
+    '//core/api:onos-api-tests',
+    '//drivers/netconf:onos-drivers-netconf-tests',
+]
+
+BUNDLES = [
+    ':onos-drivers-ciena-c5170',
+    '//drivers/utilities:onos-drivers-utilities',
+    '//drivers/netconf:onos-drivers-netconf',
+]
+
+REQUIRED_APPS = [
+    'org.onosproject.linkdiscovery',
+    'org.onosproject.netconf',
+    'org.onosproject.netconfsb',
+    'org.onosproject.drivers.netconf'
+]
+
+osgi_jar_with_tests (
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+    resources_root = 'src/main/resources',
+    resources = glob(['src/main/resources/**']),
+)
+
+onos_app (
+    app_name = 'org.onosproject.drivers.ciena.c5170',
+    title = 'Ciena 5170 Drivers',
+    category = 'Drivers',
+    url = 'http://onosproject.org',
+    description = 'Adds support for Ciena 5170 devices.',
+    included_bundles = BUNDLES,
+    required_apps = REQUIRED_APPS,
+)
diff --git a/drivers/ciena/c5170/README.md b/drivers/ciena/c5170/README.md
new file mode 100644
index 0000000..5f46635
--- /dev/null
+++ b/drivers/ciena/c5170/README.md
@@ -0,0 +1,66 @@
+# Ciena 5170
+
+This driver allows connection to the Ciena 5170
+
+The User Guide for this product is available on request from Ciena, and gives a full explanation of the theory of operation, functionality and how all functions can be accessed through the REST interface.
+
+Currently only a subset of it's functionality is supported through ONOS, but this will expand to full functionality in future releases.
+
+More information about ONOS's NETCONF support can be found at `https://wiki.onosproject.org/display/ONOS/NETCONF`.
+
+## Compile and Installation
+
+Currently this driver is built using BUCK and uses version 2.1 of onos-yang-tools<br/>
+
+All that is required to activate the driver is to run the following at the ONOS CLI
+
+```bash
+app activate org.onosproject.drivers.ciena.c5170
+```
+
+## Usage
+
+### Creating Devices
+
+Ciena 5170 Devices are not Openflow devices. The connectivity is initiated from ONOS. They have to be created through the network/configuration interface in ONOS.
+
+* The name must follow the format **netconf:ipaddr:port**
+* The **ip** and **port** must correspond to the ip and port in the name (above).
+* The **connect-timeout** and **reply-timeout** are optional and control NETCONF communication timeouts
+* The **name** is optional and allows you to set a human friendly name for the device
+
+```bash
+curl -X POST
+  http://onos-ip:8181/onos/v1/network/configuration
+  -H 'Authorization: Basic b25vczpyb2Nrcw==' \
+  -H 'Content-Type: application/json' \
+  -d '{
+    "devices": {
+      "netconf:10.184.136.181:830": {
+        "netconf": {
+          "port": 830,
+          "ip": "10.184.136.181",
+          "username": "su",
+          "password": "cws",
+          "connect-timeout": 120,
+          "reply-timeout": 640
+        },
+        "basic": {
+          "driver": "ciena-c5170-netconf",
+          "name": "my-switch"
+        }
+      }
+    }
+}'
+```
+
+
+
+#### Verify Connected Device
+
+When the 5170 is configured and connected is should be visible in ONOS through the `devices` command.
+
+```bash 
+onos> devices 
+id=netconf:10.184.136.181:830, available=true, local-status=connected 1s ago, role=MASTER, type=SWITCH, mfr=Ciena, hw=CN5170, sw=saos-01-01-00-0025, serial=1C1161D18800, driver=ciena-5170-netconf, gridX=null, gridY=null, ipaddress=10.184.136.181, latitude=null, locType=none, longitude=null, name=s6, port=830, protocol=NETCONF
+```
diff --git a/drivers/ciena/c5170/features.xml b/drivers/ciena/c5170/features.xml
new file mode 100644
index 0000000..1e78782
--- /dev/null
+++ b/drivers/ciena/c5170/features.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+    <feature name="${project.artifactId}" version="${project.version}"
+             description="${project.description}">
+        <feature>onos-api</feature>
+        <bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-drivers-utilities/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-drivers-netconf/${project.version}</bundle>
+    </feature>
+</features>
diff --git a/drivers/ciena/c5170/pom.xml b/drivers/ciena/c5170/pom.xml
new file mode 100644
index 0000000..64f09d1
--- /dev/null
+++ b/drivers/ciena/c5170/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ 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. -->
+
+<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-drivers-general</artifactId>
+		<groupId>org.onosproject</groupId>
+		<version>1.14.0-SNAPSHOT</version>
+		<relativePath>../../pom.xml</relativePath>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+
+	<artifactId>onos-drivers-ciena-c5170</artifactId>
+	<packaging>bundle</packaging>
+
+	<description>Ciena 5170 device drivers</description>
+
+	<properties>
+		<onos.app.name>org.onosproject.drivers.ciena.c5170</onos.app.name>
+		<onos.app.origin>ONOS Community</onos.app.origin>
+		<onos.app.title>Ciena 5170 Device Drivers</onos.app.title>
+		<onos.app.category>Drivers</onos.app.category>
+		<onos.app.url>http://onosproject.org</onos.app.url>
+		<onos.app.requires>
+			org.onosproject.netconf
+		</onos.app.requires>
+		<jinjava.version>2.4.0</jinjava.version>
+		<jsoup.version>1.8.1</jsoup.version>
+		<juel.version>2.2.7</juel.version>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.onosproject</groupId>
+			<artifactId>onos-drivers-utilities</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.onosproject</groupId>
+			<artifactId>onos-protocols-netconf-api</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.onosproject</groupId>
+			<artifactId>onos-drivers-netconf</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+	</dependencies>
+
+</project>
diff --git a/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/Ciena5170DriversLoader.java b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/Ciena5170DriversLoader.java
new file mode 100644
index 0000000..759d24d
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/Ciena5170DriversLoader.java
@@ -0,0 +1,30 @@
+/*
+ * 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.ciena.c5170;
+
+import org.apache.felix.scr.annotations.Component;
+import org.onosproject.net.driver.AbstractDriverLoader;
+
+/**
+ * Loader for Ciena device drivers.
+ */
+@Component(immediate = true)
+public class Ciena5170DriversLoader extends AbstractDriverLoader {
+
+    public Ciena5170DriversLoader() {
+        super("/ciena-5170-drivers.xml");
+    }
+}
diff --git a/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/Ciena5170DeviceDescription.java b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/Ciena5170DeviceDescription.java
new file mode 100644
index 0000000..2841310
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/Ciena5170DeviceDescription.java
@@ -0,0 +1,269 @@
+/*
+ * 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.ciena.c5170.netconf;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.onlab.packet.ChassisId;
+import org.onosproject.drivers.netconf.TemplateManager;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.LinkDiscovery;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.DefaultPortStatistics;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.device.PortStatistics;
+import org.onosproject.net.device.PortStatisticsDiscovery;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.link.DefaultLinkDescription;
+import org.onosproject.net.link.LinkDescription;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Discovers the ports from a Ciena WaveServer Rest device.
+ */
+public class Ciena5170DeviceDescription extends AbstractHandlerBehaviour
+        implements DeviceDescriptionDiscovery, PortStatisticsDiscovery, LinkDiscovery {
+    private static final TemplateManager TEMPLATE_MANAGER = new TemplateManager();
+
+    static {
+        TEMPLATE_MANAGER.load(Ciena5170DeviceDescription.class, "/templates/requests/%s.j2", "systemInfo",
+                "chassis-mac", "softwareVersion", "logicalPorts", "port-stats", "link-info");
+    }
+
+    private static final Logger log = getLogger(Ciena5170DeviceDescription.class);
+
+    @Override
+    public DeviceDescription discoverDeviceDetails() {
+
+        DeviceId deviceId = handler().data().deviceId();
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        try {
+            Node systemInfo = TEMPLATE_MANAGER.doRequest(session, "systemInfo");
+            Node chassisMac = TEMPLATE_MANAGER.doRequest(session, "chassis-mac");
+            Node softwareVersion = TEMPLATE_MANAGER.doRequest(session, "softwareVersion");
+            XPath xp = XPathFactory.newInstance().newXPath();
+            String mac = xp.evaluate("lldp-global-operational/chassis-id/text()", chassisMac).toUpperCase();
+            return new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH, "Ciena",
+                    xp.evaluate("components/component/name/text()", systemInfo),
+                    xp.evaluate("software-state/running-package/package-version/text()", softwareVersion), mac,
+                    new ChassisId(Long.valueOf(mac, 16)));
+
+        } catch (XPathExpressionException | NetconfException ne) {
+            log.error("failed to query system info from device {} : {}", handler().data().deviceId(), ne.getMessage(),
+                    ne);
+        }
+
+        return new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH, "Ciena", "5170", "Unknown", "Unknown",
+                new ChassisId());
+    }
+
+    /**
+     * Convert the specification of port speed in the of of #unit, i.e. {@10G} to MB
+     * as represented by a Long.
+     *
+     * @param ps
+     *            specification of port speed
+     * @return port speed as MBs
+     */
+    private Long portSpeedToLong(String ps) {
+        String value = ps.trim();
+        StringBuilder digits = new StringBuilder();
+        String unit = "";
+        for (int i = 0; i < value.length(); i += 1) {
+            final char c = value.charAt(i);
+            if (Character.isDigit(c)) {
+                digits.append(c);
+            } else {
+                unit = value.substring(i).toUpperCase().trim();
+                break;
+            }
+        }
+
+        switch (unit) {
+        case "G":
+        case "GB":
+            return Long.valueOf(digits.toString()) * 1000;
+        case "M":
+        case "MB":
+        default:
+            return Long.valueOf(digits.toString());
+        }
+    }
+
+    @Override
+    public List<PortDescription> discoverPortDetails() {
+        List<PortDescription> ports = new ArrayList<PortDescription>();
+        DeviceId deviceId = handler().data().deviceId();
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        if (controller == null || controller.getDevicesMap() == null
+                || controller.getDevicesMap().get(deviceId) == null) {
+            log.warn("NETCONF session to device {} not yet established, will be retried", deviceId);
+            return ports;
+        }
+        NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
+
+        try {
+            Node logicalPorts = TEMPLATE_MANAGER.doRequest(session, "logicalPorts");
+            XPath xp = XPathFactory.newInstance().newXPath();
+            NodeList nl = (NodeList) xp.evaluate("interfaces/interface/config", logicalPorts, XPathConstants.NODESET);
+            int count = nl.getLength();
+            Node node;
+            for (int i = 0; i < count; i += 1) {
+                node = nl.item(i);
+                if (xp.evaluate("type/text()", node).equals("ettp")) {
+                    ports.add(DefaultPortDescription.builder()
+                            .withPortNumber(PortNumber.portNumber(xp.evaluate("name/text()", node)))
+                            .isEnabled(Boolean.valueOf(xp.evaluate("admin-status/text()", node)))
+                            .portSpeed(portSpeedToLong(xp.evaluate("port-speed/text()", node))).type(Port.Type.PACKET)
+                            .build());
+                }
+            }
+        } catch (NetconfException | XPathExpressionException e) {
+            log.error("Unable to retrieve port information for device {}, {}", deviceId, e);
+        }
+        return ports;
+    }
+
+    @Override
+    public Collection<PortStatistics> discoverPortStatistics() {
+        List<PortStatistics> stats = new ArrayList<PortStatistics>();
+
+        DeviceId deviceId = handler().data().deviceId();
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        if (controller == null || controller.getDevicesMap() == null
+                || controller.getDevicesMap().get(deviceId) == null) {
+            log.warn("NETCONF session to device {} not yet established, will be retried", deviceId);
+            return stats;
+        }
+        NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
+
+        try {
+            Node data = TEMPLATE_MANAGER.doRequest(session, "port-stats");
+            XPath xp = XPathFactory.newInstance().newXPath();
+            NodeList interfaces = (NodeList) xp.evaluate("interfaces/interface", data, XPathConstants.NODESET);
+            int count = interfaces.getLength();
+            for (int i = 0; i < count; i += 1) {
+                Node iface = interfaces.item(i);
+                if (xp.evaluate("config/type/text()", iface).equals("ettp")) {
+                    stats.add(DefaultPortStatistics.builder().setDeviceId(deviceId)
+                            .setPort(PortNumber.portNumber(xp.evaluate("name/text()", iface)))
+                            .setBytesReceived(Long.valueOf(xp.evaluate("state/counters/in-octets/text()", iface)))
+                            .setBytesSent(Long.valueOf(xp.evaluate("state/counters/out-octets/text()", iface)))
+                            .setPacketsReceived(Long.valueOf(xp.evaluate("state/counters/in-pkts/text()", iface)))
+                            .setPacketsSent(Long.valueOf(xp.evaluate("state/counters/out-pkts/text()", iface)))
+                            .setPacketsTxErrors(Long.valueOf(xp.evaluate("state/counters/out-errors/text()", iface)))
+                            .setPacketsRxErrors(Long.valueOf(xp.evaluate("state/counters/in-errors/text()", iface)))
+                            .build());
+                }
+            }
+        } catch (NetconfException | XPathExpressionException e) {
+            log.error("Unable to retrieve port statistics for device {}, {}", deviceId, e);
+        }
+
+        return stats;
+    }
+
+    @Override
+    public Set<LinkDescription> getLinks() {
+        log.debug("LINKS CHECKING ...");
+        Set<LinkDescription> links = new HashSet<LinkDescription>();
+        DeviceId deviceId = handler().data().deviceId();
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        if (controller == null || controller.getDevicesMap() == null
+                || controller.getDevicesMap().get(deviceId) == null) {
+            log.warn("NETCONF session to device {} not yet established, cannot load links, will be retried", deviceId);
+            return links;
+        }
+        NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
+        try {
+
+            DeviceService deviceService = this.handler().get(DeviceService.class);
+
+            Iterable<Device> devices = deviceService.getAvailableDevices();
+            Map<String, Device> lookup = new HashMap<String, Device>();
+            for (Device d : devices) {
+                lookup.put(d.chassisId().toString().toUpperCase(), d);
+            }
+
+            Node logicalPorts = TEMPLATE_MANAGER.doRequest(session, "link-info");
+            XPath xp = XPathFactory.newInstance().newXPath();
+            NodeList ifaces = (NodeList) xp.evaluate("interfaces/interface", logicalPorts, XPathConstants.NODESET);
+            int count = ifaces.getLength();
+            Node iface;
+            Node destChassis;
+            for (int i = 0; i < count; i += 1) {
+                iface = ifaces.item(i);
+                if (xp.evaluate("config/type/text()", iface).equals("ettp")) {
+                    destChassis = (Node) xp.evaluate("state/lldp-remote-port-operational/chassis-id", iface,
+                            XPathConstants.NODE);
+
+                    if (destChassis != null) {
+                        Device dest = lookup.get(destChassis.getTextContent().toUpperCase());
+
+                        if (dest != null) {
+
+                            links.add(new DefaultLinkDescription(
+                                    new ConnectPoint(deviceId,
+                                            PortNumber.portNumber(xp.evaluate("name/text()", iface))),
+                                    new ConnectPoint(dest.id(),
+                                            PortNumber.portNumber(xp.evaluate(
+                                                    "state/lldp-remote-port-operational/port-id/text()", iface))),
+                                    Link.Type.DIRECT, true));
+                        } else {
+                            log.error("DEST CHASSIS is NULL for {}", xp.evaluate("name/text()", iface));
+                        }
+                    } else {
+                        log.debug("NO LINK for {}", xp.evaluate("name/text()", iface));
+                    }
+                }
+            }
+        } catch (NetconfException | XPathExpressionException e) {
+            log.error("Unable to retrieve links for device {}, {}", deviceId, e);
+        }
+
+        return links;
+    }
+
+}
diff --git a/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/Ciena5170PortAdmin.java b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/Ciena5170PortAdmin.java
new file mode 100644
index 0000000..1a5fdf4
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/Ciena5170PortAdmin.java
@@ -0,0 +1,113 @@
+/*
+ * 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.ciena.c5170.netconf;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.onosproject.drivers.netconf.TemplateManager;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.PortAdmin;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.w3c.dom.Node;
+
+/**
+ * Handles port administration for Ciena 5170 devices using the NETCONF
+ * protocol.
+ */
+public class Ciena5170PortAdmin extends AbstractHandlerBehaviour implements PortAdmin {
+
+    public static final Logger log = getLogger(Ciena5170PortAdmin.class);
+
+    private static final TemplateManager TEMPLATE_MANAGER = new TemplateManager();
+
+    static {
+        TEMPLATE_MANAGER.load(Ciena5170PortAdmin.class, "/templates/requests/%s.j2", "logicalPort", "port-admin-state");
+    }
+
+    /**
+     * Sets the administrative state of the given port to the given value.
+     *
+     * @param number
+     *            port number
+     * @param value
+     *            state, true for enabled, false for disabled
+     * @return true if successfully set
+     */
+    private CompletableFuture<Boolean> setAdminState(PortNumber number, Boolean value) {
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+
+        try {
+            Map<String, Object> templateContext = new HashMap<String, Object>();
+            templateContext.put("port-number", number.toLong());
+            templateContext.put("admin-state", value.toString());
+            Node req = (Node) TEMPLATE_MANAGER.doRequest(session, "port-admin-state", templateContext, "/",
+                    XPathConstants.NODE);
+            XPath xp = XPathFactory.newInstance().newXPath();
+
+            // If OK element exists then it worked.
+            Node ok = (Node) xp.evaluate("/rpc-reply/ok", req, XPathConstants.NODE);
+            return CompletableFuture.completedFuture(ok != null);
+        } catch (XPathExpressionException | NetconfException e) {
+            log.error("Unable to set port admin state for port {} to {}", number, handler().data().deviceId(), value,
+                    e);
+        }
+        return CompletableFuture.completedFuture(false);
+
+    }
+
+    @Override
+    public CompletableFuture<Boolean> enable(PortNumber number) {
+        return setAdminState(number, true);
+    }
+
+    @Override
+    public CompletableFuture<Boolean> disable(PortNumber number) {
+        return setAdminState(number, false);
+    }
+
+    @Override
+    public CompletableFuture<Boolean> isEnabled(PortNumber number) {
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+
+        try {
+            Map<String, Object> templateContext = new HashMap<String, Object>();
+            templateContext.put("port-number", number.toString());
+            Node port = TEMPLATE_MANAGER.doRequest(session, "logicalPort", templateContext);
+            XPath xp = XPathFactory.newInstance().newXPath();
+            return CompletableFuture.completedFuture(Boolean.valueOf(xp.evaluate("admin-status/text()", port)));
+        } catch (XPathExpressionException | NetconfException e) {
+            log.error("Unable to query port state for port {} from device {}", number, handler().data().deviceId(), e);
+        }
+        return CompletableFuture.completedFuture(false);
+    }
+
+}
diff --git a/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/package-info.java b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/package-info.java
new file mode 100644
index 0000000..3fabb9c
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/netconf/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Ciena device drivers.
+ */
+package org.onosproject.drivers.ciena.c5170.netconf;
diff --git a/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/package-info.java b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/package-info.java
new file mode 100644
index 0000000..64c1d0f
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/java/org/onosproject/drivers/ciena/c5170/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Ciena device drivers.
+ */
+package org.onosproject.drivers.ciena.c5170;
diff --git a/drivers/ciena/c5170/src/main/resources/ciena-5170-drivers.xml b/drivers/ciena/c5170/src/main/resources/ciena-5170-drivers.xml
new file mode 100644
index 0000000..0589873
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/ciena-5170-drivers.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<drivers>
+    <driver name="ciena-5170-netconf" manufacturer="Ciena" hwVersion="1.0.0" swVersion="1.0.0">
+        <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
+            impl="org.onosproject.drivers.ciena.c5170.netconf.Ciena5170DeviceDescription"/>
+        <behaviour api="org.onosproject.net.behaviour.PortAdmin"
+           impl="org.onosproject.drivers.ciena.c5170.netconf.Ciena5170PortAdmin"/>
+        <behaviour api="org.onosproject.net.device.PortStatisticsDiscovery"
+            impl="org.onosproject.drivers.ciena.c5170.netconf.Ciena5170DeviceDescription"/>
+        <behaviour api="org.onosproject.net.behaviour.LinkDiscovery"
+            impl="org.onosproject.drivers.ciena.c5170.netconf.Ciena5170DeviceDescription"/>
+<!--
+        <behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
+                   impl="org.onosproject.drivers.ciena.c5170.netconf.Ciena5170FlowRuleProgrammable"/>
+        <behaviour api="org.onosproject.net.behaviour.LambdaQuery"
+                   impl="org.onosproject.drivers.ciena.c5170.netconf.Ciena5170LambdaQuery"/>
+        <behaviour api="org.onosproject.incubator.net.faultmanagement.alarm.AlarmConsumer"
+                   impl="org.onosproject.drivers.ciena.c5170.netconf.Ciena5170AlarmConsumer"/>
+-->
+    </driver>
+</drivers>
+
diff --git a/drivers/ciena/c5170/src/main/resources/templates/requests/chassis-mac.j2 b/drivers/ciena/c5170/src/main/resources/templates/requests/chassis-mac.j2
new file mode 100644
index 0000000..aa94252
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/templates/requests/chassis-mac.j2
@@ -0,0 +1,7 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <lldp-global-operational xmlns="urn:ciena:params:xml:ns:yang:ciena-pn::ciena-ieee-lldp"/>
+    </filter>
+  </get>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5170/src/main/resources/templates/requests/link-info.j2 b/drivers/ciena/c5170/src/main/resources/templates/requests/link-info.j2
new file mode 100644
index 0000000..b43f85f
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/templates/requests/link-info.j2
@@ -0,0 +1,16 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <oc-if:interfaces xmlns:oc-if="http://openconfig.net/yang/interfaces" xmlns:c-pn="urn:ciena:params:xml:ns:yang:ciena-pn::ciena-ieee-lldp">
+        <oc-if:interface>
+          <oc-if:config>
+            <tt:type xmlns:tt="http://ciena.com/ns/yang/ciena-openconfig-interfaces" />
+          </oc-if:config>
+          <oc-if:state>
+            <c-pn:lldp-remote-port-operational/>
+          </oc-if:state>
+        </oc-if:interface>
+      </oc-if:interfaces>
+    </filter>
+  </get>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5170/src/main/resources/templates/requests/logicalPort.j2 b/drivers/ciena/c5170/src/main/resources/templates/requests/logicalPort.j2
new file mode 100644
index 0000000..2e7223e
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/templates/requests/logicalPort.j2
@@ -0,0 +1,11 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <oc-if:interfaces xmlns:oc-if="http://openconfig.net/yang/interfaces">
+        <oc-if:interface>
+          <oc-if:name>{{port-number}}</oc-if:name>
+        </oc-if:interface>
+      </oc-if:interfaces>
+    </filter>
+  </get>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5170/src/main/resources/templates/requests/logicalPorts.j2 b/drivers/ciena/c5170/src/main/resources/templates/requests/logicalPorts.j2
new file mode 100644
index 0000000..bd2a0c0
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/templates/requests/logicalPorts.j2
@@ -0,0 +1,9 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <oc-if:interfaces xmlns:oc-if="http://openconfig.net/yang/interfaces">
+        <oc-if:interface/>
+      </oc-if:interfaces>
+    </filter>
+  </get>
+</rpc>
diff --git a/drivers/ciena/c5170/src/main/resources/templates/requests/port-admin-state.j2 b/drivers/ciena/c5170/src/main/resources/templates/requests/port-admin-state.j2
new file mode 100644
index 0000000..3d0b02b
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/templates/requests/port-admin-state.j2
@@ -0,0 +1,17 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <running />
+        </target>
+        <config>
+            <interfaces xmlns="http://openconfig.net/yang/interfaces" xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx">
+                <interface>
+                    <name>{{port-number}}</name>
+                    <config>
+                        <admin-status xmlns="http://ciena.com/ns/yang/ciena-openconfig-interfaces">{{admin-state}}</admin-status>
+                    </config>
+                </interface>
+            </interfaces>
+        </config>
+    </edit-config>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5170/src/main/resources/templates/requests/port-stats.j2 b/drivers/ciena/c5170/src/main/resources/templates/requests/port-stats.j2
new file mode 100644
index 0000000..e416a9e
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/templates/requests/port-stats.j2
@@ -0,0 +1,16 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <get>
+        <filter type="subtree">
+            <oc-if:interfaces xmlns:oc-if="http://openconfig.net/yang/interfaces">
+                <oc-if:interface>
+                    <oc-if:config>
+                        <tt:type xmlns:tt="http://ciena.com/ns/yang/ciena-openconfig-interfaces" />
+                    </oc-if:config>
+                    <oc-if:state>
+                        <oc-if:counters />
+                    </oc-if:state>
+                </oc-if:interface>
+            </oc-if:interfaces>
+        </filter>
+    </get>
+</rpc>
\ No newline at end of file
diff --git a/drivers/ciena/c5170/src/main/resources/templates/requests/softwareVersion.j2 b/drivers/ciena/c5170/src/main/resources/templates/requests/softwareVersion.j2
new file mode 100644
index 0000000..4b17bb4
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/templates/requests/softwareVersion.j2
@@ -0,0 +1,11 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <ciena-software-mgmt:software-state xmlns:ciena-software-mgmt="http://www.ciena.com/ns/yang/ciena-software-mgmt">
+        <ciena-software-mgmt:running-package>
+          <ciena-software-mgmt:package-version/>
+        </ciena-software-mgmt:running-package>
+      </ciena-software-mgmt:software-state>
+    </filter>
+  </get>
+</rpc>
diff --git a/drivers/ciena/c5170/src/main/resources/templates/requests/systemInfo.j2 b/drivers/ciena/c5170/src/main/resources/templates/requests/systemInfo.j2
new file mode 100644
index 0000000..17dbf37
--- /dev/null
+++ b/drivers/ciena/c5170/src/main/resources/templates/requests/systemInfo.j2
@@ -0,0 +1,22 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get>
+    <filter type="subtree">
+      <oc-platform:components xmlns:oc-platform="http://openconfig.net/yang/platform">
+        <oc-platform:component>
+          <oc-platform:name>CN5170</oc-platform:name>
+          <oc-platform:state>
+            <oc-platform:name/>
+            <oc-platform:mfg-name/>
+            <oc-platform:serial-no/>
+            <oc-platform:version/>
+          </oc-platform:state>
+          <oc-platform:properties>
+            <oc-platform:property>
+                <oc-platform:name>base-mac</oc-platform:name>
+            </oc-platform:property>
+          </oc-platform:properties>
+        </oc-platform:component>
+      </oc-platform:components>
+    </filter>
+  </get>
+</rpc>
diff --git a/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/TemplateManager.java b/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/TemplateManager.java
new file mode 100644
index 0000000..56a69bb
--- /dev/null
+++ b/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/TemplateManager.java
@@ -0,0 +1,250 @@
+/*
+ * 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.netconf;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.commons.io.IOUtils;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.google.common.io.Resources;
+
+/**
+ * Manages templates and provides utilities to execute these templates against a
+ * NETCONF session.
+ */
+public final class TemplateManager {
+    private static final Logger log = getLogger(TemplateManager.class);
+    private final Map<String, String> templates = new HashMap<String, String>();
+    private TemplateRequestDriver requestDriver;
+    public static final Map<String, Object> EMPTY_TEMPLATE_CONTEXT = new HashMap<String, Object>();
+
+    /**
+     * Internal implementation of the request driver that implements a NETCONF
+     * driver.
+     */
+    private class InternalRequestDriver implements TemplateRequestDriver {
+        @Override
+        public Object doRequest(NetconfSession session, String templateName, Map<String, Object> templateContext,
+                String baseXPath, QName returnType) throws NetconfException {
+            try {
+                String data = session.rpc(render(templates.get(templateName), templateContext)).get();
+                InputStream resp = IOUtils.toInputStream(data, StandardCharsets.UTF_8);
+                DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+                DocumentBuilder builder = builderFactory.newDocumentBuilder();
+                Document document = builder.parse(resp);
+                XPath xp = XPathFactory.newInstance().newXPath();
+                return xp.evaluate(baseXPath, document, returnType);
+            } catch (Exception e) {
+                NetconfException ne = new NetconfException(e.getMessage(), e);
+                throw ne;
+            }
+        }
+    }
+
+    /**
+     * Constructs a new template manager and loads the default templates.
+     */
+    public TemplateManager() {
+        requestDriver = new InternalRequestDriver();
+    }
+
+    /**
+     * Sets the request driver for the template manager.
+     *
+     * @param driver
+     *            the driver to use
+     */
+    public void setRequestDriver(TemplateRequestDriver driver) {
+        requestDriver = driver;
+    }
+
+    /**
+     * Loads the named templates into the template manager.
+     *
+     * @param reference
+     *            the class reference from which to load resources
+     * @param pattern
+     *            pattern to convert template name to resource path
+     * @param templateNames
+     *            list of template to load
+     */
+    public void load(Class<? extends Object> reference, String pattern, String... templateNames) {
+        for (String name : templateNames) {
+            String key = name;
+            String resource;
+
+            // If the template name begins with a '/', then assume it is a full path
+            // specification
+            if (name.charAt(0) == '/') {
+                int start = name.lastIndexOf('/') + 1;
+                int end = name.lastIndexOf('.');
+                if (end == -1) {
+                    key = name.substring(start);
+                } else {
+                    key = name.substring(start, end);
+                }
+                resource = name;
+            } else {
+                resource = String.format(pattern, name);
+            }
+
+            log.error("LOAD TEMPLATE: '{}' as '{}' from '{}", name, key, resource);
+
+            try {
+                templates.put(name,
+                        Resources.toString(Resources.getResource(reference, resource), StandardCharsets.UTF_8));
+
+            } catch (IOException ioe) {
+                log.error("Unable to load NETCONF request template '{}' from '{}'", key, resource, ioe);
+            }
+        }
+    }
+
+    /**
+     * Loads the named templates into the template manager using the default
+     * reference class and resource path pattern.
+     *
+     * @param templateMNames
+     *            list of template to load
+     */
+    public void load(String... templateMNames) {
+        load(this.getClass(), "/templates/requests/%s.j2", templateMNames);
+    }
+
+    /**
+     * Loads the named templates into the template manager using the default
+     * reference class.
+     *
+     * @param pattern
+     *            pattern to convert template name to resource path
+     * @param templateMNames
+     *            list of template to load
+     */
+    public void load(String pattern, String... templateMNames) {
+        load(this.getClass(), pattern, templateMNames);
+    }
+
+    /**
+     * Returns the named template.
+     *
+     * @param templateName
+     *            name of template to return
+     * @return template
+     */
+    public String get(String templateName) {
+        return templates.get(templateName);
+    }
+
+    /**
+     * Performs simple variable substitution into a string in likely the most
+     * inefficient way possible.
+     *
+     * @param template
+     *            template into which to substitute variables
+     * @param context
+     *            variable substitution map
+     * @return template rendered with variable substitution
+     */
+    public String render(String template, Map<String, Object> context) {
+        if (context == null) {
+            return template;
+        }
+
+        String temp = template;
+        for (Map.Entry<String, Object> e : context.entrySet()) {
+            temp = temp.replaceAll("\\{\\{ *" + e.getKey() + " *\\}\\}", e.getValue().toString());
+        }
+        return temp;
+    }
+
+    /**
+     * Executes the named NETCONF template against the specified session, returning
+     * the referenced XML node as the specified type.
+     *
+     * @param session
+     *            NETCONF serssion
+     * @param templateName
+     *            name of NETCONF request template to execute
+     * @param templateContext
+     *            variable to values substitutions to be used against templates
+     * @param baseXPath
+     *            XPath expression to specify the returned document node
+     * @param returnType
+     *            expected return type of the referenced node
+     * @return XML document node referenced by the {@code baseXPath}
+     * @throws NetconfException
+     *             if any IO, XPath, or NETCONF exception occurs
+     */
+    public Object doRequest(NetconfSession session, String templateName, Map<String, Object> templateContext,
+            String baseXPath, QName returnType) throws NetconfException {
+        return requestDriver.doRequest(session, templateName, templateContext, baseXPath, returnType);
+    }
+
+    /**
+     * Execute the named NETCONF template against the specified session returning
+     * the {@code /rpc-reply/data} section of the response document as a
+     * {@code Node}.
+     *
+     * @param session
+     *            NETCONF session
+     * @param templateName
+     *            name of NETCONF request template to execute
+     * @return XML document node that represents the NETCONF response data
+     * @throws NetconfException
+     *             if any IO, XPath, or NETCONF exception occurs
+     */
+    public Node doRequest(NetconfSession session, String templateName) throws NetconfException {
+        return (Node) doRequest(session, templateName, EMPTY_TEMPLATE_CONTEXT, "/rpc-reply/data", XPathConstants.NODE);
+    }
+
+    /**
+     * Execute the named NETCONF template with the given template context against
+     * the specified session returning the {@code /rpc-reply/data} section of the
+     * response document as a {@code Node}.
+     *
+     * @param session
+     *            NETCONF session
+     * @param templateName
+     *            name of NETCONF request template to execute
+     * @param templateContext
+     *            variables to substitute into the template
+     * @return XML document node that represents the NETCONF response data
+     * @throws NetconfException
+     *             if any IO, XPath, or NETCONF exception occurs
+     */
+    public Node doRequest(NetconfSession session, String templateName, Map<String, Object> templateContext)
+            throws NetconfException {
+        return (Node) doRequest(session, templateName, templateContext, "/rpc-reply/data", XPathConstants.NODE);
+    }
+}
diff --git a/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/TemplateRequestDriver.java b/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/TemplateRequestDriver.java
new file mode 100644
index 0000000..47c326f
--- /dev/null
+++ b/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/TemplateRequestDriver.java
@@ -0,0 +1,47 @@
+/*
+ * 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.netconf;
+
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+
+public interface TemplateRequestDriver {
+
+    /**
+     * Executes the named NETCONF template against the specified session, returning
+     * the referenced XML node as the specified type.
+     *
+     * @param session
+     *            NETCONF serssion
+     * @param templateName
+     *            name of NETCONF request template to execute
+     * @param templateContext
+     *            variable to values substitutions to be used against templates
+     * @param baseXPath
+     *            XPath expression to specify the returned document node
+     * @param returnType
+     *            expected return type of the referenced node
+     * @return XML document node referenced by the {@code baseXPath}
+     * @throws NetconfException
+     *             if any IO, XPath, or NETCONF exception occurs
+     */
+    public Object doRequest(NetconfSession session, String templateName, Map<String, Object> templateContext,
+            String baseXPath, QName returnType) throws NetconfException;
+}
diff --git a/drivers/pom.xml b/drivers/pom.xml
index 25cd060..94410d1 100644
--- a/drivers/pom.xml
+++ b/drivers/pom.xml
@@ -33,6 +33,8 @@
     <modules>
         <module>default</module>
         <module>ciena/waveserver</module>
+        <module>ciena/c5162</module>
+        <module>ciena/c5170</module>
         <module>fujitsu</module>
         <module>cisco</module>
         <module>netconf</module>
diff --git a/modules.defs b/modules.defs
index 555e32d..f597f36 100644
--- a/modules.defs
+++ b/modules.defs
@@ -92,6 +92,8 @@
     # TODO ONOS-5554 excluding from the build
     #'//drivers/bti:onos-drivers-bti-oar',
     '//drivers/ciena/waveserver:onos-drivers-ciena-waveserver-oar',
+    '//drivers/ciena/c5162:onos-drivers-ciena-c5162-oar',
+    '//drivers/ciena/c5170:onos-drivers-ciena-c5170-oar',
     # TODO in-progress '//drivers/ciena/waveserverai:onos-drivers-ciena-waveserverai-oar',
     '//drivers/cisco/netconf:onos-drivers-cisco-netconf-oar',
     '//drivers/cisco/rest:onos-drivers-cisco-rest-oar',