ONOS-7975 ODTN OpenROADM v2.2 NetConf drivers.
Change-Id: I7b4115146bfda7b0061e095ca189ea4d2e9d993d
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmAddConnection.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmAddConnection.java
new file mode 100644
index 0000000..bb39189
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmAddConnection.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+
+package org.onosproject.drivers.odtn.openroadm;
+
+import org.onosproject.net.device.DeviceService;
+
+/**
+ * Class that models an ADD connection.
+ *
+ */
+public class OpenRoadmAddConnection extends OpenRoadmConnection {
+
+ /**
+ * Constructor for an Add Connection (from a client to line ports).
+ *
+ * @param openRoadmName name of the Connection.
+ * @param xc the associated OpenRoadmFlowRule.
+ * @param deviceService ONOS device service.
+ */
+ public OpenRoadmAddConnection(String openRoadmName, OpenRoadmFlowRule xc,
+ DeviceService deviceService) {
+ super(openRoadmName, xc, deviceService);
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmCBandLambdaQuery.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmCBandLambdaQuery.java
new file mode 100644
index 0000000..89ee6d8
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmCBandLambdaQuery.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import java.util.stream.IntStream;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.LambdaQuery;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+
+/**
+ * Abstract C-band DWDM plan lambda query.
+ *
+ */
+public abstract class OpenRoadmCBandLambdaQuery
+ extends AbstractHandlerBehaviour implements LambdaQuery {
+
+ protected ChannelSpacing channelSpacing;
+ protected int lambdaCount;
+ protected int slotGranularity;
+
+ @Override
+ public Set<OchSignal> queryLambdas(PortNumber port) {
+ return IntStream.range(0, lambdaCount)
+ .mapToObj(
+ x
+ -> new OchSignal(GridType.DWDM, channelSpacing, x - (lambdaCount / 2), slotGranularity))
+ .collect(ImmutableSet.toImmutableSet());
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnection.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnection.java
new file mode 100644
index 0000000..5afaf2f
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnection.java
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ *
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+
+package org.onosproject.drivers.odtn.openroadm;
+
+import org.onlab.util.Frequency;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.FlowId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+class OpenRoadmConnectionBase {
+
+ protected static final Logger log = LoggerFactory.getLogger(OpenRoadmConnection.class);
+
+ // Parameters of the FlowRule traslated into the OpenRoadm connection
+ protected DeviceId deviceId;
+ protected FlowId id;
+ protected int priority;
+
+ protected OpenRoadmFlowRule.Type type; // enum (EXPRESS_LINK, ADD_LINK, DROP_LINK)
+ protected OchSignal ochSignal;
+ protected PortNumber inPortNumber;
+ protected PortNumber outPortNumber;
+
+ protected Port srcPort; // used to retrieve info in the annotations
+ protected Port dstPort; // used to retrieve info in the annotations
+
+ // Parameters of <roadm-connections>
+ protected String connectionName;
+ protected String opticalControlMode;
+ protected double targetOutputPower = 0.0;
+ protected String srcConnInterface; // this is an NMC interface
+ protected String dstConnInterface; // this is an NMC interface
+
+ // Parameters of associated NMC interfaces:
+ // <type>openROADM-if:networkMediaChannelConnectionTerminationPoint</type>
+ protected String srcNmcName;
+ protected String srcNmcDescription;
+ protected String srcNmcType;
+ protected String srcNmcAdministrativeState;
+ protected String srcNmcSupportingCircuitPack;
+ protected String srcNmcSupportingInterface; // this is an MC interface (express-link) or a
+ // physical-port (add-drop)
+ protected String srcNmcSupportingPort;
+ protected Frequency srcNmcFrequency; // expressed in Thz
+ protected Frequency srcNmcWidth; // expressed in Ghz
+
+ protected String dstNmcName;
+ protected String dstNmcDescription;
+ protected String dstNmcType;
+ protected String dstNmcAdministrativeState;
+ protected String dstNmcSupportingCircuitPack;
+ protected String dstNmcSupportingInterface; // this is an MC interface (express-link) or a
+ // physical-port (add-drop)
+ protected String dstNmcSupportingPort;
+ protected Frequency dstNmcFrequency; // expressed in Thz
+ protected Frequency dstNmcWidth; // expressed in Ghz
+
+ // Parameters of associated MC interfaces:
+ // <type>openROADM-if:mediaChannelTrailTerminationPoint</type>
+ protected String srcMcName;
+ protected String srcMcDescription;
+ protected String srcMcType;
+ protected String srcMcAdministrativeState;
+ protected String srcMcSupportingCircuitPack;
+ protected String srcMcSupportingInterface; // this is a physical-port
+ protected String srcMcSupportingPort;
+ protected Frequency srcMcMinFrequency; // expressed in Thz
+ protected Frequency srcMcMaxFrequency; // expressed in Thz
+
+ protected String dstMcName;
+ protected String dstMcDescription;
+ protected String dstMcType;
+ protected String dstMcAdministrativeState;
+ protected String dstMcSupportingCircuitPack;
+ protected String dstMcSupportingInterface; // this is a physical-port
+ protected String dstMcSupportingPort;
+ protected Frequency dstMcMinFrequency; // expressed in Thz
+ protected Frequency dstMcMaxFrequency; // expressed in Thz
+
+
+
+ public OpenRoadmFlowRule.Type getType() {
+ return type;
+ }
+}
+
+
+
+/**
+ * Class that models an OpenROADM connection object (Yang leaf).
+ *
+ */
+public class OpenRoadmConnection extends OpenRoadmConnectionBase {
+
+ public static final String OPENROADM_CIRCUIT_PACK_NAME = "openroadm-circuit-pack-name";
+
+ public static final String OPENROADM_PORT_NAME = "openroadm-port-name";
+
+ public static final String OPENROADM_LOGICAL_CONNECTION_POINT =
+ "openroadm-logical-connection-point";
+
+ /**
+ * Constructor.
+ *
+ * @param openRoadmName name of the Connection.
+ * @param xc the associated OpenRoadmFlowRule.
+ * @param deviceService ONOS device service.
+ */
+ public OpenRoadmConnection(String openRoadmName, OpenRoadmFlowRule xc,
+ DeviceService deviceService) {
+ connectionName = openRoadmName;
+ deviceId = xc.deviceId();
+ id = xc.id();
+ priority = xc.priority();
+
+ inPortNumber = xc.inPort();
+ outPortNumber = xc.outPort();
+ ochSignal = xc.ochSignal();
+ type = xc.type();
+
+ srcPort = deviceService.getPort(deviceId, xc.inPort());
+ dstPort = deviceService.getPort(deviceId, xc.outPort());
+
+ // Conversion from ochSignal (center frequency + diameter) to OpenRoadm
+ // Media Channel (start - end)
+ Frequency freqRadius = Frequency.ofHz(
+ xc.ochSignal().channelSpacing().frequency().asHz() / 2);
+ Frequency centerFreq = xc.ochSignal().centralFrequency();
+
+ // e.g. DEG1-TTP-RX
+ String srcTag =
+ srcPort.annotations().value(OPENROADM_LOGICAL_CONNECTION_POINT) +
+ "-" + centerFreq.asTHz();
+
+ // e.g. DEG2-TTP-TX or SRG2-PP1-TX
+ String dstTag =
+ dstPort.annotations().value(OPENROADM_LOGICAL_CONNECTION_POINT) +
+ "-" + centerFreq.asTHz();
+
+ srcMcMinFrequency = centerFreq.subtract(freqRadius);
+ srcMcMaxFrequency = centerFreq.add(freqRadius);
+ dstMcMinFrequency = srcMcMinFrequency;
+ dstMcMaxFrequency = srcMcMaxFrequency;
+ srcNmcFrequency = centerFreq;
+ dstNmcFrequency = centerFreq;
+ srcNmcWidth = xc.ochSignal().channelSpacing().frequency();
+ dstNmcWidth = xc.ochSignal().channelSpacing().frequency();
+
+ srcMcSupportingInterface =
+ "OMS-" +
+ srcPort.annotations().value(OPENROADM_LOGICAL_CONNECTION_POINT);
+ dstMcSupportingInterface =
+ "OMS-" +
+ dstPort.annotations().value(OPENROADM_LOGICAL_CONNECTION_POINT);
+
+ // Media Channel Interfaces
+ srcMcName = "MC-TTP-" + srcTag;
+ srcMcSupportingCircuitPack =
+ srcPort.annotations().value(OPENROADM_CIRCUIT_PACK_NAME);
+ srcMcSupportingPort = srcPort.annotations().value(OPENROADM_PORT_NAME);
+
+ dstMcName = "MC-TTP-" + dstTag;
+ dstMcSupportingCircuitPack =
+ dstPort.annotations().value(OPENROADM_CIRCUIT_PACK_NAME);
+ dstMcSupportingPort = dstPort.annotations().value(OPENROADM_PORT_NAME);
+
+ // Network Media Channel Interfaces
+ srcNmcName = "NMC-CTP-" + srcTag;
+ srcConnInterface = srcNmcName;
+ srcNmcSupportingInterface = srcMcName;
+ srcNmcSupportingCircuitPack =
+ srcPort.annotations().value(OPENROADM_CIRCUIT_PACK_NAME);
+ srcNmcSupportingPort = srcPort.annotations().value(OPENROADM_PORT_NAME);
+
+ dstNmcName = "NMC-CTP-" + dstTag;
+ dstConnInterface = dstNmcName;
+ dstNmcSupportingInterface = dstMcName;
+ dstNmcSupportingCircuitPack =
+ dstPort.annotations().value(OPENROADM_CIRCUIT_PACK_NAME);
+ dstNmcSupportingPort = dstPort.annotations().value(OPENROADM_PORT_NAME);
+ }
+
+ protected String getConnectionName() {
+ return connectionName;
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnectionFactory.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnectionFactory.java
new file mode 100644
index 0000000..7dda1aa
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnectionFactory.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import org.onosproject.net.device.DeviceService;
+
+/**
+ * Factory class for Connection objects based on the OpenRoadmFlowRule.
+ */
+public final class OpenRoadmConnectionFactory {
+
+ /**
+ * Static method to create an OpenROADM connection.
+ *
+ * @param openRoadmName name of the Connection.
+ * @param xc the associated OpenRoadmFlowRule.
+ * @param deviceService ONOS device service.
+ * @return the OpenRoadmConnectionObject
+ * @throws IllegalArgumentException
+ *
+ * Based on the cross-connection type, the method allocates and
+ * Add, Drop or Express connection object (or local, from client to client).
+ */
+ public static OpenRoadmConnection create(String openRoadmName,
+ OpenRoadmFlowRule xc,
+ DeviceService deviceService)
+ throws IllegalArgumentException {
+ switch (xc.type()) {
+ case EXPRESS_LINK:
+ return new OpenRoadmExpressConnection(openRoadmName, xc,
+ deviceService);
+ case ADD_LINK:
+ return new OpenRoadmAddConnection(openRoadmName, xc,
+ deviceService);
+ case DROP_LINK:
+ return new OpenRoadmDropConnection(openRoadmName, xc,
+ deviceService);
+ case LOCAL:
+ return new OpenRoadmLocalConnection(openRoadmName, xc,
+ deviceService);
+ default:
+ throw new IllegalArgumentException(
+ "Unknown OpenRoadmFlowRule type");
+ }
+ }
+
+ private OpenRoadmConnectionFactory() {
+ // Utility classes should not have a public or default constructor.
+ // [HideUtilityClassConstructor]
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDeviceDescription.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDeviceDescription.java
new file mode 100644
index 0000000..7a19fa9
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDeviceDescription.java
@@ -0,0 +1,575 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.onlab.packet.ChassisId;
+import org.onlab.util.Frequency;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.PortNumber;
+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 org.onosproject.net.intent.OpticalPathIntent;
+import org.onosproject.net.optical.device.OchPortHelper;
+import org.onosproject.net.optical.device.OmsPortHelper;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+
+import java.util.concurrent.ExecutionException;
+/**
+ * Driver Implementation of the DeviceDescrption discovery for OpenROADM.
+ */
+public class OpenRoadmDeviceDescription extends OpenRoadmNetconfHandlerBehaviour
+ implements DeviceDescriptionDiscovery {
+
+ // These annotations are added to the device and ports
+ public final class AnnotationKeys {
+ public static final String OPENROADM_NODEID = "openroadm-node-id";
+ public static final String OPENROADM_CIRCUIT_PACK_NAME =
+ "openroadm-circuit-pack-name";
+ public static final String OPENROADM_PORT_NAME = "openroadm-port-name";
+ public static final String OPENROADM_PARTNER_CIRCUIT_PACK_NAME =
+ "openroadm-partner-circuit-pack-name";
+ public static final String OPENROADM_PARTNER_PORT_NAME =
+ "openroadm-partner-port-name";
+ public static final String OPENROADM_LOGICAL_CONNECTION_POINT =
+ "openroadm-logical-connection-point";
+ private AnnotationKeys() {
+ // utility class
+ }
+ }
+
+ public static final ChannelSpacing CHANNEL_SPACING =
+ ChannelSpacing.CHL_50GHZ;
+
+
+ /*
+ * The following 2 values are not specified by the OpenROADM standard,
+ * but they are a reasonable default for a tunable C-band, defined from
+ * Channel C1 at 191.35 to C96 at 196.10 GHz (for a spacing at 50GHz)
+ */
+ public static final Frequency START_CENTER_FREQ = Frequency.ofGHz(191_350);
+ public static final Frequency STOP_CENTER_FREQ = Frequency.ofGHz(196_100);
+
+
+ public static final String OPENROADM_DEVICE_OPEN = //
+ "<org-openroadm-device xmlns=\"http://org/openroadm/device\">";
+ public static final String OPENROADM_DEVICE_CLOSE = //
+ "</org-openroadm-device>";
+
+
+ /**
+ * Builds a request to get OpenRoadm Device main node (within root).
+ *
+ * @param nodeTag the tag with the name to get e.g. <info/>
+ *
+ * @return A string with the Netconf RPC for a get with subtree info
+ */
+ private String getDeviceXmlNodeBuilder(final String nodeTag) {
+ StringBuilder filter = new StringBuilder();
+ filter.append(OPENROADM_DEVICE_OPEN);
+ filter.append(nodeTag);
+ filter.append(OPENROADM_DEVICE_CLOSE);
+ return filteredGetBuilder(filter.toString());
+ }
+
+ /**
+ * Builds a request to get Device details (<info>).
+ *
+ * @return A string with the Netconf RPC for a get with subtree info
+ */
+ private String getDeviceDetailsBuilder() {
+ return getDeviceXmlNodeBuilder("<info/>");
+ }
+
+ /**
+ * Builds a request to get Ports data (<circuit-packs>).
+ *
+ * @return A string with the Netconf RPC
+ */
+ private String getDeviceCircuitPacksBuilder() {
+ return getDeviceXmlNodeBuilder("<circuit-packs/>");
+ }
+
+ /**
+ * Builds a request to get External Links data (<external-link>).
+ *
+ * @return A string with the Netconf RPC
+ */
+ private String getDeviceExternalLinksBuilder() {
+ return getDeviceXmlNodeBuilder("<external-link/>");
+ }
+
+ /**
+ * Builds a request to get Device Degrees, config and operational data.
+ *
+ * @return A string with the Netconf RPC for a get with subtree rpcing based
+ * on /components/component/state/type being oc-platform-types:PORT
+ */
+ private String getDeviceDegreesBuilder() {
+ return getDeviceXmlNodeBuilder("<degree/>");
+ }
+
+ /**
+ * Builds a request to get Device SharedRiskGroups, config and operational
+ * data.
+ *
+ * @return A string with the Netconf RPC for a get with subtree
+ */
+ private String getDeviceSharedRiskGroupsBuilder() {
+ return getDeviceXmlNodeBuilder("<shared-risk-group/>");
+ }
+
+ /**
+ * Builds a request to get Ports data.
+ * Changed to XPath and added one based on classic filters since some agents
+ * do not support xpath filtering.
+ *
+ * @return A string with the Netconf RPC
+ */
+ private String getDeviceExternalPortsBuilderXPath() {
+ StringBuilder filter = new StringBuilder();
+ filter.append(
+ "/org-openroadm-device/circuit-packs/ports[port-qual='roadm-external']");
+ return xpathFilteredGetBuilder(filter.toString());
+ }
+
+ /**
+ * Builds a request to get Ports data.
+ *
+ * @return A string with the Netconf RPC
+ */
+ private String getDeviceExternalPortsBuilder() {
+ StringBuilder filter = new StringBuilder();
+ filter.append(OPENROADM_DEVICE_OPEN);
+ filter.append("<circuit-packs>");
+ filter.append(" <ports>");
+ filter.append(" <port-qual>roadm-external</port-qual>");
+ filter.append(" </ports>");
+ filter.append("</circuit-packs>");
+ filter.append(OPENROADM_DEVICE_CLOSE);
+ return filteredGetBuilder(filter.toString());
+ }
+
+ /**
+ * Builds a request to get External Links data.
+ *
+ * @return A string with the Netconf RPC
+ */
+ private String getDeviceExternalLinksBuilderXpath() {
+ StringBuilder filter = new StringBuilder();
+ filter.append("/org-openroadm-device/external-link");
+ return xpathFilteredGetBuilder(filter.toString());
+ }
+
+ /**
+ * Builds a request to get External Links data.
+ *
+ * @param nodeId OpenROADM node identifier.
+ * @param circuitPackName name of the circuit part of the port.
+ * @param portName name of the port.
+ * @return A string with the Netconf RPC
+ */
+ private String getDeviceExternalLinkForPortBuilderXPath(
+ String nodeId, String circuitPackName, String portName) {
+ StringBuilder filter = new StringBuilder();
+ filter.append("/org-openroadm-device/external-link[");
+ filter.append("./source/node-id='");
+ filter.append(nodeId);
+ filter.append("' and ");
+ filter.append("./source/circuit-pack-name='");
+ filter.append(circuitPackName);
+ filter.append("' and ");
+ filter.append("./source/port-name='");
+ filter.append(portName);
+ filter.append("']");
+ return xpathFilteredGetBuilder(filter.toString());
+ }
+
+ private String getDeviceExternalLinkForPortBuilder(String nodeId,
+ String circuitPackName,
+ String portName) {
+ StringBuilder filter = new StringBuilder();
+ filter.append(OPENROADM_DEVICE_OPEN);
+ filter.append("<external-link>");
+ filter.append(" <source>");
+ filter.append(" <node-id>");
+ filter.append(nodeId);
+ filter.append("</node-id>");
+ filter.append(" <circuit-pack-name>");
+ filter.append(circuitPackName);
+ filter.append("</circuit-pack-name>");
+ filter.append(" <port-name>");
+ filter.append(portName);
+ filter.append("</port-name>");
+ filter.append(" </source>");
+ filter.append("</external-link>");
+ filter.append(OPENROADM_DEVICE_CLOSE);
+ return xpathFilteredGetBuilder(filter.toString());
+ }
+
+
+ /**
+ * Returns a DeviceDescription with Device info.
+ *
+ * @return DeviceDescription or null
+ */
+ @Override
+ public DeviceDescription discoverDeviceDetails() {
+ boolean defaultAvailable = true;
+ NetconfDevice ncDevice = getNetconfDevice();
+ if (ncDevice == null) {
+ log.error("ONOS Error: Device reachable, deviceID {} is not in Map", did());
+ return null;
+ }
+ DefaultAnnotations.Builder annotationsBuilder =
+ DefaultAnnotations.builder();
+
+ // Some defaults
+ String vendor = "UNKNOWN";
+ String hwVersion = "2.2.0";
+ String swVersion = "2.2.0";
+ String serialNumber = "0x0000";
+ String chassisId = "0";
+ String nodeType = "rdm";
+
+ // Get the session, if null, at least we can use the defaults.
+ NetconfSession session = getNetconfSession(did());
+ if (session != null) {
+ try {
+ String reply = session.rpc(getDeviceDetailsBuilder()).get();
+ XMLConfiguration xconf =
+ (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+ String nodeId =
+ xconf.getString("data.org-openroadm-device.info.node-id", "");
+ if (nodeId.equals("")) {
+ log.error("[OPENROADM] {} org-openroadm-device node-id undefined, returning", did());
+ return null;
+ }
+ annotationsBuilder.set(AnnotationKeys.OPENROADM_NODEID, nodeId);
+ nodeType = xconf.getString("data.org-openroadm-device.info.node-type", "");
+ if (nodeType.equals("")) {
+ log.error("[OPENROADM] {} empty node-type", did());
+ return null;
+ }
+ vendor = xconf.getString(
+ "data.org-openroadm-device.info.vendor", vendor);
+ hwVersion = xconf.getString(
+ "data.org-openroadm-device.info.model", hwVersion);
+ swVersion = xconf.getString(
+ "data.org-openroadm-device.info.softwareVersion", swVersion);
+ serialNumber = xconf.getString(
+ "data.org-openroadm-device.info.serial-id", serialNumber);
+ chassisId = xconf.getString(
+ "data.org-openroadm-device.info.node-number", chassisId);
+
+ // GEOLOCATION
+ String longitudeStr = xconf.getString(
+ "data.org-openroadm-device.info.geoLocation.longitude");
+ String latitudeStr = xconf.getString(
+ "data.org-openroadm-device.info.geoLocation.latitude");
+ if (longitudeStr != null && latitudeStr != null) {
+ annotationsBuilder
+ .set(org.onosproject.net.AnnotationKeys.LONGITUDE,
+ longitudeStr)
+ .set(org.onosproject.net.AnnotationKeys.LATITUDE,
+ latitudeStr);
+ }
+ } catch (NetconfException | InterruptedException | ExecutionException e) {
+ log.error("[OPENROADM] {} exception", did());
+ return null;
+ }
+ } else {
+ log.debug("[OPENROADM] - No session {}", did());
+ }
+
+ log.debug("[OPENROADM] {} - VENDOR {} HWVERSION {} SWVERSION {} SERIAL {} CHASSIS {}",
+ did(), vendor, hwVersion, swVersion, serialNumber, chassisId);
+ ChassisId cid = new ChassisId(Long.valueOf(chassisId, 10));
+ /*
+ * OpenROADM defines multiple devices (node types). This driver has been tested with
+ * ROADMS, (node type, "rdm"). Other devices can also be discovered, and this code is here
+ * for future developments - untested - it is likely that the XML documents
+ * are model specific.
+ */
+ org.onosproject.net.Device.Type type;
+ if (nodeType.equals("rdm")) {
+ type = org.onosproject.net.Device.Type.ROADM;
+ } else if (nodeType.equals("ila")) {
+ type = org.onosproject.net.Device.Type.OPTICAL_AMPLIFIER;
+ } else if (nodeType.equals("xpdr")) {
+ type = org.onosproject.net.Device.Type.TERMINAL_DEVICE;
+ } else if (nodeType.equals("extplug")) {
+ type = org.onosproject.net.Device.Type.OTHER;
+ } else {
+ log.error("[OPENROADM] {} unsupported node-type", did());
+ return null;
+ }
+ DeviceDescription desc = new DefaultDeviceDescription(
+ did().uri(), type, vendor, hwVersion, swVersion, serialNumber, cid,
+ defaultAvailable, annotationsBuilder.build());
+ return desc;
+ }
+
+
+
+
+ /**
+ * Get the external links as a list of XML hieriarchical configs.
+ * @param session the NETConf session to the OpenROADM device.
+ * @return a list of hierarchical conf. each one external link.
+ */
+ List<HierarchicalConfiguration> getExternalLinks(NetconfSession session) {
+ try {
+ String reply = session.rpc(getDeviceExternalLinksBuilder()).get();
+ XMLConfiguration extLinksConf = //
+ (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+ extLinksConf.setExpressionEngine(new XPathExpressionEngine());
+ return extLinksConf.configurationsAt(
+ "/data/org-openroadm-device/external-link");
+ } catch (NetconfException | InterruptedException | ExecutionException e) {
+ log.error("[OPENROADM] {} exception getting external links", did());
+ return ImmutableList.of();
+ }
+ }
+
+
+ /**
+ * Get the circuit packs from the device as a list of XML hierarchical configs.
+ * @param session the NETConf session to the OpenROADM device.
+ * @return a list of hierarchical conf. each one circuit pack.
+ */
+ List<HierarchicalConfiguration> getCircuitPacks(NetconfSession session) {
+ try {
+ String reply = session.rpc(getDeviceCircuitPacksBuilder()).get();
+ XMLConfiguration cpConf = //
+ (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+ cpConf.setExpressionEngine(new XPathExpressionEngine());
+ return cpConf.configurationsAt(
+ "/data/org-openroadm-device/circuit-packs");
+ } catch (NetconfException | InterruptedException | ExecutionException e) {
+ log.error("[OPENROADM] {} exception getting circuit packs", did());
+ return ImmutableList.of();
+ }
+ }
+
+ /**
+ * Returns a list of PortDescriptions for the device.
+ *
+ * @return a list of descriptions.
+ */
+ @Override
+ public List<PortDescription> discoverPortDetails() {
+ NetconfSession session = getNetconfSession(did());
+ if (session == null) {
+ log.error("discoverPortDetails null session for {}", did());
+ return ImmutableList.of();
+ }
+ if (!getDevice().annotations().keys().contains("openroadm-node-id")) {
+ log.error("PortDiscovery before DeviceDiscovery, using netconf");
+ return ImmutableList.of();
+ }
+ String nodeId = getDevice().annotations().value("openroadm-node-id");
+ List<PortDescription> list = new ArrayList<PortDescription>();
+ List<HierarchicalConfiguration> circuitPacks = getCircuitPacks(session);
+ /*
+ * Iterate all the ports. We need to pass the whole circuitPacks list
+ * because some port data refers to ports in other circuit packs
+ * (reverse), in addition to pass the current circuit pack name, list of
+ * external ports etc
+ */
+ for (HierarchicalConfiguration c : circuitPacks) {
+ parsePorts(list, nodeId, // c contains the whole circuit pack
+ c.getString("circuit-pack-name"), //
+ c.configurationsAt(
+ "ports[port-qual='roadm-external']"), // ext ports
+ circuitPacks, getExternalLinks(session));
+ }
+ return list;
+ }
+
+ /**
+ * Parses port information.
+ *
+ * @param list List of port descriptions to append to.
+ * @param nodeId OpenROADM node identifier.
+ * @param circuitPackName Name of the circuit pack the ports belong to
+ * @param ports hierarchical conf containing all the ports for the circuit
+ * pack
+ * @param circuitPacks all the circuit packs (to correlate data).
+ * @param extLinks Hierarchical configuration containing all the ext.
+ * links.
+ */
+ protected void parsePorts(List<PortDescription> list, String nodeId,
+ String circuitPackName,
+ List<HierarchicalConfiguration> ports,
+ List<HierarchicalConfiguration> circuitPacks,
+ List<HierarchicalConfiguration> extLinks) {
+ checkNotNull(nodeId);
+ checkNotNull(circuitPackName);
+ for (HierarchicalConfiguration port : ports) {
+ try {
+ String portName = checkNotNull(port.getString("port-name"));
+ long portNum = Long.parseLong(port.getString("label"));
+ PortNumber pNum = PortNumber.portNumber(portNum);
+ PortNumber reversepNum = findReversePort(port, circuitPacks);
+ // To see if we have an external port
+ HierarchicalConfiguration eLink = null;
+ for (HierarchicalConfiguration extLink : extLinks) {
+ String eln =
+ checkNotNull(extLink.getString("external-link-name"));
+ String esnid =
+ checkNotNull(extLink.getString("source/node-id"));
+ String escpn =
+ checkNotNull(extLink.getString("source/circuit-pack-name"));
+ String espn =
+ checkNotNull(extLink.getString("source/port-name"));
+ if (nodeId.equals(esnid) && circuitPackName.equals(escpn) &&
+ portName.equals(espn)) {
+ eLink = extLink;
+ }
+ }
+ PortDescription pd = parsePortComponent(
+ nodeId, circuitPackName, pNum, reversepNum, port, eLink);
+ if (pd != null) {
+ list.add(pd);
+ }
+ } catch (NetconfException e) {
+ log.error("[OPENROADM] {} NetConf exception", did());
+ return;
+ }
+ }
+ }
+
+ /**
+ * Given a device port (external), return its patner/reverse port.
+ *
+ * @param thisPort the port for which we are looking for the reverse port.
+ * @param circuitPacks all the circuit packs (to correlate data).
+ * @return the port number for the reverse port.
+ * @throws NetconfException .
+ */
+ protected PortNumber
+ findReversePort(HierarchicalConfiguration thisPort,
+ List<HierarchicalConfiguration> circuitPacks)
+ throws NetconfException {
+ String partnerCircuitPackName =
+ checkNotNull(thisPort.getString("partner-port/circuit-pack-name"));
+ String partnerPortName =
+ checkNotNull(thisPort.getString("partner-port/port-name"));
+ for (HierarchicalConfiguration c : circuitPacks) {
+ if (!partnerCircuitPackName.equals(
+ c.getString("circuit-pack-name"))) {
+ continue;
+ }
+ for (HierarchicalConfiguration thatPort :
+ c.configurationsAt("ports[port-qual='roadm-external']")) {
+ String thatPortName = thatPort.getString("port-name");
+ if (partnerPortName.equals(thatPortName)) {
+ long thatPortNum =
+ Long.parseLong(thatPort.getString("label"));
+ return PortNumber.portNumber(thatPortNum);
+ }
+ }
+ }
+ // We should not reach here
+ throw new NetconfException("missing partner/reverse port info");
+ }
+
+ /**
+ * Parses a component XML doc into a PortDescription.
+ * An OMS port description is constructed from XML parsed data.
+ *
+ * @param port the port to parse
+ * @return PortDescription or null
+ */
+ private PortDescription
+ parsePortComponent(String nodeId, String circuitPackName, PortNumber pNum,
+ PortNumber reversepNum, HierarchicalConfiguration port,
+ HierarchicalConfiguration extLink) {
+ Map<String, String> annotations = new HashMap<>();
+ annotations.put(AnnotationKeys.OPENROADM_NODEID, nodeId);
+ annotations.put(AnnotationKeys.OPENROADM_CIRCUIT_PACK_NAME,
+ circuitPackName);
+ annotations.put(AnnotationKeys.OPENROADM_PORT_NAME,
+ port.getString("port-name"));
+ annotations.put(AnnotationKeys.OPENROADM_PARTNER_CIRCUIT_PACK_NAME,
+ port.getString("partner-port/circuit-pack-name", ""));
+ annotations.put(AnnotationKeys.OPENROADM_PARTNER_PORT_NAME,
+ port.getString("partner-port/port-name", ""));
+ annotations.put(AnnotationKeys.OPENROADM_LOGICAL_CONNECTION_POINT,
+ port.getString("logical-connection-point", ""));
+ // Annotate the reverse port, this is needed for bidir intents.
+ annotations.put(OpticalPathIntent.REVERSE_PORT_ANNOTATION_KEY,
+ Long.toString(reversepNum.toLong()));
+
+ // for backwards compatibility
+ annotations.put("logical-connection-point",
+ port.getString("logical-connection-point", ""));
+ // Annotate external link if we found one for this port
+ if (extLink != null) {
+ String ednid = extLink.getString("destination/node-id");
+ String edcpn = extLink.getString("destination/circuit-pack-name");
+ String edpn = extLink.getString("destination/port-name");
+ annotations.put("openroadm-external-node-id", ednid);
+ annotations.put("openroadm-external-circuit-pack-name", edcpn);
+ annotations.put("openroadm-external-port-name", edpn);
+ }
+
+ /*
+ * Declare the actual optical port:
+ * Assumptions: client ports are OCh, assumed to carry ODU4 (should be
+ * configurable)
+ */
+ if (port.getString("port-wavelength-type", "wavelength")
+ .equals("wavelength")) {
+ // OchSignal is needed for OchPortDescription constructor, but it's
+ // tunable
+ OchSignal signalId =
+ OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 3);
+ return OchPortHelper.ochPortDescription(
+ pNum, true /* enabled */, OduSignalType.ODU4, true /* tunable */,
+ signalId,
+ DefaultAnnotations.builder().putAll(annotations).build());
+ } else {
+ return OmsPortHelper.omsPortDescription(
+ pNum, true /* enabled */,
+ // Relationship : START and STOP Freq not being used (See
+ // LambdaQuery)
+ START_CENTER_FREQ, STOP_CENTER_FREQ, CHANNEL_SPACING.frequency(),
+ DefaultAnnotations.builder().putAll(annotations).build());
+ }
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDropConnection.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDropConnection.java
new file mode 100644
index 0000000..ad93359
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDropConnection.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import org.onosproject.net.device.DeviceService;
+
+/**
+ * Class that models a DROP connection.
+ *
+ */
+public class OpenRoadmDropConnection extends OpenRoadmConnection {
+
+ /**
+ * Constructor for a Drop Connection (from a line to a client port).
+ *
+ * @param openRoadmName name given to the connection.
+ * @param xc cross-connection
+ * @param deviceService ONOS device service.
+ */
+ public OpenRoadmDropConnection(String openRoadmName, OpenRoadmFlowRule xc,
+ DeviceService deviceService) {
+ super(openRoadmName, xc, deviceService);
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmExpressConnection.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmExpressConnection.java
new file mode 100644
index 0000000..8c1aad9
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmExpressConnection.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import org.onosproject.net.device.DeviceService;
+
+/**
+ * Class that models an EXPRESS connection.
+ *
+ */
+public class OpenRoadmExpressConnection extends OpenRoadmConnection {
+
+ /**
+ * Constructor for an Express connection (from line port to line port).
+ *
+ * @param openRoadmName name of the Connection.
+ * @param xc the associated OpenRoadmFlowRule.
+ * @param deviceService ONOS device service.
+ */
+ public OpenRoadmExpressConnection(String openRoadmName, OpenRoadmFlowRule xc,
+ DeviceService deviceService) {
+ super(openRoadmName, xc, deviceService);
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRule.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRule.java
new file mode 100644
index 0000000..7138ec4
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRule.java
@@ -0,0 +1,194 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
+import static org.onosproject.net.flow.criteria.Criterion.Type.OCH_SIGID;
+
+import com.google.common.base.MoreObjects;
+import java.util.List;
+import java.util.Objects;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OchSignalType;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.OchSignalCriterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+
+/**
+ * Class that models a FlowRule in an OpenROADM context.
+ *
+ */
+public class OpenRoadmFlowRule extends DefaultFlowRule {
+
+ /**
+ * Type of conenction.
+ */
+ public enum Type {
+ EXPRESS_LINK, // Degree to Degree
+ ADD_LINK, // SRG to Degree
+ DROP_LINK, // Degree to SRG
+ LOCAL // SRG to SRG
+ }
+
+ private Type type;
+
+ private PortNumber inPortNumber;
+
+ private PortNumber outPortNumber;
+
+ private OchSignal ochSignal;
+
+ private OchSignalType ochSignalType;
+
+ /**
+ * Constructor. Build an OpenRoadm flow rule from the passed rule.
+ *
+ * @param rule ONOS flow rule that we have to process
+ * @param linePorts List of ports that are line ports (degrees) used
+ * to know the Type of this connection.
+ *
+ * We store and construct attributes like interface names to support
+ * this OpenROADM connection.
+ */
+ public OpenRoadmFlowRule(FlowRule rule, List<PortNumber> linePorts) {
+ super(rule);
+
+ TrafficSelector trafficSelector = rule.selector();
+ PortCriterion pc = (PortCriterion) trafficSelector.getCriterion(IN_PORT);
+ checkArgument(pc != null, "Missing IN_PORT Criterion");
+ inPortNumber = pc.port();
+
+ // Generally, Sigtype and ochSignal could be null. This would mean e.g. a
+ // port switching connection.
+ OchSignalCriterion osc = (OchSignalCriterion) trafficSelector.getCriterion(OCH_SIGID);
+ // checkArgument(osc != null, "Missing OCH_SIGID Criterion");
+ if (osc != null) {
+ ochSignal = osc.lambda();
+ }
+
+ TrafficTreatment trafficTreatment = rule.treatment();
+ List<Instruction> instructions = trafficTreatment.immediate();
+
+ outPortNumber = instructions.stream()
+ .filter(i -> i.type() == Instruction.Type.OUTPUT)
+ .map(i -> ((OutputInstruction) i).port())
+ .findFirst()
+ .orElse(null);
+ checkArgument(outPortNumber != null, "Missing OUTPUT Instruction");
+
+ if (linePorts.contains(inPortNumber) && linePorts.contains(outPortNumber)) {
+ type = Type.EXPRESS_LINK;
+ }
+ if (!linePorts.contains(inPortNumber) && linePorts.contains(outPortNumber)) {
+ type = Type.ADD_LINK;
+ }
+ if (linePorts.contains(inPortNumber) && !linePorts.contains(outPortNumber)) {
+ type = Type.DROP_LINK;
+ }
+ if (!linePorts.contains(inPortNumber) && !linePorts.contains(outPortNumber)) {
+ type = Type.LOCAL;
+ }
+ }
+
+ /**
+ * Get the type of the connection.
+ *
+ * @return type (express, add, drop, local)
+ */
+ public Type type() {
+ return type;
+ }
+
+ /**
+ * Get the input port.
+ *
+ * @return the input port (connection source).
+ */
+ public PortNumber inPort() {
+ return inPortNumber;
+ }
+
+
+ /**
+ * Get the output port.
+ *
+ * @return the output port (connection destination).
+ */
+ public PortNumber outPort() {
+ return outPortNumber;
+ }
+
+
+ /**
+ * Get the OchSignal for this connection.
+ *
+ * @return the OchSignal.
+ */
+ public OchSignal ochSignal() {
+ return ochSignal;
+ }
+
+
+ /**
+ * Get the OchSignalType for this connection.
+ *
+ * @return the OchSignalType.
+ */
+ public OchSignalType ochSignalType() {
+ return ochSignalType;
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof OpenRoadmFlowRule)) {
+ return false;
+ }
+ OpenRoadmFlowRule that = (OpenRoadmFlowRule) o;
+ return Objects.equals(this.inPortNumber, that.inPortNumber) &&
+ Objects.equals(this.outPortNumber, that.outPortNumber) &&
+ Objects.equals(this.ochSignal, that.ochSignal) &&
+ Objects.equals(this.ochSignalType, that.ochSignalType) &&
+ Objects.equals(this.type, that.type);
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(inPortNumber, outPortNumber, ochSignal, ochSignalType, type);
+ }
+
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("type", type)
+ .add("inPortNumber", inPortNumber)
+ .add("outPortNumber", outPortNumber)
+ .add("ochSignal", ochSignal)
+ .add("ochSignalType", ochSignalType)
+ .toString();
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRuleProgrammable.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRuleProgrammable.java
new file mode 100644
index 0000000..54d5152
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRuleProgrammable.java
@@ -0,0 +1,746 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.collect.ImmutableList;
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.onlab.util.Frequency;
+import org.onlab.util.Spectrum;
+import org.onosproject.drivers.odtn.impl.DeviceConnectionCache;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OchSignalType;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleProgrammable;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of FlowRuleProgrammable interface for OpenROADM devices.
+ */
+public class OpenRoadmFlowRuleProgrammable
+ extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
+
+ private static final Logger log =
+ LoggerFactory.getLogger(OpenRoadmFlowRuleProgrammable.class);
+
+ private static final String RPC_TAG_NETCONF_BASE =
+ "<rpc xmlns='urn:ietf:params:xml:ns:netconf:base:1.0'>";
+
+ private static final String RPC_CLOSE_TAG = "</rpc>";
+
+ private static final String ORG_OPENROADM_DEVICE_OPEN_TAG =
+ "<org-openroadm-device xmlns='http://org/openroadm/device' xmlns:nc='urn:ietf:params:xml:ns:netconf:base:1.0'>";
+ private static final String ORG_OPENROADM_DEVICE_CLOSE_TAG = "</org-openroadm-device>";
+
+ /**
+ * Helper method to get the DeviceId.
+ * <p>
+ */
+ private DeviceId did() {
+ return data().deviceId();
+ }
+
+ private DeviceConnectionCache getConnectionCache() {
+ return DeviceConnectionCache.init();
+ }
+
+ /**
+ * Helper method to log from this class adding DeviceId.
+ * <p>
+ */
+ private void openRoadmLog(String format, Object... arguments) {
+ log.debug("OPENROADM {}: " + format, did(), arguments);
+ }
+
+ /**
+ * Helper method to log from this class adding DeviceId.
+ * <p>
+ */
+ private void openRoadmInfo(String format, Object... arguments) {
+ log.info("OPENROADM {}: " + format, did(), arguments);
+ }
+
+
+ /**
+ * Get a list of Port numbers that are LINE ports (degree).
+ * <p>
+ * @return list of port numbers
+ */
+ private List<PortNumber> getLinePorts() {
+ DeviceService deviceService = this.handler().get(DeviceService.class);
+ return deviceService.getPorts(did())
+ .stream()
+ .filter(
+ p -> p.annotations().value("openroadm-logical-connection-point").contains("DEG"))
+ .map(p -> p.number())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Helper method to get the Netconf Session.
+ * @return the netconf session, which may be null.
+ */
+ private NetconfSession getNetconfSession() {
+ NetconfController controller = handler().get(NetconfController.class);
+ NetconfSession session = controller.getNetconfDevice(did()).getSession();
+ return session;
+ }
+
+ /**
+ * Fetches list of connections from device.
+ *
+ * @return list of connections as XML hierarchy
+ */
+ private List<HierarchicalConfiguration> getDeviceConnections() {
+ NetconfSession session = getNetconfSession();
+ if (session == null) {
+ log.error("OPENROADM {}: session not found", did());
+ return ImmutableList.of();
+ }
+ try {
+ StringBuilder rb = new StringBuilder();
+ rb.append(ORG_OPENROADM_DEVICE_OPEN_TAG);
+ rb.append(" <roadm-connections/>");
+ rb.append(ORG_OPENROADM_DEVICE_CLOSE_TAG);
+ String reply = session.getConfig(DatastoreId.RUNNING, rb.toString());
+ log.debug("REPLY to getDeviceConnections {}", reply);
+ HierarchicalConfiguration cfg =
+ XmlConfigParser.loadXml(new ByteArrayInputStream(reply.getBytes()));
+ return cfg.configurationsAt("data.org-openroadm-device.roadm-connections");
+ } catch (NetconfException e) {
+ return ImmutableList.of();
+ }
+ }
+
+
+ /**
+ * Get the flow entries that are present on the device, called by
+ * FlowRuleDriverProvider. <p> The flow entries must match exactly the
+ * FlowRule entries in the ONOS store. If they are not an exact match the
+ * device will be requested to remove those flows.
+ *
+ * @return A collection of Flow Entries
+ */
+ @Override
+ public Collection<FlowEntry> getFlowEntries() {
+ List<HierarchicalConfiguration> conf = getDeviceConnections();
+ List<FlowEntry> entries = new ArrayList<>();
+ for (HierarchicalConfiguration c : conf) {
+ openRoadmLog("Existing connection {}", c);
+ FlowRule r = buildFlowrule(c);
+ if (r != null) {
+ FlowEntry e = new DefaultFlowEntry(r, FlowEntry.FlowEntryState.ADDED, 0, 0, 0);
+ openRoadmLog("RULE RETRIEVED {}", r);
+ entries.add(e);
+ }
+ }
+ return entries;
+ }
+
+
+ /**
+ * Apply the flow entries specified in the collection rules.
+ *
+ * @param rules A collection of Flow Rules to be applied
+ * @return The collection of added Flow Entries
+ */
+ @Override
+ public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
+ List<FlowRule> added = new ArrayList<>();
+ for (FlowRule r : rules) {
+ openRoadmLog("TO APPLY RULE {}", r);
+ OpenRoadmFlowRule xc = new OpenRoadmFlowRule(r, getLinePorts());
+ openRoadmInfo("OpenRoadmRule {}", xc);
+ if (editConfigCreateConnection(xc)) {
+ added.add(xc);
+ openRoadmLog("RULE APPLIED {}", r);
+ }
+ }
+ openRoadmLog("applyFlowRules added {}", added.size());
+ return added;
+ }
+
+
+ /**
+ * Remove the specified flow rules.
+ *
+ * @param rules A collection of Flow Rules to be removed
+ * @return The collection of removed Flow Rules
+ */
+ @Override
+ public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
+ List<FlowRule> removed = new ArrayList<>();
+ for (FlowRule r : rules) {
+ OpenRoadmFlowRule xc = new OpenRoadmFlowRule(r, getLinePorts());
+ openRoadmLog("TO REMOVE RULE {}", xc);
+ if (editConfigDeleteConnection(xc)) {
+ removed.add(r);
+ openRoadmLog("RULE REMOVED {}", r);
+ }
+ }
+ openRoadmLog("removedFlowRules removed {}", removed.size());
+ return removed;
+ }
+
+ /**
+ * Construct a connection name for a connection between two ports.
+ *
+ * @param srcPort source port, can be a degree port or a SRG port
+ * @param dstPort destination port, can be a degree port or a SRG port
+ * @param ncFreq Nominal Center freq.
+ * @return a string with the connection name.
+ *
+ * OpenROADM Connections are of the form <nmc-interface>-to-<nmc-interface>.
+ * NMC interfaces are created before the connection, directly over the SRG
+ * port or a supporting MC interface.
+ *
+ */
+ private String openRoadmConnectionName(Port srcPort, Port dstPort, Frequency ncFreq) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("NMC-CTP-");
+ sb.append(srcPort.annotations().value("openroadm-logical-connection-point"));
+ sb.append("-");
+ sb.append(ncFreq.asTHz());
+ sb.append("-to-NMC-CTP-");
+ sb.append(dstPort.annotations().value("openroadm-logical-connection-point"));
+ sb.append("-");
+ sb.append(ncFreq.asTHz());
+ return sb.toString();
+ }
+
+ /**
+ * Construct a connection name given an OpenRoadmFlowRule.
+ *
+ * @param xc the flow rule or crossconnection.
+ *
+ */
+ private String openRoadmConnectionName(OpenRoadmFlowRule xc) {
+ DeviceService deviceService = this.handler().get(DeviceService.class);
+ Port srcPort = deviceService.getPort(did(), xc.inPort());
+ Port dstPort = deviceService.getPort(did(), xc.outPort());
+ Frequency centerFreq = xc.ochSignal().centralFrequency();
+ return openRoadmConnectionName(srcPort, dstPort, centerFreq);
+ }
+
+ /**
+ * Builds a flow rule from a connection object (as XML object).
+ *
+ * @param connection the connection hierarchy
+ * @return the flow rule
+ */
+ private FlowRule buildFlowrule(HierarchicalConfiguration connection) {
+ String name = connection.getString("connection-name");
+ if (name == null) {
+ log.error("OPENROADM {}: connection name not correctly retrieved", did());
+ return null;
+ }
+ // If the flow entry is not in the cache: return null
+ FlowRule flowRule = getConnectionCache().get(did(), name);
+ if (flowRule == null) {
+ log.error("OPENROADM {}: name {} not in cache. delete editConfig", did(), name);
+ editConfigDeleteConnection(name);
+ return null;
+ } else {
+ openRoadmLog("connection retrieved {}", name);
+ }
+ OpenRoadmFlowRule xc = new OpenRoadmFlowRule(flowRule, getLinePorts());
+ DeviceService deviceService = this.handler().get(DeviceService.class);
+ OpenRoadmConnection conn = OpenRoadmConnectionFactory.create(name, xc, deviceService);
+ OchSignal och = toOchSignalCenterWidth(conn.srcNmcFrequency, conn.srcNmcWidth);
+ // Build the rule selector and treatment
+ TrafficSelector selector =
+ DefaultTrafficSelector.builder()
+ .matchInPort(conn.inPortNumber)
+ .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID))
+ .add(Criteria.matchLambda(och))
+ .build();
+ Instruction ochInstruction = Instructions.modL0Lambda(och);
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .add(ochInstruction)
+ .setOutput(conn.outPortNumber)
+ .build();
+
+ return DefaultFlowRule.builder()
+ .forDevice(data().deviceId())
+ .makePermanent()
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(conn.priority)
+ .withCookie(conn.id.value())
+ .build();
+ }
+
+
+
+ /**
+ * Delete a ROADM Interface given its name.
+ *
+ * @param interfaceName name of the interface to be removed.
+ */
+ private void editConfigDeleteInterfaceEntry(String interfaceName) {
+ checkNotNull(interfaceName);
+ StringBuilder sb = new StringBuilder();
+ sb.append(ORG_OPENROADM_DEVICE_OPEN_TAG);
+ sb.append(" <interface nc:operation='delete'>");
+ sb.append(" <name>" + interfaceName + "</name>");
+ sb.append(" </interface>");
+ sb.append(ORG_OPENROADM_DEVICE_CLOSE_TAG);
+ if (!editConfig(sb.toString())) {
+ log.error("OPENROADM {}: failed to delete interface{}", did(), interfaceName);
+ }
+ }
+
+
+
+ /**
+ * Delete a ROADM Connection given its name.
+ *
+ * @param connectionName name of the connection to be removed.
+ */
+ private void editConfigDeleteConnectionEntry(String connectionName) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ORG_OPENROADM_DEVICE_OPEN_TAG);
+ sb.append(" <roadm-connections nc:operation='delete'>");
+ sb.append(" <connection-name>" + connectionName + "</connection-name>");
+ sb.append(" </roadm-connections>");
+ sb.append(ORG_OPENROADM_DEVICE_CLOSE_TAG);
+ if (!editConfig(sb.toString())) {
+ log.error("OPENROADM {}: failed to delete Connection {}", did(), connectionName);
+ }
+ }
+
+ /**
+ * Entry point to remove a Crossconnect.
+ *
+ * @param connectionName name of the connection to be removed.
+ * @return true (an edit delete is assumed to not fail)
+ *
+ * NMC-CTP-<rx-logical-port>-<freq>-to-NMC-CTP-<tx-logical-port>-<freq>
+ * NMC-CTP-DEG1-TTP-RX-192.7-to-NMC-CTP-DEG3-TTP-TX-192.7
+ *
+ * Local:
+ * NMC-CTP-SRG1-PP1-RX-190.7-to-NMC-CTP-SRG1-PP2-TX-190.7
+ *
+ * Note this method is rarely used, only when it exists in the Datastore
+ * but not in the connection cache.
+ */
+ private boolean editConfigDeleteConnection(String connectionName) {
+ String[] nmcNames = connectionName.split("-to-");
+ // Connection src NMC interface (RX) is NMC-CTP-DEG1-TTP-RX-192.7
+ // Connection dst NMC interface (TX) is NMC-CTP-DEG3-TTP-TX-192.7
+ String nmcRxName = nmcNames[0];
+ String nmcTxName = nmcNames[1];
+ // Connection src MC interface (RX) is MC-TTP-DEG3-TTP-RX-192.7
+ // Connection dst MC interface (TX) is MC-TTP-DEG3-TTP-TX-192.7
+ String mcRxName = "MC-TTP" + nmcRxName.substring(7);
+ String mcTxName = "MC-TTP" + nmcTxName.substring(7);
+
+ // Delete Connection
+ editConfigDeleteConnectionEntry(connectionName);
+ // Delete interfaces
+ editConfigDeleteInterfaceEntry(nmcRxName);
+ editConfigDeleteInterfaceEntry(nmcTxName);
+ if (!nmcRxName.contains("SRG")) { // Source MC interfaces not in ADD
+ editConfigDeleteInterfaceEntry(mcRxName);
+ }
+ if (!nmcTxName.contains("SRG")) { // Dest MC interfaces not in ADD
+ editConfigDeleteInterfaceEntry(mcTxName);
+ }
+ return true;
+ }
+
+
+
+ /**
+ * Entry point to remove a Crossconnect.
+ *
+ * @param xc - OpenROADM flow rule (cross-connect data)
+ */
+ private boolean editConfigDeleteConnection(OpenRoadmFlowRule xc) {
+ String name = openRoadmConnectionName(xc);
+ FlowRule flowRule = getConnectionCache().get(did(), name);
+ if (flowRule == null) {
+ openRoadmLog("editConfigDeleteConnection, {} not in cache", name);
+ // What to do ? it should be in the cache
+ return true;
+ }
+ // Delete Connection
+ editConfigDeleteConnectionEntry(name);
+ // Remove connection from cache
+ getConnectionCache().remove(did(), xc);
+
+ DeviceService deviceService = this.handler().get(DeviceService.class);
+ OpenRoadmConnection conn = OpenRoadmConnectionFactory.create(name, xc, deviceService);
+
+ // Delete interfaces. Note, deletion of interfaces may fail if
+ // they are used by other connections.
+ editConfigDeleteInterfaceEntry(conn.dstNmcName);
+ editConfigDeleteInterfaceEntry(conn.srcNmcName);
+ if ((conn.getType() != OpenRoadmFlowRule.Type.ADD_LINK) &&
+ (conn.getType() != OpenRoadmFlowRule.Type.LOCAL)) {
+ editConfigDeleteInterfaceEntry(conn.srcMcName);
+ }
+ if ((conn.getType() != OpenRoadmFlowRule.Type.DROP_LINK) &&
+ (conn.getType() != OpenRoadmFlowRule.Type.LOCAL)) {
+ editConfigDeleteInterfaceEntry(conn.dstMcName);
+ }
+
+
+ return true;
+ }
+
+ /**
+ * Create a ROADM NMC Interfaces.
+ *
+ * @param conn connection to create on the device.
+ * @param operation netconf operation (e.g. merge)
+ * @return true if Netconf operation was ok, false otherwise.
+ */
+ private boolean editConfigCreateMcInterfaces(OpenRoadmConnection conn, String operation) {
+
+ openRoadmLog("Checking MC interafaces for {}", conn);
+ // clang-format off
+ // Creation of MC in Input
+ if ((conn.getType() != OpenRoadmFlowRule.Type.ADD_LINK) &&
+ (conn.getType() != OpenRoadmFlowRule.Type.LOCAL)) {
+ StringBuilder sb = new StringBuilder();
+ openRoadmLog("Creating MC SRC interface {}", conn.srcMcName);
+ sb.append(ORG_OPENROADM_DEVICE_OPEN_TAG);
+ sb.append("<interface nc:operation='" + operation + "'>");
+ sb.append(" <name>" + conn.srcMcName + "</name>");
+ sb.append(" <description>Media-Channel</description>");
+ sb.append(" <type xmlns:openROADM-if='http://org/openroadm/interfaces'>" +
+ "openROADM-if:mediaChannelTrailTerminationPoint</type>");
+ sb.append(" <administrative-state>inService</administrative-state>");
+ sb.append(" <supporting-circuit-pack-name>" +
+ conn.srcMcSupportingCircuitPack +
+ "</supporting-circuit-pack-name>");
+ sb.append(" <supporting-port>" + conn.srcMcSupportingPort + "</supporting-port>");
+ sb.append(" <supporting-interface>" + conn.srcMcSupportingInterface + "</supporting-interface>");
+ sb.append(" <mc-ttp xmlns='http://org/openroadm/media-channel-interfaces'>");
+ sb.append(" <min-freq>" + conn.srcMcMinFrequency.asTHz() + "</min-freq>");
+ sb.append(" <max-freq>" + conn.srcMcMaxFrequency.asTHz() + "</max-freq>");
+ sb.append(" </mc-ttp>");
+ sb.append("</interface>");
+ sb.append(ORG_OPENROADM_DEVICE_CLOSE_TAG);
+ if (!editConfig(sb.toString())) {
+ log.error("OPENROADM {}: failed to create interface\n {}", did(), sb.toString());
+ return false;
+ }
+ }
+ if ((conn.getType() != OpenRoadmFlowRule.Type.DROP_LINK) &&
+ (conn.getType() != OpenRoadmFlowRule.Type.LOCAL)) {
+ StringBuilder sb = new StringBuilder();
+ openRoadmLog("Creating MC DST interface {}", conn.dstMcName);
+ sb.append(ORG_OPENROADM_DEVICE_OPEN_TAG);
+ sb.append("<interface nc:operation='" + operation + "'>");
+ sb.append(" <name>" + conn.dstMcName + "</name>");
+ sb.append(" <description>Media-Channel</description>");
+ sb.append(" <type xmlns:openROADM-if='http://org/openroadm/interfaces'>" +
+ "openROADM-if:mediaChannelTrailTerminationPoint</type>");
+ sb.append(" <administrative-state>inService</administrative-state>");
+ sb.append(" <supporting-circuit-pack-name>" +
+ conn.dstMcSupportingCircuitPack +
+ "</supporting-circuit-pack-name>");
+ sb.append(" <supporting-port>" + conn.dstMcSupportingPort + "</supporting-port>");
+ sb.append(" <supporting-interface>" + conn.dstMcSupportingInterface + "</supporting-interface>");
+ sb.append(" <mc-ttp xmlns='http://org/openroadm/media-channel-interfaces'>");
+ sb.append(" <min-freq>" + conn.dstMcMinFrequency.asTHz() + "</min-freq>");
+ sb.append(" <max-freq>" + conn.dstMcMaxFrequency.asTHz() + "</max-freq>");
+ sb.append(" </mc-ttp>");
+ sb.append("</interface>");
+ sb.append(ORG_OPENROADM_DEVICE_CLOSE_TAG);
+ if (!editConfig(sb.toString())) {
+ log.error("OPENROADM {}: failed to create interface\n {}", did(), sb.toString());
+ return false;
+ }
+ }
+ // clang-format on
+ return true;
+ }
+
+ /**
+ * Create a ROADM NMC Interfaces.
+ *
+ * @param conn connection to create on the device.
+ * @param operation netconf operation (e.g. merge)
+ * @return true if Netconf operation was ok, false otherwise.
+ */
+ private boolean editConfigCreateNmcInterfaces(OpenRoadmConnection conn, String operation) {
+ // clang-format off
+ openRoadmLog("Creating NMC interfaces SRC {}", conn.srcNmcName);
+ StringBuilder sb = new StringBuilder();
+ sb.append(ORG_OPENROADM_DEVICE_OPEN_TAG);
+ sb.append("<interface nc:operation='" + operation + "'>");
+ sb.append(" <name>" + conn.srcNmcName + "</name>");
+ sb.append(" <description>Network-Media-Channel</description>");
+ sb.append(" <type xmlns:openROADM-if='http://org/openroadm/interfaces'>" +
+ "openROADM-if:networkMediaChannelConnectionTerminationPoint</type>");
+ sb.append(" <administrative-state>inService</administrative-state>");
+ sb.append(" <supporting-circuit-pack-name>" +
+ conn.srcNmcSupportingCircuitPack +
+ "</supporting-circuit-pack-name>");
+ sb.append(" <supporting-port>" + conn.srcNmcSupportingPort + "</supporting-port>");
+ if ((conn.getType() != OpenRoadmFlowRule.Type.ADD_LINK) &&
+ (conn.getType() != OpenRoadmFlowRule.Type.LOCAL)) {
+ sb.append("<supporting-interface>" + conn.srcNmcSupportingInterface + "</supporting-interface>");
+ }
+ sb.append(" <nmc-ctp xmlns='http://org/openroadm/network-media-channel-interfaces'>");
+ sb.append(" <frequency>" + conn.srcNmcFrequency.asTHz() + "</frequency>");
+ sb.append(" <width>" + conn.srcNmcWidth.asGHz() + "</width>");
+ sb.append(" </nmc-ctp>");
+ sb.append("</interface>");
+ sb.append(ORG_OPENROADM_DEVICE_CLOSE_TAG);
+ if (!editConfig(sb.toString())) {
+ log.error("OpenRoadm driver - failed to create interface");
+ return false;
+ }
+
+ openRoadmLog("Creating NMC interfaces DST {}", conn.dstNmcName);
+ sb = new StringBuilder();
+ sb.append(ORG_OPENROADM_DEVICE_OPEN_TAG);
+ sb.append("<interface nc:operation='" + operation + "'>");
+ sb.append(" <name>" + conn.dstNmcName + "</name>");
+ sb.append(" <description>Network-Media-Channel</description>");
+ sb.append(" <type xmlns:openROADM-if='http://org/openroadm/interfaces'>" +
+ "openROADM-if:networkMediaChannelConnectionTerminationPoint</type>");
+ sb.append(" <administrative-state>inService</administrative-state>");
+ sb.append(" <supporting-circuit-pack-name>" +
+ conn.dstNmcSupportingCircuitPack +
+ "</supporting-circuit-pack-name>");
+ sb.append(" <supporting-port>" + conn.dstNmcSupportingPort + "</supporting-port>");
+ if ((conn.getType() != OpenRoadmFlowRule.Type.DROP_LINK) &&
+ (conn.getType() != OpenRoadmFlowRule.Type.LOCAL)) {
+ sb.append("<supporting-interface>" + conn.dstNmcSupportingInterface + "</supporting-interface>");
+ }
+ sb.append(" <nmc-ctp xmlns='http://org/openroadm/network-media-channel-interfaces'>");
+ sb.append(" <frequency>" + conn.dstNmcFrequency.asTHz() + "</frequency>");
+ sb.append(" <width>" + conn.dstNmcWidth.asGHz() + "</width>");
+ sb.append(" </nmc-ctp>");
+ sb.append("</interface>");
+ sb.append(ORG_OPENROADM_DEVICE_CLOSE_TAG);
+ if (!editConfig(sb.toString())) {
+ log.error("OpenRoadm driver - failed to create interface");
+ return false;
+ }
+ return true;
+ // clang-format on
+ }
+
+ /**
+ * Create the MC and NMC interfaces supporting a connection.
+ *
+ * @param conn connection to create on the device.
+ * @return true if Netconf operation was ok, false otherwise.
+ */
+ private boolean editConfigCreateInterfaces(OpenRoadmConnection conn) {
+ if (!editConfigCreateMcInterfaces(conn, "merge")) {
+ return false;
+ }
+ if (!editConfigCreateNmcInterfaces(conn, "merge")) {
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Create a ROADM Connection given its data.
+ *
+ * @param conn connection to create on the device.
+ * @return true if Netconf operation was ok, false otherwise.
+ */
+ private boolean editConfigCreateConnectionEntry(OpenRoadmConnection conn,
+ String operation) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ORG_OPENROADM_DEVICE_OPEN_TAG);
+ sb.append(" <roadm-connections nc:operation='" + operation + "'>");
+ sb.append(" <connection-name>" + conn.connectionName + "</connection-name>");
+ sb.append(" <opticalControlMode>off</opticalControlMode>");
+ sb.append(" <target-output-power>0</target-output-power>");
+ sb.append(" <source>");
+ sb.append(" <src-if>" + conn.srcConnInterface + "</src-if>");
+ sb.append(" </source>");
+ sb.append(" <destination>");
+ sb.append(" <dst-if>" + conn.dstConnInterface + "</dst-if>");
+ sb.append(" </destination>");
+ sb.append(" </roadm-connections>");
+ sb.append(ORG_OPENROADM_DEVICE_CLOSE_TAG);
+ if (!editConfig(sb.toString())) {
+ log.error("OPENROADM {}: failed to create Connection {}", did(),
+ conn.connectionName);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Request the device to setup the Connection for the rule.
+
+ * @param xc - OpenRoadmFlowRule crossconnect
+ *
+ * @return true if operation was completed, false otherwise.
+ */
+ private boolean editConfigCreateConnection(OpenRoadmFlowRule xc) {
+ checkNotNull(xc);
+ String openRoadmConnectionName = openRoadmConnectionName(xc);
+ DeviceService deviceService = this.handler().get(DeviceService.class);
+ OpenRoadmConnection connection =
+ OpenRoadmConnectionFactory.create(openRoadmConnectionName, xc, deviceService);
+
+ if (!editConfigCreateInterfaces(connection)) {
+ return false;
+ }
+
+ if (!editConfigCreateConnectionEntry(connection, "merge")) {
+ return false;
+ }
+
+ // Add connection to local cache
+ getConnectionCache().add(did(), openRoadmConnectionName, xc);
+ openRoadmLog("Connection {} created", connection.connectionName);
+ return true;
+ }
+
+ /**
+ * Helper function to send an edit-config message.
+ * @param config XML string to send
+ * @return false on error, true otherwise
+ * <p>
+ * This method uses the running datastore.
+ */
+ private boolean editConfig(String config) {
+ NetconfSession session = getNetconfSession();
+ if (session == null) {
+ log.error("OPENROADM {}: session not found", did());
+ return false;
+ }
+ try {
+ return session.editConfig(DatastoreId.RUNNING, null, config);
+ } catch (NetconfException e) {
+ log.error("OPENROADM {}: failed to editConfig device {}", did(), e);
+ return false;
+ }
+ }
+
+ /**
+ * Convert start and end frequencies to OCh signal.
+ *
+ * FIXME: assumes slots of 12.5 GHz while devices allows granularity 6.25
+ * GHz and only supports channel spacing 50 and 100
+ *
+ * @param min starting frequency as double in THz
+ * @param max end frequency as double in THz
+ * @return OCh signal
+ */
+ public static OchSignal toOchSignalMinMax(Frequency min, Frequency max) {
+ double start = min.asGHz();
+ double end = max.asGHz();
+
+ int slots = (int) ((end - start) / ChannelSpacing.CHL_12P5GHZ.frequency().asGHz());
+ int multiplier = 0;
+
+ // Conversion for 50 GHz slots
+ if (end - start == 50) {
+ multiplier =
+ (int) (((end - start) / 2 + start - Spectrum.CENTER_FREQUENCY.asGHz()) /
+ ChannelSpacing.CHL_50GHZ.frequency().asGHz());
+
+ return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, multiplier, slots);
+ }
+
+ // Conversion for 100 GHz slots
+ if (end - start == 100) {
+ multiplier =
+ (int) (((end - start) / 2 + start - Spectrum.CENTER_FREQUENCY.asGHz()) /
+ ChannelSpacing.CHL_100GHZ.frequency().asGHz());
+
+ return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, multiplier, slots);
+ }
+
+ return null;
+ }
+
+ /**
+ * Helper method to create an OchSignal for a frequency slot.
+ *
+ * @param center the center frequency as per the ITU-grid.
+ * @param width slot width
+ * @return OCh signal
+ */
+ public static OchSignal toOchSignalCenterWidth(Frequency center, Frequency width) {
+
+ Frequency radius = width.floorDivision(2);
+
+ // Frequency slot start and end frequency.
+ double start = center.subtract(radius).asGHz();
+ double end = center.add(radius).asGHz();
+
+ int slots = (int) ((end - start) / ChannelSpacing.CHL_12P5GHZ.frequency().asGHz());
+ int multiplier = 0;
+
+ // Conversion for 50 GHz slots
+ if (end - start == 50) {
+ multiplier =
+ (int) (((end - start) / 2 + start - Spectrum.CENTER_FREQUENCY.asGHz()) /
+ ChannelSpacing.CHL_50GHZ.frequency().asGHz());
+
+ return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, multiplier, slots);
+ }
+
+ // Conversion for 100 GHz slots
+ if (end - start == 100) {
+ multiplier =
+ (int) (((end - start) / 2 + start - Spectrum.CENTER_FREQUENCY.asGHz()) /
+ ChannelSpacing.CHL_100GHZ.frequency().asGHz());
+
+ return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, multiplier, slots);
+ }
+
+ return null;
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmInterface.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmInterface.java
new file mode 100644
index 0000000..ba6f7e2
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmInterface.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+
+public class OpenRoadmInterface {
+
+ protected String name;
+ protected String description;
+ protected String type;
+ protected String administrativeState;
+ protected String supportingCircuitPack;
+ protected String supportingPort;
+ protected String supportingInterface;
+
+ public abstract static class Builder<T extends Builder<T>> {
+ protected String name;
+ protected String description;
+ protected String type;
+ protected String administrativeState;
+ protected String supportingCircuitPack;
+ protected String supportingPort;
+ protected String supportingInterface;
+
+ protected abstract T self();
+
+ public T name(String name) {
+ this.name = name;
+ return self();
+ }
+
+ public T description(String description) {
+ this.description = description;
+ return self();
+ }
+
+ public T administrativeState(String administrativeState) {
+ this.administrativeState = administrativeState;
+ return self();
+ }
+
+ public T supportingCircuitPack(String supportingCircuitPack) {
+ this.supportingCircuitPack = supportingCircuitPack;
+ return self();
+ }
+
+ public T supportingPort(String supportingPort) {
+ this.supportingPort = supportingPort;
+ return self();
+ }
+
+ public T supportingInterface(String supportingInterface) {
+ this.supportingInterface = supportingInterface;
+ return self();
+ }
+
+ public OpenRoadmInterface build() { //
+ return new OpenRoadmInterface(this);
+ }
+ }
+
+ private static class Builder2 extends Builder<Builder2> {
+ @Override
+ protected Builder2 self() {
+ return this;
+ }
+ }
+
+ public static Builder<?> builder() {
+ return new Builder2();
+ }
+
+ protected OpenRoadmInterface(Builder<?> builder) {
+ this.name = builder.name;
+ this.description = builder.description;
+ this.type = builder.type;
+ this.administrativeState = builder.administrativeState;
+ this.supportingCircuitPack = builder.supportingCircuitPack;
+ this.supportingPort = builder.supportingPort;
+ this.supportingInterface = builder.supportingInterface;
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmLambdaQuery.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmLambdaQuery.java
new file mode 100644
index 0000000..882c78a
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmLambdaQuery.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import java.util.Set;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.PortNumber;
+
+/**
+ * Lambda Query for OpenROADM ports (see Optical model).
+ *
+ * This needs to be addapted to a given use case.
+ */
+public class OpenRoadmLambdaQuery extends OpenRoadmCBandLambdaQuery {
+
+ @Override
+ public Set<OchSignal> queryLambdas(PortNumber port) {
+ channelSpacing = ChannelSpacing.CHL_50GHZ;
+ lambdaCount = 32;
+ slotGranularity = 4;
+ Set<OchSignal> set = super.queryLambdas(port);
+ return set;
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmLocalConnection.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmLocalConnection.java
new file mode 100644
index 0000000..e2fb974
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmLocalConnection.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import org.onosproject.net.device.DeviceService;
+
+/**
+ * Class that models a LOCAL connection.
+ *
+ */
+public class OpenRoadmLocalConnection extends OpenRoadmConnection {
+
+ /**
+ * Constructor for a Local Connection (from client to client ports).
+ *
+ * @param openRoadmName name of the Connection.
+ * @param xc the associated OpenRoadmFlowRule.
+ * @param deviceService ONOS device service.
+ */
+ public OpenRoadmLocalConnection(String openRoadmName, OpenRoadmFlowRule xc,
+ DeviceService deviceService) {
+ super(openRoadmName, xc, deviceService);
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmMcInterface.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmMcInterface.java
new file mode 100644
index 0000000..bf78929
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmMcInterface.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import org.onlab.util.Frequency;
+
+
+public class OpenRoadmMcInterface extends OpenRoadmInterface {
+
+ protected Frequency mcMinFrequency; // expressed in Thz
+ protected Frequency mcMaxFrequency; // expressed in Thz
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<interface>");
+ sb.append("<name>" + name + "</name>");
+ sb.append("<description>Media-Channel</description>");
+ sb.append("<type xmlns:openROADM-if=\"http://org/openroadm/interfaces\">"
+ + "openROADM-if:mediaChannelTrailTerminationPoint</type>");
+ sb.append("<administrative-state>inService</administrative-state>");
+ sb.append("<supporting-circuit-pack-name>" + supportingCircuitPack +
+ "</supporting-circuit-pack-name>");
+ sb.append("<supporting-port>" + supportingPort + "</supporting-port>");
+ if (!supportingInterface.isEmpty()) {
+ sb.append("<supporting-interface>" + supportingInterface +
+ "</supporting-interface>");
+ }
+ sb.append("<mc-ttp xmlns=\"http://org/openroadm/media-channel-interfaces\">");
+ sb.append("<min-freq>" + mcMinFrequency.asTHz() + "</min-freq>");
+ sb.append("<max-freq>" + mcMaxFrequency.asTHz() + "</max-freq>");
+ sb.append("</mc-ttp>");
+ sb.append("</interface>");
+
+ return sb.toString();
+ }
+
+ public abstract static class Builder<T extends Builder<T>>
+ extends OpenRoadmInterface.Builder<T> {
+
+ protected Frequency mcMinFrequency; // expressed in Thz
+ protected Frequency mcMaxFrequency; // expressed in Thz
+
+ public T mcMinFrequency(Frequency mcMinFrequency) {
+ this.mcMinFrequency = mcMinFrequency;
+ return self();
+ }
+
+ public T mcMaxFrequency(Frequency mcMaxFrequency) {
+ this.mcMaxFrequency = mcMaxFrequency;
+ return self();
+ }
+ }
+
+ private static class Builder2 extends Builder<Builder2> {
+ @Override
+ protected Builder2 self() {
+ return this;
+ }
+ }
+
+ public static Builder<?> builder() {
+ return new Builder2();
+ }
+
+
+ protected OpenRoadmMcInterface(Builder<?> builder) {
+ super(builder);
+ this.mcMinFrequency = builder.mcMinFrequency;
+ this.mcMaxFrequency = builder.mcMaxFrequency;
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmNetconfHandlerBehaviour.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmNetconfHandlerBehaviour.java
new file mode 100644
index 0000000..643714f
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmNetconfHandlerBehaviour.java
@@ -0,0 +1,134 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+
+
+
+/**
+ * Driver Implementation of the DeviceDescrption discovery for OpenROADM.
+ */
+public class OpenRoadmNetconfHandlerBehaviour extends AbstractHandlerBehaviour {
+
+ protected static final String RPC_TAG_NETCONF_BASE =
+ "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+
+ protected static final String RPC_CLOSE_TAG = "</rpc>";
+
+ protected static final Logger log = getLogger(OpenRoadmNetconfHandlerBehaviour.class);
+
+
+ /**
+ * Returns the NetconfSession with the device for which the method was called.
+ *
+ * @param deviceId device indetifier
+ *
+ * @return The netconf session or null
+ */
+ protected NetconfSession getNetconfSession(DeviceId deviceId) {
+ NetconfController controller = handler().get(NetconfController.class);
+ NetconfDevice ncdev = controller.getDevicesMap().get(deviceId);
+ if (ncdev == null) {
+ log.trace("No netconf device, returning null session");
+ return null;
+ }
+ return ncdev.getSession();
+ }
+
+
+ /**
+ * Get the deviceId for which the methods apply.
+ *
+ * @return The deviceId as contained in the handler data
+ */
+ protected DeviceId did() {
+ return handler().data().deviceId();
+ }
+
+
+ /**
+ * Get the device instance for which the methods apply.
+ *
+ * @return The device instance
+ */
+ protected Device getDevice() {
+ DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
+ Device device = deviceService.getDevice(did());
+ return device;
+ }
+
+
+ /**
+ * Get the device instance for which the methods apply.
+ *
+ * @return The device instance
+ */
+ protected NetconfDevice getNetconfDevice() {
+ NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+ NetconfDevice ncDevice = controller.getDevicesMap().get(did());
+ return ncDevice;
+ }
+
+
+ /**
+ * Construct a String with a Netconf filtered get RPC Message.
+ *
+ * @param filter A valid XML tree with the filter to apply in the get
+ * @return a String containing the RPC XML Document
+ */
+ protected String filteredGetBuilder(String filter) {
+ StringBuilder rpc = new StringBuilder(RPC_TAG_NETCONF_BASE);
+ rpc.append("<get>");
+ rpc.append("<filter type='subtree'>");
+ rpc.append(filter);
+ rpc.append("</filter>");
+ rpc.append("</get>");
+ rpc.append(RPC_CLOSE_TAG);
+ return rpc.toString();
+ }
+
+ /**
+ * Construct a String with a Netconf filtered get RPC Message.
+ *
+ * @param filter A valid XPath Expression with the filter to apply in the get
+ * @return a String containing the RPC XML Document
+ *
+ * Note: server must support xpath capability.
+ */
+ protected String xpathFilteredGetBuilder(String filter) {
+ StringBuilder rpc = new StringBuilder(RPC_TAG_NETCONF_BASE);
+ rpc.append("<get>");
+ rpc.append("<filter type='xpath' select=\"");
+ rpc.append(filter);
+ rpc.append("\"/>");
+ rpc.append("</get>");
+ rpc.append(RPC_CLOSE_TAG);
+ return rpc.toString();
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmNmcInterface.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmNmcInterface.java
new file mode 100644
index 0000000..ca5e8a4
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmNmcInterface.java
@@ -0,0 +1,85 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+import org.onlab.util.Frequency;
+
+public class OpenRoadmNmcInterface extends OpenRoadmInterface {
+
+ protected Frequency nmcFrequency; // expressed in Thz
+ protected Frequency nmcWidth; // expressed in Ghz
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<interface>");
+ sb.append("<name>" + name + "</name>");
+ sb.append("<description>Network-Media-Channel</description>");
+ sb.append(
+ "<type xmlns:openROADM-if=\"http://org/openroadm/interfaces\">"
+ +
+ "openROADM-if:networkMediaChannelConnectionTerminationPoint</type>");
+ sb.append("<administrative-state>inService</administrative-state>");
+ sb.append("<supporting-circuit-pack-name>" + supportingCircuitPack +
+ "</supporting-circuit-pack-name>");
+ sb.append("<supporting-port>" + supportingPort + "</supporting-port>");
+ if (!supportingInterface.isEmpty()) {
+ sb.append("<supporting-interface>" + supportingInterface + "</supporting-interface>");
+ }
+
+ sb.append("<nmc-ctp xmlns=\"http://org/openroadm/network-media-channel-interfaces\">");
+ sb.append("<frequency>" + nmcFrequency.asTHz() + "</frequency>");
+ sb.append("<width>" + nmcWidth.asGHz() + "</width>");
+ sb.append("</nmc-ctp>");
+ sb.append("</interface>");
+ return sb.toString();
+ }
+
+ public abstract static class Builder<T extends Builder<T>>
+ extends OpenRoadmInterface.Builder<T> {
+
+ protected Frequency nmcFrequency; // expressed in Thz
+ protected Frequency nmcWidth; // expressed in Ghz
+
+ public T nmcFrequency(Frequency nmcFrequency) {
+ this.nmcFrequency = nmcFrequency;
+ return self();
+ }
+
+ public T nmcWidth(Frequency nmcWidth) {
+ this.nmcWidth = nmcWidth;
+ return self();
+ }
+ }
+
+ private static class Builder2 extends Builder<Builder2> {
+ @Override
+ protected Builder2 self() {
+ return this;
+ }
+ }
+
+ public static Builder<?> builder() {
+ return new Builder2();
+ }
+
+ protected OpenRoadmNmcInterface(Builder<?> builder) {
+ super(builder);
+ this.nmcFrequency = builder.nmcFrequency;
+ this.nmcWidth = builder.nmcWidth;
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmOmsInterface.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmOmsInterface.java
new file mode 100644
index 0000000..0516dfb
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmOmsInterface.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+public class OpenRoadmOmsInterface extends OpenRoadmInterface {
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<interface>");
+ sb.append("<name>" + name + "</name>");
+ sb.append("<description>" + description + "</description>");
+ sb.append(
+ "<type xmlns:openROADM-if=\"http://org/openroadm/interfaces\">openROADM-if:openROADMOpticalMultiplex</type>");
+ sb.append("<administrative-state>inService</administrative-state>");
+ sb.append("<supporting-circuit-pack-name>" + supportingCircuitPack +
+ "</supporting-circuit-pack-name>");
+ sb.append("<supporting-port>" + supportingPort + "</supporting-port>");
+ if (!supportingInterface.isEmpty()) {
+ sb.append("<supporting-interface>" + supportingInterface + "</supporting-interface>");
+ }
+ return sb.toString();
+ }
+
+ public abstract static class Builder<T extends Builder<T>>
+ extends OpenRoadmInterface.Builder<T> {
+ //
+ }
+
+ private static class Builder2 extends Builder<Builder2> {
+ @Override
+ protected Builder2 self() {
+ return this;
+ }
+ }
+
+ public static Builder<?> builder() {
+ return new Builder2();
+ }
+
+ protected OpenRoadmOmsInterface(Builder<?> builder) {
+ super(builder);
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmOtsInterface.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmOtsInterface.java
new file mode 100644
index 0000000..0fc82ef
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmOtsInterface.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.openroadm;
+
+public class OpenRoadmOtsInterface extends OpenRoadmInterface {
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<interface>");
+ sb.append("<name>" + name + "</name>");
+ sb.append("<description>" + description + "</name>");
+ sb.append(
+ "<type xmlns:openROADM-if=\"http://org/openroadm/interfaces\">openROADM-if:opicalTransport</type>");
+ sb.append("<administrative-state>inService</administrative-state>");
+ sb.append("<supporting-circuit-pack-name>" + supportingCircuitPack +
+ "</supporting-circuit-pack-name>");
+ sb.append("<supporting-port>" + supportingPort + "</supporting-port>");
+ sb.append("</interface>");
+ return sb.toString();
+ }
+
+ public abstract static class Builder<T extends Builder<T>>
+ extends OpenRoadmInterface.Builder<T> {
+ //
+ }
+
+ private static class Builder2 extends Builder<Builder2> {
+ @Override
+ protected Builder2 self() {
+ return this;
+ }
+ }
+
+ public static Builder<?> builder() {
+ return new Builder2();
+ }
+
+ protected OpenRoadmOtsInterface(Builder<?> builder) {
+ super(builder);
+ }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/package-info.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/package-info.java
new file mode 100644
index 0000000..03711c1
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+/**
+ * Package for Metro-Haul OpenROADM device drivers.
+ */
+package org.onosproject.drivers.odtn.openroadm;
diff --git a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
index 8c7a799..ba102a7 100644
--- a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
+++ b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
@@ -43,6 +43,17 @@
impl="org.onosproject.drivers.odtn.openconfig.TerminalDeviceFlowRuleProgrammable"/>
</driver>
+ <driver name="openroadm" extends="" manufacturer="CTTC/CNIT" hwVersion="0.0.1" swVersion="0.0.1">
+ <behaviour api ="org.onosproject.net.device.DeviceDescriptionDiscovery"
+ impl="org.onosproject.drivers.odtn.openroadm.OpenRoadmDeviceDescription"/>
+ <behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
+ impl="org.onosproject.drivers.odtn.openroadm.OpenRoadmFlowRuleProgrammable"/>
+ <behaviour api ="org.onosproject.net.behaviour.LambdaQuery"
+ impl="org.onosproject.drivers.odtn.openroadm.OpenRoadmLambdaQuery"/>
+ <behaviour api ="org.onosproject.net.optical.OpticalDevice"
+ impl="org.onosproject.net.optical.DefaultOpticalDevice"/>
+ </driver>
+
<driver name="infinera-xt3300" manufacturer="infinera" hwVersion="xt3300" swVersion="18.0">
<behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
impl="org.onosproject.drivers.odtn.InfineraOpenConfigDeviceDiscovery"/>