blob: bf54ebb013d52ae5eddcf7fb951828c76ee27913 [file] [log] [blame]
/*
* 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.DatastoreId;
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 specific circuit pack data (by name).
*
* @return A string with the Netconf RPC
*/
private String getDeviceCircuitPackByNameBuilder(String cpName) {
StringBuilder filter = new StringBuilder();
filter.append(OPENROADM_DEVICE_OPEN);
filter.append("<circuit-packs>");
filter.append(" <circuit-pack-name>");
filter.append(cpName);
filter.append(" </circuit-pack-name>");
filter.append("</circuit-packs>");
filter.append(OPENROADM_DEVICE_CLOSE);
return filteredGetBuilder(filter.toString());
}
/**
* Builds a request to get External Links data (<external-link>).
*
* @return A string with the Netconf filter for the get-config operation.
*/
private String getDeviceExternalLinksBuilder() {
StringBuilder rb = new StringBuilder();
rb.append(OPENROADM_DEVICE_OPEN);
rb.append("<external-link/>");
rb.append(OPENROADM_DEVICE_CLOSE);
return rb.toString();
}
/**
* 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.getConfig(DatastoreId.RUNNING, getDeviceExternalLinksBuilder());
XMLConfiguration extLinksConf =
(XMLConfiguration) XmlConfigParser.loadXmlString(reply);
extLinksConf.setExpressionEngine(new XPathExpressionEngine());
return extLinksConf.configurationsAt(
"/data/org-openroadm-device/external-link");
} catch (NetconfException e) {
log.error("[OPENROADM] {} exception getting external links", did());
return ImmutableList.of();
}
}
/**
* Get config and status info for a specific circuit pack as a
* list of XML hierarchical configs.
* @param session the NETConf session to the OpenROADM device.
* @param cpName the name of the requested circuit-pack
* @return the hierarchical conf. for the circuit pack.
*/
HierarchicalConfiguration getCircuitPackByName(NetconfSession session, String cpName) {
try {
String reply = session.rpc(getDeviceCircuitPackByNameBuilder(cpName)).get();
XMLConfiguration cpConf =
(XMLConfiguration) XmlConfigParser.loadXmlString(reply);
cpConf.setExpressionEngine(new XPathExpressionEngine());
List<HierarchicalConfiguration> cPacks = cpConf.configurationsAt(
"/data/org-openroadm-device/circuit-packs");
// <circuit-pack-name> is the key for the list.
// It shouldn't happen they are > 1
if (cPacks.size() > 1) {
log.warn("[OPENROADM] More than one circuit pack with the same name. Using first one");
}
return cPacks.get(0);
} catch (NetconfException | InterruptedException | ExecutionException e) {
log.error("[OPENROADM] {} exception getting circuit pack {}: {}", did(), cpName, e);
return null;
}
}
/**
* Get config and status info for the degrees 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 degree.
*/
List<HierarchicalConfiguration> getDegrees(NetconfSession session) {
try {
String reply = session.rpc(getDeviceDegreesBuilder()).get();
XMLConfiguration conf =
(XMLConfiguration) XmlConfigParser.loadXmlString(reply);
conf.setExpressionEngine(new XPathExpressionEngine());
return conf.configurationsAt(
"/data/org-openroadm-device/degree");
} catch (NetconfException | InterruptedException | ExecutionException e) {
log.error("[OPENROADM] {} exception getting degrees: {}", did(), e);
return ImmutableList.of();
}
}
/**
* Get config and status info for the SRGs 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 SRG.
*/
List<HierarchicalConfiguration> getSrgs(NetconfSession session) {
try {
String reply = session.rpc(getDeviceSharedRiskGroupsBuilder()).get();
XMLConfiguration conf =
(XMLConfiguration) XmlConfigParser.loadXmlString(reply);
conf.setExpressionEngine(new XPathExpressionEngine());
return conf.configurationsAt(
"/data/org-openroadm-device/shared-risk-group");
} catch (NetconfException | InterruptedException | ExecutionException e) {
log.error("[OPENROADM] {} exception getting SRGs: {}", did(), e);
return ImmutableList.of();
}
}
/**
* Returns a list of PortDescriptions for the device.
*
* @return a list of descriptions.
*/
/*
* Assumptions: ROADM degree ports are Oms carrying 80 lambdas (should be
* configurable)
* ROADM SRG (client) ports are OCh carrying ODU4 (should be
* configurable)
*/
@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("Unable to run PortDiscovery: missing openroadm-node-id annotation." +
" Probable failure during DeviceDiscovery. Aborting!");
return ImmutableList.of();
}
List<HierarchicalConfiguration> externalLinks = getExternalLinks(session);
List<PortDescription> list = new ArrayList<PortDescription>();
discoverDegreePorts(session, list, externalLinks);
discoverSrgPorts(session, list, externalLinks);
return list;
}
/**
* Parses degree (ROADM) port information.
*
* @param session the NETConf session to the OpenROADM device.
* @param list List of port descriptions to append to.
* @param externalLinks Hierarchical configuration containing all the external
* links.
* Port-id is obtained from degree-number and from the index contained
* in the <connection-ports> leaf.
* For OpenROADM Device model 2.2 both <degree-number> and <index> inside
* <connection-ports> are key for the related lists, so composing them
* assures identificator uniqueness.
* Degree IDs are chosen as 10 * degree-number + index to avoid overlapping
* with SRGs IDs.
* The above formula allows making a two-digit number starting from two
* one-digit numbers (actually, only port index needs to be single digit and
* this assumption is assured by what stated in the model:
* OpenROADM Device model 2.2 (line 675):
* (connection-ports) description "Port associated with degree: One if bi-directional; two if uni-directional"
* If my numbers are A and B, to have a number in the form AB (i.e. 11, 12, 21,
* 31, 42, ...) I have to multiply A by 10.
*
* Note that both bidirectional and unidirectional ports IDs are taken from
* the datastore.
* Ex. DEG1 bidirectional port
* ONOS port ID: 11
* DEG3 unidirectional port
* ONOS port IDs: 31 and 32
*/
private List<PortDescription>
discoverDegreePorts(NetconfSession session,
List<PortDescription> list,
List<HierarchicalConfiguration> externalLinks) {
int degreeNumber = 0;
String nodeId = getDevice().annotations().value(AnnotationKeys.OPENROADM_NODEID);
List<HierarchicalConfiguration> degrees = getDegrees(session);
for (HierarchicalConfiguration degree : degrees) {
degreeNumber = degree.getInt("degree-number", 0);
// From OpenROADM Device model 2.2: degree-number must be > 0
if (degreeNumber == 0) {
log.warn("[OPENROADM] Device {} <degree-number> MUST be > 0", did());
continue;
}
List<HierarchicalConfiguration> connectionPorts =
degree.configurationsAt("connection-ports");
for (HierarchicalConfiguration cport : connectionPorts) {
int portIndex = cport.getInt("index", 0);
long portNum = degreeNumber * 10 + portIndex;
PortNumber pNum = PortNumber.portNumber(portNum);
String cpName = cport.getString("circuit-pack-name", "");
String portName = cport.getString("port-name", "");
PortNumber reversepNum = findDegreeReversePort(degreeNumber, portIndex, connectionPorts);
HierarchicalConfiguration eLink = parseExternalLink(externalLinks, nodeId, cpName, portName);
HierarchicalConfiguration circuitPack = getCircuitPackByName(session, cpName);
List<HierarchicalConfiguration> cpPorts =
circuitPack.configurationsAt("ports[port-name='" + portName + "']");
if (cpPorts.size() > 1) {
log.warn("[OPENROADM] {}: more than one port with the same name. Using first one", did());
}
HierarchicalConfiguration port = cpPorts.get(0);
PortDescription pd = buildDegreePortDesc(nodeId, cpName, pNum, reversepNum, port, eLink);
if (pd != null) {
list.add(pd);
}
}
}
return list;
}
/**
* Parses SRG (ROADM) port information.
*
* @param session the NETConf session to the OpenROADM device.
* @param list List of port descriptions to append to.
* @param externalLinks Hierarchical configuration containing all the external
* links.
*
* Port-id is obtained from srg-number and the number of the client
* port contained in the <logical-connection-point> leaf.
* OpenROADM Device Whitepaper for release 2.2, sect. 7.2.2.2.1:
* "For the ROADM SRG add/drop port, the logical connection point should
* be set to the format “SRG<n>-PP<m>”, where <n> is the SRG number
* and <m> is the add/drop port pair identifier. For example SRG1
* add/drop port #7 would have the logical connection point set to
* SRG1-PP7".
* The method extract <m> following the sustring PP and use it in conjuncion
* with the degree-number taken from the <degree> branch (If the datastore is
* consistent this should be the same number in SRG<n>).
* To avoid overlapping with IDs assigned to degrees, the srg-number is multiplied
* by 1000. The to cover the uni-directional case (that needs two IDs, one per
* direction) the port index is multiplied by 10.
* Using 1000 as multiplier avoids overlapping with degree port IDs as long as
* the number of degree in the ROADM is less than 100. Current optical
* technologies don't allow ROADMs having such a high number of degrees.
*
* For unidirectional links the logical connection point is assumed to
* have the form DEGn-PPi[-TX/-RX] and to the RX link is assigned an ID
* following (+1) the TX one.
* Ex. SRG1 second port bidirectional link (SRG1-PP2)
* ONOS port ID: 1020
* SRG2 third port, unidirectional link (SRG2-PP3-TX, SRG2-PP3-RX)
* ONOS port IDs: 2030 and 2031
*/
private List<PortDescription>
discoverSrgPorts(NetconfSession session,
List<PortDescription> list,
List<HierarchicalConfiguration> externalLinks) {
int srgNumber = 0;
String nodeId = getDevice().annotations().value(AnnotationKeys.OPENROADM_NODEID);
List<HierarchicalConfiguration> srgs = getSrgs(session);
for (HierarchicalConfiguration s : srgs) {
srgNumber = s.getInt("srg-number", 0);
// From OpenROADM Device model 2.2: srg-number must be > 0
if (srgNumber == 0) {
log.warn("[OPENROADM] Device {} <srg-number> MUST be > 0", did());
continue;
}
List<HierarchicalConfiguration> srgCircuitPacks =
s.configurationsAt("circuit-packs");
for (HierarchicalConfiguration scp : srgCircuitPacks) {
String srgCpName = scp.getString("circuit-pack-name");
HierarchicalConfiguration cpConf = getCircuitPackByName(session, srgCpName);
List<HierarchicalConfiguration> ports = cpConf.configurationsAt("ports[port-qual='roadm-external']");
for (HierarchicalConfiguration p : ports) {
String portName = p.getString("port-name");
String lcp = p.getString("logical-connection-point", "unknown");
int ppIndex = lcp.indexOf("PP");
if (ppIndex == -1) {
log.warn("[OPENROADM] {}: cannot find port index for circuit-pack {}", did(), srgCpName);
} else {
long portNum, revPortNum;
String[] split = lcp.split("-");
// 1000 is chosen as base value to avoid overlapping
// with IDs for degree ports that have 10 as base value
long basePort = srgNumber * 1000 + Long.parseLong(split[1].replace("PP", "")) * 10;
if (split.length > 2) {
// Unidirectional port
portNum = basePort + (split[2].equals("RX") ? 1 : 0);
revPortNum = basePort + (split[2].equals("RX") ? 0 : 1);
} else {
// Bidirectional port
portNum = basePort;
revPortNum = 0;
}
PortNumber pNum = PortNumber.portNumber(portNum);
PortNumber reversepNum = PortNumber.portNumber(revPortNum);
HierarchicalConfiguration eLink = parseExternalLink(externalLinks, nodeId, srgCpName, portName);
PortDescription pd = buildSrgPortDesc(nodeId, srgCpName, pNum, reversepNum, p, eLink);
if (pd != null) {
list.add(pd);
}
}
}
}
}
return list;
}
/**
* Locate (if present) the external link for a given <circuit-pack, port> pair
* within the Hierarchical Configuration.
*
* @param extLinks Hierarchical configuration containing all the external
* links.
* @param nodeId The OpenRoadm nodeId of the current node.
* @param circuitPackName name of the circuit pack of the port.
* @param portName name of the port.
* @return the external link.
*/
private HierarchicalConfiguration parseExternalLink(List<HierarchicalConfiguration> extLinks,
String nodeId,
String circuitPackName,
String portName) {
HierarchicalConfiguration eLink = null;
try {
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;
}
}
} catch (NullPointerException e) {
log.error("[OPENROADM] {} invalid external-links", did());
}
return eLink;
}
/**
* Given a degree port (external), return its partner/reverse port.
*
* @param degreeNumber Number identifying the current degree.
* @param portIndex the index of the port (degree branch) for which we are
* looking for the reverse port.
* @param connPorts list of connection-ports as hierarchical configuration.
* @return the port number for the reverse port.
*/
protected PortNumber
findDegreeReversePort(int degreeNumber, int portIndex,
List<HierarchicalConfiguration> connPorts) {
// bidirectional port.
if (connPorts.size() == 1) {
return PortNumber.portNumber(0);
}
for (HierarchicalConfiguration cp : connPorts) {
int revPortIndex = cp.getInt("index", -1);
if (revPortIndex != portIndex) {
return PortNumber.portNumber(10 * degreeNumber + revPortIndex);
}
}
// We should not reach here
return PortNumber.portNumber(0);
}
/**
* Parses a component XML doc into a PortDescription.
* An OMS port description is constructed from XML parsed data.
*
* @param nodeId The OpenRoadm nodeId of the current node.
* @param circuitPackName name of circuit pack containing the port.
* @param pNum the portNumber of the port.
* @param reversepNum the portNumber of the partner port.
* @param port the hierarchical configuration of the port to parse
* @param extLink Hierarchical configuration for the external links.
* @return PortDescription or null.
*/
private PortDescription
buildDegreePortDesc(String nodeId, String circuitPackName,
PortNumber pNum, PortNumber reversepNum,
HierarchicalConfiguration port,
HierarchicalConfiguration extLink) {
DefaultAnnotations annotations = createPortAnnotations(nodeId,
circuitPackName,
pNum,
reversepNum,
port,
extLink);
// Relationship : START and STOP Freq not being used (See
// LambdaQuery)
return OmsPortHelper.omsPortDescription(pNum,
true /* enabled */,
START_CENTER_FREQ,
STOP_CENTER_FREQ,
CHANNEL_SPACING.frequency(),
annotations);
}
/**
* Parses a component XML doc into a PortDescription.
* An Och port description is constructed from XML parsed data.
*
* @param nodeId The OpenRoadm nodeId of the current node.
* @param circuitPackName name of circuit pack containing the port.
* @param pNum the portNumber of the port.
* @param reversepNum the portNumber of the partner port.
* @param port the hierarchical configuration of the port to parse
* @param extLink Hierarchical configuration for the external links.
* @return PortDescription or null.
*/
private PortDescription
buildSrgPortDesc(String nodeId, String circuitPackName,
PortNumber pNum, PortNumber reversepNum,
HierarchicalConfiguration port,
HierarchicalConfiguration extLink) {
DefaultAnnotations annotations = createPortAnnotations(nodeId,
circuitPackName,
pNum,
reversepNum,
port,
extLink);
OchSignal signalId =
OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 3);
return OchPortHelper.ochPortDescription(pNum,
true /* enabled */,
OduSignalType.ODU4,
true /* tunable */,
signalId,
annotations);
}
/**
* Creates annotations for the port.
*
* @param nodeId The OpenRoadm nodeId of the current node.
* @param circuitPackName name of circuit pack containing the port.
* @param pNum the portNumber of the port.
* @param reversepNum the portNumber of the partner port.
* @param port the hierarchical configuration of the port to parse
* @param extLink Hierarchical configuration for the external links.
* @return DefaultAnnotation.
*/
private DefaultAnnotations
createPortAnnotations(String nodeId,
String circuitPackName,
PortNumber pNum,
PortNumber reversepNum,
HierarchicalConfiguration port,
HierarchicalConfiguration extLink) {
Map<String, String> annotations = new HashMap<>();
String portName = port.getString("port-name");
annotations.put(AnnotationKeys.OPENROADM_NODEID, nodeId);
annotations.put(AnnotationKeys.OPENROADM_CIRCUIT_PACK_NAME,
circuitPackName);
annotations.put(org.onosproject.net.AnnotationKeys.PORT_NAME, portName);
annotations.put(AnnotationKeys.OPENROADM_PORT_NAME, portName);
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
// (Partner port is present in the datastore only for
// unidirectional ports).
if (reversepNum.toLong() != 0) {
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);
}
return DefaultAnnotations.builder().putAll(annotations).build();
}
}