diff --git a/apps/roadm/src/main/java/org/onosproject/roadm/RoadmManager.java b/apps/roadm/src/main/java/org/onosproject/roadm/RoadmManager.java index 9f83df50de..a98b2520c9 100644 --- a/apps/roadm/src/main/java/org/onosproject/roadm/RoadmManager.java +++ b/apps/roadm/src/main/java/org/onosproject/roadm/RoadmManager.java @@ -593,11 +593,12 @@ public class RoadmManager implements RoadmService { } // Delay the call to setTargetPower because the flow may not be in the store yet + // Tested with Lumentum ROADM-20 1 seconds was not enough, increased to 5 seconds private void delayedSetAttenuation(DeviceId deviceId, PortNumber outPort, OchSignal ochSignal, long attenuation) { Runnable setAtt = () -> { try { - TimeUnit.SECONDS.sleep(1); + TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { log.warn("Thread interrupted. Setting attenuation early."); Thread.currentThread().interrupt(); diff --git a/drivers/lumentum/BUILD b/drivers/lumentum/BUILD index b8f8156002..2f991cc585 100644 --- a/drivers/lumentum/BUILD +++ b/drivers/lumentum/BUILD @@ -5,6 +5,7 @@ COMPILE_DEPS = CORE_DEPS + [ "//protocols/tl1/api:onos-protocols-tl1-api", "//protocols/netconf/api:onos-protocols-netconf-api", "//apps/optical-model:onos-apps-optical-model", + "//drivers/odtn-driver:onos-drivers-odtn-driver", "//drivers/optical:onos-drivers-optical", ] @@ -31,6 +32,8 @@ onos_app( "org.onosproject.optical-model", "org.onosproject.tl1", "org.onosproject.netconf", + "org.onosproject.drivers.odtn-driver", + "org.onosproject.drivers.netconf", "org.onosproject.drivers.optical", ], title = "Lumentum Drivers", diff --git a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumConnection.java b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumConnection.java deleted file mode 100644 index 58c5b784ed..0000000000 --- a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumConnection.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.onosproject.drivers.lumentum; - -import org.onosproject.net.OchSignal; -import org.onosproject.net.PortNumber; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Lumentum cross connection abstraction. - * - * Required to store all information needed by Lumentum device not included in CrossConnectFlowRule. - */ -public class LumentumConnection { - - private static final Logger log = LoggerFactory.getLogger(LumentumConnection.class); - - protected boolean isAddRule; - protected int connectionId; - protected int connectionModule; - protected int hashCode; - protected PortNumber inPortNumber; - protected PortNumber outPortNumber; - protected OchSignal ochSignal; - - protected double attenuation; - protected double targetAttenuation; - protected double targetPower; - protected double inputPower; - protected double outputPower; - - protected LumentumFlowRule rule; - - //TODO: compute target attenuation to obtain the desired targetPower - - /** - * Builds a LumentumConnection. - * - * @param id the id retrieved from the device - * @param flowRuleHash the hash code associated to the Flow Rule - * @param xc the cross connect flow rule - */ - public LumentumConnection(Integer id, Integer flowRuleHash, LumentumFlowRule xc) { - - connectionId = id; - hashCode = flowRuleHash; - - isAddRule = xc.isAddRule(); - ochSignal = xc.ochSignal(); - attenuation = 0.0; //dB - inputPower = 0.0; //dBm - outputPower = 0.0; //dBm - rule = xc; - - if (isAddRule) { - outPortNumber = LumentumNetconfRoadmFlowRuleProgrammable.LINE_PORT_NUMBER; - inPortNumber = xc.addDrop(); - } else { - outPortNumber = xc.addDrop(); - inPortNumber = LumentumNetconfRoadmFlowRuleProgrammable.LINE_PORT_NUMBER; - } - - log.debug("Lumentum NETCONF inPort {} outPort {} ochSignal {}", inPortNumber, outPortNumber, xc.ochSignal()); - } - - protected Integer getConnectionId() { - return connectionId; - } - - protected Integer getHash() { - return hashCode; - } - - protected void setAttenuation(double att) { - attenuation = att; - } - - protected void setInputPower(double power) { - inputPower = power; - } - - protected void setOutputPower(double power) { - outputPower = power; - } - -} diff --git a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumFlowRule.java b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumFlowRule.java index 9489ff1831..fe26d72d5c 100644 --- a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumFlowRule.java +++ b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumFlowRule.java @@ -44,6 +44,9 @@ public class LumentumFlowRule extends DefaultFlowRule { } public Type type; + private String connectionName; + private int connectionId; + private int connectionModule; private PortNumber addDrop; private PortNumber inputPort; @@ -52,6 +55,12 @@ public class LumentumFlowRule extends DefaultFlowRule { private OchSignal ochSignal; private boolean isAddRule; + protected double attenuation; + protected double targetAttenuation; + protected double targetPower; + protected double inputPower; + protected double outputPower; + //As generated by the OpticalConnectivityIntentCompiler private static final int NUM_CRITERIA_INTENT = 3; private static final int NUM_INSTRUCTIONS_INTENT = 2; @@ -60,6 +69,7 @@ public class LumentumFlowRule extends DefaultFlowRule { private static final int NUM_CRITERIA_ROADM = 3; private static final int NUM_INSTRUCTIONS_ROADM = 1; + public LumentumFlowRule(FlowRule rule, List linePorts) { super(rule); @@ -137,6 +147,8 @@ public class LumentumFlowRule extends DefaultFlowRule { addDrop = outInstruction.port(); isAddRule = false; } + + connectionName = "inPort" + inputPort.toString() + "-ochSig-" + ochSignal.centralFrequency().toString(); } public PortNumber addDrop() { @@ -158,4 +170,36 @@ public class LumentumFlowRule extends DefaultFlowRule { public PortNumber getOutputPort() { return outputPort; } + + public String getConnectionName() { + return connectionName; + } + + public int getConnectionId() { + return connectionId; + } + + public int getConnectionModule() { + return connectionModule; + } + + public void setConnectionId(int id) { + connectionId = id; + } + + public void setConnectionModule(int id) { + connectionModule = id; + } + + protected void setAttenuation(double att) { + attenuation = att; + } + + protected void setInputPower(double power) { + inputPower = power; + } + + protected void setOutputPower(double power) { + outputPower = power; + } } diff --git a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumNetconfRoadmDiscovery.java b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumNetconfRoadmDiscovery.java index eea8b5906c..df656c94b1 100644 --- a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumNetconfRoadmDiscovery.java +++ b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumNetconfRoadmDiscovery.java @@ -45,7 +45,6 @@ import org.onosproject.net.intent.OpticalPathIntent; import org.onosproject.netconf.NetconfController; import org.onosproject.netconf.NetconfException; import org.onosproject.netconf.NetconfSession; -import org.onosproject.netconf.NetconfDevice; import org.slf4j.Logger; @@ -87,13 +86,17 @@ public class LumentumNetconfRoadmDiscovery private static final int MAX_DEM_PORT = 5220; private static final int DELTA_MUX_DEM_PORT = MIN_DEM_PORT - MIN_MUX_PORT; + private static final String MUX_PORT_NAME = "Mux Input"; + private static final String DEMUX_PORT_NAME = "Demux Output"; + private static final String LINE_PORT_NAME = "Optical Line"; + private final Logger log = getLogger(getClass()); @Override public DeviceDescription discoverDeviceDetails() { SparseAnnotations annotations = DefaultAnnotations.builder().build(); - log.info("Lumentum NETCONF - starting discoverDeviceDetails"); + log.debug("Lumentum NETCONF - starting discoverDeviceDetails"); // Some defaults values String vendor = "Lumentum"; @@ -106,7 +109,6 @@ public class LumentumNetconfRoadmDiscovery DeviceId deviceId = handler().data().deviceId(); NetconfSession session = getNetconfSession(); - if (session == null) { log.error("Lumentum NETCONF - session not found for {}", deviceId); return null; @@ -119,7 +121,7 @@ public class LumentumNetconfRoadmDiscovery try { String reply = session.get(systemRequestBuilder.toString(), null); - log.info("Lumentum NETCONF - session.get reply {}", reply); + log.debug("Lumentum NETCONF - session.get reply {}", reply); XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply); @@ -136,7 +138,7 @@ public class LumentumNetconfRoadmDiscovery try { String reply = session.get(chassisRequestBuilder.toString(), null); - log.info("Lumentum NETCONF - session.get reply {}", reply); + log.debug("Lumentum NETCONF - session.get reply {}", reply); XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply); @@ -152,10 +154,11 @@ public class LumentumNetconfRoadmDiscovery } //Upon connection of a new devices all pre-configured connections are removed - //TODO: do not cancel and import already configured connections + //TODO consider a way to keep "external" FlowRules rpcRemoveAllConnections("1"); rpcRemoveAllConnections("2"); + log.info("Lumentum ROADM20 - discovered details:"); log.info("TYPE {}", Device.Type.ROADM); log.info("VENDOR {}", vendor); log.info("HWVERSION {}", hwVersion); @@ -170,7 +173,6 @@ public class LumentumNetconfRoadmDiscovery @Override public List discoverPortDetails() { - String reply; DeviceId deviceId = handler().data().deviceId(); DeviceService deviceService = checkNotNull(handler().get(DeviceService.class)); Device device = deviceService.getDevice(deviceId); @@ -182,7 +184,6 @@ public class LumentumNetconfRoadmDiscovery } NetconfSession session = getNetconfSession(); - if (session == null) { log.error("Lumentum NETCONF - session not found for {}", deviceId); return ImmutableList.of(); @@ -195,6 +196,7 @@ public class LumentumNetconfRoadmDiscovery requestBuilder.append("xmlns:loteeth=\"http://www.lumentum.com/lumentum-ote-port-ethernet\">"); requestBuilder.append(""); + String reply; try { reply = session.get(requestBuilder.toString(), null); } catch (NetconfException e) { @@ -259,9 +261,6 @@ public class LumentumNetconfRoadmDiscovery log.error("Port Type not correctly loaded"); } - //Store reverse port index in the annotations - Long reversePortId; - /** * Setting the reverse port value for the unidirectional ports. * @@ -272,11 +271,11 @@ public class LumentumNetconfRoadmDiscovery * Where port 520x is always the reverse of 410x. */ if ((portNum.toLong() >= MIN_MUX_PORT) && (portNum.toLong() <= MAX_MUX_PORT)) { - reversePortId = portNum.toLong() + DELTA_MUX_DEM_PORT; + Long reversePortId = portNum.toLong() + DELTA_MUX_DEM_PORT; annotations.set(OpticalPathIntent.REVERSE_PORT_ANNOTATION_KEY, reversePortId.toString()); } if ((portNum.toLong() >= MIN_DEM_PORT) && (portNum.toLong() <= MAX_DEM_PORT)) { - reversePortId = portNum.toLong() - DELTA_MUX_DEM_PORT; + Long reversePortId = portNum.toLong() - DELTA_MUX_DEM_PORT; annotations.set(OpticalPathIntent.REVERSE_PORT_ANNOTATION_KEY, reversePortId.toString()); } @@ -305,7 +304,13 @@ public class LumentumNetconfRoadmDiscovery log.debug("Lumentum NETCONF - retrieved port {},{},{},{},{}", portNum, isEnabled, type, speed, annotations.build()); - if (type == Port.Type.FIBER) { + + if ((type == Port.Type.FIBER) && + ((annotations.build().value(AnnotationKeys.PORT_NAME)).contains(MUX_PORT_NAME) || + (annotations.build().value(AnnotationKeys.PORT_NAME)).contains(DEMUX_PORT_NAME) || + (annotations.build().value(AnnotationKeys.PORT_NAME)).contains(LINE_PORT_NAME))) { + + //These are the ports supporting OchSignals portDescriptions.add(omsPortDescription(portNum, isEnabled, START_CENTER_FREQ_50, @@ -313,6 +318,7 @@ public class LumentumNetconfRoadmDiscovery CHANNEL_SPACING_50.frequency(), annotations.build())); } else { + //These are COPPER ports, or FIBER ports not supporting OchSignals DefaultPortDescription.Builder portDescriptionBuilder = DefaultPortDescription.builder(); portDescriptionBuilder.withPortNumber(portNum) .isEnabled(isEnabled) @@ -342,7 +348,6 @@ public class LumentumNetconfRoadmDiscovery private boolean editCrossConnect(String xcString) { NetconfSession session = getNetconfSession(); - if (session == null) { log.error("Lumentum NETCONF - session not found for {}", handler().data().deviceId()); return false; @@ -358,15 +363,19 @@ public class LumentumNetconfRoadmDiscovery } } + /** + * Helper method to get the Netconf session. + */ private NetconfSession getNetconfSession() { - NetconfController controller = checkNotNull(handler().get(NetconfController.class)); - NetconfDevice ncDevice = controller.getNetconfDevice(handler().data().deviceId()); + NetconfController controller = + checkNotNull(handler().get(NetconfController.class)); + return controller.getNetconfDevice(did()).getSession(); + } - if (ncDevice == null) { - log.error("Lumentum NETCONF - device not found for {}", handler().data().deviceId()); - return null; - } - - return ncDevice.getSession(); + /** + * Helper method to get the device id. + */ + private DeviceId did() { + return data().deviceId(); } } diff --git a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumNetconfRoadmFlowRuleProgrammable.java b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumNetconfRoadmFlowRuleProgrammable.java index 13f82eb624..57cc0256f2 100644 --- a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumNetconfRoadmFlowRuleProgrammable.java +++ b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumNetconfRoadmFlowRuleProgrammable.java @@ -21,27 +21,23 @@ import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.lang3.tuple.Pair; import org.onlab.util.Frequency; import org.onlab.util.Spectrum; -import org.onosproject.driver.optical.flowrule.CrossConnectCache; +import org.onosproject.drivers.odtn.impl.DeviceConnectionCache; import org.onosproject.drivers.utilities.XmlConfigParser; -import org.onosproject.net.ChannelSpacing; -import org.onosproject.net.GridType; +import org.onosproject.net.PortNumber; import org.onosproject.net.OchSignal; import org.onosproject.net.OchSignalType; -import org.onosproject.net.PortNumber; +import org.onosproject.net.DeviceId; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; 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.FlowId; 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.Instructions; import org.onosproject.netconf.NetconfController; import org.onosproject.netconf.NetconfException; import org.onosproject.netconf.NetconfSession; @@ -49,12 +45,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; -import java.util.stream.Collectors; import java.util.Collection; -import java.util.Objects; -import java.util.Set; +import java.util.ArrayList; import java.util.List; -import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -91,14 +86,7 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh protected static final long MUX_OUT = 4201; protected static final long DEMUX_IN = 5101; protected static final long GHZ = 1_000_000_000L; - protected static final int MAX_CONNECTIONS = 100; - - //List of LumentumConnections to associate ConnectionId and other info to the relative hash - - //This is required because CrossConnect, CrossConnect Cache do not include all parameters required by Lumentum - //TODO: Use an external cache as CrossConnectCache to avoid problems in case of multiple devices using this driver - - protected static final Set CONNECTION_SET = new HashSet<>(); + protected static final int LUMENTUM_ROADM20_MAX_CONNECTIONS = 100; /**Get the flow entries that are present on the Lumentum device, called by FlowRuleDriverProvider. * @@ -109,13 +97,15 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh */ @Override public Collection getFlowEntries() { - return ImmutableList.copyOf( - fetchConnectionsFromDevice().stream() - .map(conn -> buildFlowrule(conn)) - .filter(Objects::nonNull) - .map(fr -> new DefaultFlowEntry( - fr, FlowEntry.FlowEntryState.ADDED, 0, 0, 0)) - .collect(Collectors.toList())); + Collection fetched = fetchConnectionsFromDevice().stream() + .map(conn -> buildFlowrule(conn)) + .map(fr -> new DefaultFlowEntry(fr, FlowEntry.FlowEntryState.ADDED, 0, 0, 0)) + .collect(Collectors.toList()); + + //Print out number of rules actually found on the device that are also included in the cache + log.debug("Device {} getFlowEntries fetched connections {}", did(), fetched.size()); + + return fetched; } /**Apply the flow entries specified in the collection rules. @@ -125,40 +115,54 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh */ @Override public Collection applyFlowRules(Collection rules) { - // Apply the rules on the device - Collection added = rules.stream() - .map(r -> new LumentumFlowRule(r, getLinePorts())) - .filter(xc -> rpcAddConnection(xc)) - .collect(Collectors.toList()); + //Check NETCONF session + NetconfSession session = getNetconfSession(); + if (session == null) { + log.error("Device {} null session", did()); + return ImmutableList.of(); + } - // Cache the cookie/priority - CrossConnectCache cache = this.handler().get(CrossConnectCache.class); - added.forEach(xc -> cache.set( - Objects.hash(data().deviceId(), xc.selector()), - xc.id(), - xc.priority())); + // Apply the rules on the device and add to cache if success + Collection added = new ArrayList<>(); + for (FlowRule flowRule : rules) { + LumentumFlowRule lumFlowRule = new LumentumFlowRule(flowRule, getLinePorts()); - added.forEach(xc -> log.debug("Lumentum build cached FlowRule selector {} treatment {}", - xc.selector().toString(), xc.treatment().toString())); + if (rpcAddConnection(lumFlowRule)) { + added.add(lumFlowRule); + getConnectionCache().add(did(), lumFlowRule.getConnectionName(), lumFlowRule); + } + } + + //Print out number of rules sent to the device (without receiving errors) + log.debug("Device {} applyFlowRules added {}", did(), added.size()); return added; } @Override public Collection removeFlowRules(Collection rules) { - // Remove the valid rules from the device - Collection removed = rules.stream() - .map(r -> new LumentumFlowRule(r, getLinePorts())) - .filter(xc -> rpcDeleteConnection(xc)) - .collect(Collectors.toList()); + NetconfSession session = getNetconfSession(); + if (session == null) { + log.error("Device {} null session", did()); + return ImmutableList.of(); + } - // Remove flow rule from cache - CrossConnectCache cache = this.handler().get(CrossConnectCache.class); - removed.forEach(xc -> cache.remove( - Objects.hash(data().deviceId(), xc.selector()))); + // Remove the rules from the device and from the cache + List removed = new ArrayList<>(); + for (FlowRule r : rules) { + try { + LumentumFlowRule flowRule = new LumentumFlowRule(r, getLinePorts()); + rpcDeleteConnection(flowRule); + getConnectionCache().remove(did(), r); + removed.add(r); + } catch (Exception e) { + log.error("Device {} Error {}", did(), e); + continue; + } + } - removed.forEach(xc -> log.debug("Lumentum NETCONF - removed cached FlowRule selector {} treatment {}", - xc.selector(), xc.treatment())); + //Print out number of removed rules from the device (without receiving errors) + log.debug("Device {} removeFlowRules removed {}", did(), removed.size()); return removed; } @@ -184,7 +188,6 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh requestBuilder.append(""); NetconfSession session = getNetconfSession(); - if (session == null) { log.error("Lumentum NETCONF - session not found for {}", handler().data().deviceId()); return ImmutableList.of(); @@ -192,7 +195,7 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh try { reply = session.get(requestBuilder.toString(), null); - log.info("Lumentum NETCONF - fetchConnectionsFromDevice reply {}", reply); + log.debug("Lumentum NETCONF - fetchConnectionsFromDevice reply {}", reply); } catch (NetconfException e) { log.error("Failed to retrieve configuration details for device {}", handler().data().deviceId(), e); @@ -238,6 +241,15 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh String dn = connection.getString(DN); Pair pair = parseDn(dn); + short connId = pair.getRight(); + short moduleId = pair.getLeft(); + + if (pair == null) { + log.error("Lumentum NETCONF - device {} error in retrieving DN field", did()); + return null; + } + + log.debug("Lumentum NETCONF - retrieved FlowRule module {} connection {}", moduleId, connId); HierarchicalConfiguration config = connection.configurationAt(CONFIG); double startFreq = config.getDouble(START_FREQ); @@ -250,65 +262,44 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh double inputPower = state.getDouble(CHANNEL_INPUT_POWER); double outputPower = state.getDouble(CHANNEL_OUTPUT_POWER); - if (pair == null) { - return null; - } - - PortNumber portNumber = getPortNumber(pair.getLeft(), inputPortReference, outputPortReference); + PortNumber portNumber = getPortNumber(moduleId, inputPortReference, outputPortReference); + //If rule is on module 1 it means input port in the Flow rule is contained in portNumber. + //Otherwise the input port in the Flow rule must is the line port. TrafficSelector selector = DefaultTrafficSelector.builder() - .matchInPort(pair.getLeft() == 1 ? portNumber : LINE_PORT_NUMBER) + .matchInPort(moduleId == 1 ? portNumber : LINE_PORT_NUMBER) .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID)) .add(Criteria.matchLambda(toOchSignal(startFreq, endFreq))) .build(); log.debug("Lumentum NETCONF - retrieved FlowRule startFreq {} endFreq {}", startFreq, endFreq); - // Lookup flow ID and priority - int hash = Objects.hash(data().deviceId(), selector); - CrossConnectCache cache = this.handler().get(CrossConnectCache.class); - Pair lookup = cache.get(hash); - - LumentumConnection conn = CONNECTION_SET.stream() - .filter(c -> hash == c.getHash()) - .findFirst() - .orElse(null); - - TrafficTreatment treatment; - if (conn.rule.type == LumentumFlowRule.Type.OPTICAL_CONNECTIVITY_INTENT_RULE) { - treatment = DefaultTrafficTreatment.builder() - .add(Instructions.modL0Lambda(toOchSignal(startFreq, endFreq))) - .setOutput(pair.getLeft() == 1 ? LINE_PORT_NUMBER : portNumber) - .build(); - } else { // This is ROADM_APP_RULE - treatment = DefaultTrafficTreatment.builder() - .setOutput(pair.getLeft() == 1 ? LINE_PORT_NUMBER : portNumber) - .build(); + //Lookup of connection + //Retrieved rules, cached rules are considered equal if the selector is equal + FlowRule cacheRule = null; + if (getConnectionCache().size(did()) != 0) { + cacheRule = getConnectionCache().get(did()).stream() + .filter(r -> (r.selector().equals(selector))) + .findFirst() + .orElse(null); } - //If the flow entry is not in the cache: return null/publish the flow rule - if ((lookup == null) || (conn == null)) { - log.error("Lumentum NETCONF connection not in connectionSet {}", pair.getRight()); - rpcDeleteUnwantedConnection(pair.getRight().toString()); - return null; + + if (cacheRule == null) { + //TODO consider a way to keep "external" FlowRules + log.error("Lumentum NETCONF connection not in the cache {}", pair.getRight()); + rpcDeleteExternalConnection(moduleId, connId); + return null; } else { - log.debug("Lumentum NETCONF attenuation and parameters set {} for connection id {}", - attenuation, - conn.getConnectionId()); + //Update monitored values + log.debug("Attenuation retrieved {} dB for connection {}", + attenuation, ((LumentumFlowRule) cacheRule).getConnectionId()); + ((LumentumFlowRule) cacheRule).setAttenuation(attenuation); + ((LumentumFlowRule) cacheRule).setInputPower(inputPower); + ((LumentumFlowRule) cacheRule).setOutputPower(outputPower); - conn.setAttenuation(attenuation); - conn.setInputPower(inputPower); - conn.setOutputPower(outputPower); + return cacheRule; } - - return DefaultFlowRule.builder() - .forDevice(data().deviceId()) - .makePermanent() - .withSelector(selector) - .withTreatment(treatment) - .withPriority(lookup.getRight()) - .withCookie(lookup.getLeft().value()) - .build(); } /** @@ -339,47 +330,16 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh */ private Pair setModuleConnection(LumentumFlowRule xc, Integer id) { if (xc.isAddRule()) { + xc.setConnectionModule((short) 1); + xc.setConnectionId(id.shortValue()); return Pair.of((short) 1, id.shortValue()); } else { + xc.setConnectionModule((short) 2); + xc.setConnectionId(id.shortValue()); return Pair.of((short) 2, id.shortValue()); } } - /** - * Retrieve module and connection from the cache. - * - * Connection number is incremental within the class and associated to the rule hash. - * - * @param xc the cross connect flow - * @return pair of module (1 for MUX/ADD, 2 for DEMUX/DROP) and connection number - */ - private Pair retrieveModuleConnection(LumentumFlowRule xc) { - - int hash = Objects.hash(data().deviceId(), xc.selector()); - - LumentumConnection retrievedConnection = CONNECTION_SET.stream() - .filter(conn -> conn.getHash() == hash) - .findFirst() - .orElse(null); - - if (retrievedConnection == null) { - log.error("Lumentum connection not found"); - return null; - } - - //Remove connection id from the local cache - CONNECTION_SET.remove(retrievedConnection); - - log.debug("Lumentum NETCONF - retrieveModuleConnection {} retrievedConnectionId {} port {}", - xc.isAddRule(), retrievedConnection.getConnectionId(), xc.addDrop()); - - if (xc.isAddRule()) { - return Pair.of((short) 1, retrievedConnection.getConnectionId().shortValue()); - } else { - return Pair.of((short) 2, retrievedConnection.getConnectionId().shortValue()); - } - } - //Following Lumentum documentation rpc operation to configure a new connection private boolean rpcAddConnection(LumentumFlowRule xc) { @@ -390,11 +350,6 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh return false; } - LumentumConnection connection = new LumentumConnection(currentConnectionId, - Objects.hash(data().deviceId(), xc.selector()), xc); - - CONNECTION_SET.add(connection); - Pair pair = setModuleConnection(xc, currentConnectionId); String module = pair.getLeft().toString(); String connectionId = pair.getRight().toString(); @@ -431,7 +386,8 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh stringBuilder.append("" + "\n"); stringBuilder.append("" + "\n"); - log.info("Lumentum NETCONF - RPC add-connection {}", stringBuilder); + log.info("Lumentum ROADM20 - RPC add-connection sent to device {}", did()); + log.debug("Lumentum ROADM20 - RPC add-connection sent to device {} {}", did(), stringBuilder); return editCrossConnect(stringBuilder.toString()); } @@ -467,48 +423,59 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh stringBuilder.append("" + "\n"); stringBuilder.append("" + "\n"); - log.info("Lumentum {} - edit-connection {}", data().deviceId(), stringBuilder); + log.info("Lumentum ROADM20 - edit-connection sent to device {}", did()); + log.debug("Lumentum ROADM20 - edit-connection sent to device {} {}", did(), stringBuilder); return editCrossConnect(stringBuilder.toString()); } //Following Lumentum documentation rpc operation to delete a new connection private boolean rpcDeleteConnection(LumentumFlowRule xc) { - Pair pair = retrieveModuleConnection(xc); - if (pair == null) { + //Look for corresponding rule into the cache + FlowRule cacheRule = getConnectionCache().get(did()).stream() + .filter(r -> (r.selector().equals(xc.selector()) && r.treatment().equals(xc.treatment()))) + .findFirst() + .orElse(null); + + if (cacheRule == null) { log.error("Lumentum RPC delete-connection, connection not found on the local cache"); throw new IllegalStateException("Lumentum RPC delete-connection, connection not found on the local cache"); } - String module = pair.getLeft().toString(); - String connection = pair.getRight().toString(); + + int moduleId = ((LumentumFlowRule) cacheRule).getConnectionModule(); + int connId = ((LumentumFlowRule) cacheRule).getConnectionId(); + StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("" + "\n"); stringBuilder.append("" + "\n"); stringBuilder.append( - "ne=1;chassis=1;card=1;module=" + module + ";connection=" + connection + "" + "\n"); + "ne=1;chassis=1;card=1;module=" + moduleId + ";connection=" + connId + "" + "\n"); stringBuilder.append("" + "\n"); stringBuilder.append("" + " \n"); - log.info("Lumentum RPC delete-connection {}", stringBuilder); + log.info("Lumentum ROADM20 - RPC delete-connection sent to device {}", did()); + log.debug("Lumentum ROADM20 - - RPC delete-connection sent to device {} {}", did(), stringBuilder); return editCrossConnect(stringBuilder.toString()); } //Following Lumentum documentation rpc operation to delete a new connection //Executed if for some reason a connection not in the cache is detected - private boolean rpcDeleteUnwantedConnection(String connectionId) { + private boolean rpcDeleteExternalConnection(short moduleId, short connectionId) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("" + "\n"); stringBuilder.append("" + "\n"); - stringBuilder.append("ne=1;chassis=1;card=1;module=1;connection=" + connectionId + "" + "\n"); + stringBuilder.append("ne=1;chassis=1;card=1;module=" + + moduleId + ";connection=" + connectionId + "" + "\n"); stringBuilder.append("" + "\n"); stringBuilder.append("" + "\n"); - log.info("Lumentum {} - RPC delete-connection unwanted {}", data().deviceId(), stringBuilder); + log.info("Lumentum ROADM20 - RPC delete-external-connection sent to device {}", did()); + log.debug("Lumentum ROADM20 - - RPC delete-external-connection sent to device {} {}", did(), stringBuilder); return editCrossConnect(stringBuilder.toString()); } @@ -516,7 +483,6 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh private boolean editCrossConnect(String xcString) { NetconfSession session = getNetconfSession(); - if (session == null) { log.error("Lumentum NETCONF - session not found for device {}", handler().data().deviceId()); return false; @@ -532,20 +498,7 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh } } - private NetconfSession getNetconfSession() { - NetconfController controller = checkNotNull(handler().get(NetconfController.class)); - - try { - NetconfSession session = checkNotNull( - controller.getNetconfDevice(handler().data().deviceId()).getSession()); - return session; - } catch (NullPointerException e) { - log.error("Lumentum NETCONF - session not found for {}", handler().data().deviceId()); - return null; - } - } - - /** + /** * Convert start and end frequencies to OCh signal. * * FIXME: assumes slots of 12.5 GHz while devices allows granularity 6.25 GHz @@ -585,18 +538,43 @@ public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBeh * * Device only supports connection id < 100 */ - private static Integer generateConnectionId() { + private int generateConnectionId() { + //LUMENTUM_ROADM20_MAX_CONNECTIONS = 100, device only supports connection id < 100 + for (int i = 1; i < LUMENTUM_ROADM20_MAX_CONNECTIONS; i++) { + Set rulesForDevice = getConnectionCache().get(did()); - //Device only supports connection id < 100 - for (int i = 1; i < MAX_CONNECTIONS; i++) { - Set connIds = CONNECTION_SET.stream() - .map(conn -> conn.getConnectionId()) - .collect(Collectors.toSet()); + if (rulesForDevice == null) { + return 1; + } else { + Set connIds = rulesForDevice.stream() + .map(flow -> ((LumentumFlowRule) flow).getConnectionId()) + .collect(Collectors.toSet()); - if (!connIds.contains(i)) { - return i; + if (!connIds.contains(i)) { + return i; + } } } return 0; } + + private DeviceConnectionCache getConnectionCache() { + return DeviceConnectionCache.init(); + } + + /** + * Helper method to get the device id. + */ + private DeviceId did() { + return data().deviceId(); + } + + /** + * Helper method to get the Netconf session. + */ + private NetconfSession getNetconfSession() { + NetconfController controller = + checkNotNull(handler().get(NetconfController.class)); + return controller.getNetconfDevice(did()).getSession(); + } } diff --git a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumPowerConfig.java b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumPowerConfig.java index 16000bd0e4..7bc44c6d37 100644 --- a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumPowerConfig.java +++ b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumPowerConfig.java @@ -17,6 +17,8 @@ package org.onosproject.drivers.lumentum; import com.google.common.collect.Range; +import org.onosproject.drivers.odtn.impl.DeviceConnectionCache; +import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.OchSignal; import org.onosproject.net.behaviour.PowerConfig; @@ -27,8 +29,13 @@ import java.util.Optional; import java.util.Set; import java.util.stream.IntStream; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.netconf.NetconfController; +import org.onosproject.netconf.NetconfException; +import org.onosproject.netconf.NetconfSession; import org.slf4j.Logger; +import static com.google.common.base.Preconditions.checkNotNull; import static org.slf4j.LoggerFactory.getLogger; public class LumentumPowerConfig extends AbstractHandlerBehaviour @@ -43,6 +50,7 @@ public class LumentumPowerConfig extends AbstractHandlerBehaviour return Optional.ofNullable(acquireTargetPower(port, component)); } + //Used by the ROADM app to set the "attenuation" parameter @Override public void setTargetPower(PortNumber port, T component, long power) { if (component instanceof OchSignal) { @@ -101,22 +109,33 @@ public class LumentumPowerConfig extends AbstractHandlerBehaviour //TODO implement actual get configuration from the device //This is used by ROADM application to retrieve attenuation parameter, with T instanceof OchSignal + //The ROADM app expresses the attenuation in 0.01 dB units private Long acquireTargetPower(PortNumber port, T component) { log.debug("Lumentum get port {} target power...", port); if (component instanceof OchSignal) { - //FIXME include port in the filter - LumentumConnection conn = LumentumNetconfRoadmFlowRuleProgrammable.CONNECTION_SET.stream() - .filter(c -> c.ochSignal == component) - .findFirst() - .orElse(null); - if (conn == null) { - log.debug("Lumentum NETCONF fail to retrieve attenuation signal {} port {}", component, port); + Set rules = getConnectionCache().get(did()); + FlowRule rule; + + if (rules == null) { + log.error("Lumentum NETCONF fail to retrieve attenuation signal {} port {}", component, port); return 0L; } else { - log.debug("Lumentum NETCONF on port {} attenuation {}", port, conn.attenuation); - return ((long) (conn.attenuation * 100)); + rule = rules.stream() + .filter(c -> ((LumentumFlowRule) c).getOutputPort() == port) + .filter(c -> ((LumentumFlowRule) c).ochSignal() == component) + .findFirst() + .orElse(null); + } + + if (rule == null) { + log.error("Lumentum NETCONF fail to retrieve attenuation signal {} port {}", component, port); + return 0L; + } else { + log.debug("Lumentum NETCONF on port {} attenuation {}", port, + (((LumentumFlowRule) rule).attenuation * 100)); + return ((long) (((LumentumFlowRule) rule).attenuation * 100)); } } @@ -124,23 +143,32 @@ public class LumentumPowerConfig extends AbstractHandlerBehaviour } //TODO implement actual get configuration from the device - //This is used by ROADM application to retrieve attenuation parameter, with T instanceof OchSignal + //This is used by ROADM application to retrieve power parameter, with T instanceof OchSignal private Long acquireCurrentPower(PortNumber port, T component) { log.debug("Lumentum get port {} current power...", port); if (component instanceof OchSignal) { - //FIXME include port in the filter - LumentumConnection conn = LumentumNetconfRoadmFlowRuleProgrammable.CONNECTION_SET.stream() - .filter(c -> c.ochSignal == component) - .findFirst() - .orElse(null); - if (conn == null) { - log.debug("Lumentum NETCONF fail to retrieve power signal {} port {}", component, port); + Set rules = getConnectionCache().get(did()); + FlowRule rule; + + if (rules == null) { + log.error("Lumentum NETCONF fail to retrieve power signal {} port {}", component, port); return 0L; } else { - log.debug("Lumentum NETCONF on port {} power {}", port, conn.inputPower); - return ((long) (conn.inputPower * 100)); + rule = rules.stream() + .filter(c -> ((LumentumFlowRule) c).getInputPort() == port) + .filter(c -> ((LumentumFlowRule) c).ochSignal() == component) + .findFirst() + .orElse(null); + } + + if (rule == null) { + log.error("Lumentum NETCONF fail to retrieve power signal {} port {}", component, port); + return 0L; + } else { + log.debug("Lumentum NETCONF on port {} power {}", port, (((LumentumFlowRule) rule).inputPower)); + return ((long) (((LumentumFlowRule) rule).inputPower * 100)); } } @@ -167,9 +195,103 @@ public class LumentumPowerConfig extends AbstractHandlerBehaviour log.debug("Set port {} target power {}", port, power); } - //TODO implement configuration on the device - //Nothing to do + //Used by the ROADM app to set the "attenuation" parameter private void setConnectionTargetPower(PortNumber port, OchSignal signal, long power) { log.debug("Set connection target power {} ochsignal {} port {}", power, signal, port); + + Set rules = getConnectionCache().get(did()); + FlowRule rule = null; + + if (rules == null) { + log.error("Lumentum NETCONF fail to retrieve power signal {} port {}", signal, port); + } else { + rule = rules.stream() + .filter(c -> ((LumentumFlowRule) c).getOutputPort() == port) + .filter(c -> ((LumentumFlowRule) c).ochSignal() == signal) + .findFirst() + .orElse(null); + } + + if (rule == null) { + log.error("Lumentum NETCONF fail to retrieve attenuation signal {} port {}", signal, port); + } else { + log.debug("Lumentum NETCONF setting attenuation {} on port {} signal {}", power, port, signal); + + int moduleId = ((LumentumFlowRule) rule).getConnectionModule(); + int connId = ((LumentumFlowRule) rule).getConnectionId(); + + editConnection(moduleId, connId, power); + } + } + + + private DeviceConnectionCache getConnectionCache() { + return DeviceConnectionCache.init(); + } + + //Following Lumentum documentation operation to edit connection parameter + //Currently only edit the "attenuation" parameter + private boolean editConnection(int moduleId, int connectionId, long attenuation) { + + double attenuationDouble = ((double) attenuation); + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + + "ne=1;chassis=1;card=1;module=" + moduleId + ";connection=" + connectionId + "" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + attenuationDouble + "" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + stringBuilder.append("" + "\n"); + + log.info("Lumentum ROADM20 - edit-connection sent to device {}", did()); + log.debug("Lumentum ROADM20 - edit-connection sent to device {} {}", did(), stringBuilder); + + return editCrossConnect(stringBuilder.toString()); + } + + private boolean editCrossConnect(String xcString) { + NetconfSession session = getNetconfSession(); + + if (session == null) { + log.error("Lumentum NETCONF - session not found for device {}", handler().data().deviceId()); + return false; + } + + try { + return session.editConfig(xcString); + } catch (NetconfException e) { + log.error("Failed to edit the CrossConnect edid-cfg for device {}", + handler().data().deviceId(), e); + log.debug("Failed configuration {}", xcString); + return false; + } + } + + /** + * Helper method to get the device id. + */ + private DeviceId did() { + return data().deviceId(); + } + + /** + * Helper method to get the Netconf session. + */ + private NetconfSession getNetconfSession() { + NetconfController controller = + checkNotNull(handler().get(NetconfController.class)); + return controller.getNetconfDevice(did()).getSession(); } } \ No newline at end of file diff --git a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumRoadmLambdaQuery.java b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumRoadmLambdaQuery.java index cfd54c895e..53fdc6361d 100644 --- a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumRoadmLambdaQuery.java +++ b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumRoadmLambdaQuery.java @@ -17,17 +17,19 @@ package org.onosproject.drivers.lumentum; import org.onlab.util.Frequency; import org.onlab.util.Spectrum; -import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; +import org.onosproject.net.ChannelSpacing; import org.onosproject.net.OchSignal; +import org.onosproject.net.Port; import org.onosproject.net.PortNumber; import org.onosproject.net.behaviour.LambdaQuery; +import org.onosproject.net.device.DeviceService; import org.onosproject.net.driver.AbstractHandlerBehaviour; +import java.util.Collections; import java.util.Set; import java.util.stream.IntStream; import java.util.stream.Collectors; -import com.google.common.collect.Sets; /** * Implementation of lambda query interface for Lumentum ROADMs. @@ -53,19 +55,23 @@ public class LumentumRoadmLambdaQuery extends AbstractHandlerBehaviour implement private static final int LAMBDA_COUNT_100 = 48; @Override - public Set queryLambdas(PortNumber port) { + public Set queryLambdas(PortNumber portNumber) { + DeviceService deviceService = this.handler().get(DeviceService.class); + Port port = deviceService.getPort(data().deviceId(), portNumber); - //Complete set of 50GHz OchSignal - int startMultiplier50 = (int) (START_CENTER_FREQ_50.subtract(Spectrum.CENTER_FREQUENCY).asHz() - / Frequency.ofGHz(50).asHz()); + if (port.type() == Port.Type.FIBER) { - Set channels50 = IntStream.range(0, LAMBDA_COUNT_50) - .mapToObj(x -> new OchSignal(GRID_TYPE, CHANNEL_SPACING_50, - startMultiplier50 + x, - 4)) - .collect(Collectors.toSet()); + //Complete set of 50GHz OchSignal + int startMultiplier50 = (int) (START_CENTER_FREQ_50.subtract(Spectrum.CENTER_FREQUENCY).asHz() + / Frequency.ofGHz(50).asHz()); - //Complete set of 100GHz OchSignal + Set channels50 = IntStream.range(0, LAMBDA_COUNT_50) + .mapToObj(x -> new OchSignal(GRID_TYPE, CHANNEL_SPACING_50, + startMultiplier50 + x, + 4)) + .collect(Collectors.toSet()); + + /*//Complete set of 100GHz OchSignal int startMultiplier100 = (int) (START_CENTER_FREQ_100.subtract(Spectrum.CENTER_FREQUENCY).asHz() / Frequency.ofGHz(100).asHz()); @@ -74,9 +80,12 @@ public class LumentumRoadmLambdaQuery extends AbstractHandlerBehaviour implement CHANNEL_SPACING_100, startMultiplier100 + x, 8)) .collect(Collectors.toSet()); - Set channels = Sets.union(channels50, channels100); + Set channels = Sets.union(channels50, channels100);*/ - return channels; + return channels50; + } else { + return Collections.emptySet(); + } } }