| /* |
| * 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 com.google.common.collect.ImmutableList; |
| 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.drivers.odtn.impl.DeviceConnectionCache; |
| import org.onosproject.drivers.utilities.XmlConfigParser; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.net.OchSignal; |
| import org.onosproject.net.OchSignalType; |
| 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.DefaultTrafficSelector; |
| 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.criteria.Criteria; |
| import org.onosproject.netconf.NetconfController; |
| import org.onosproject.netconf.NetconfException; |
| import org.onosproject.netconf.NetconfSession; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.ByteArrayInputStream; |
| import java.util.Collection; |
| import java.util.ArrayList; |
| import java.util.List; |
| 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; |
| |
| /** |
| * Implementation of FlowRuleProgrammable interface for Lumentum ROADM-A Whitebox devices using NETCONF. |
| */ |
| public class LumentumNetconfRoadmFlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable { |
| |
| private static final Logger log = |
| LoggerFactory.getLogger(LumentumNetconfRoadmFlowRuleProgrammable.class); |
| |
| private static final String DN = "dn"; |
| private static final String DN_PORT = "port="; |
| private static final String DN_CARD1 = "ne=1;chassis=1;card=1;port="; |
| private static final String CONNECTION = "connection"; |
| private static final String CONNECTIONS = "data.connections.connection"; |
| private static final String CONFIG = "config"; |
| private static final String STATE = "state"; |
| private static final String START_FREQ = "start-freq"; |
| private static final String END_FREQ = "end-freq"; |
| private static final String MODULE = "module"; |
| private static final String SEMI_COLON = ";"; |
| private static final String EQUAL = "="; |
| private static final String INPUT_PORT_REFERENCE = "input-port-reference"; |
| private static final String OUTPUT_PORT_REFERENCE = "output-port-reference"; |
| |
| private static final String CHANNEL_ATTENUATION = "attenuation"; |
| private static final String CHANNEL_INPUT_POWER = "input-channel-attributes.power"; |
| private static final String CHANNEL_OUTPUT_POWER = "output-channel-attributes.power"; |
| |
| protected static final long LINE_PORT = 3001; |
| protected static final PortNumber LINE_PORT_NUMBER = PortNumber.portNumber(LINE_PORT); |
| 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 LUMENTUM_ROADM20_MAX_CONNECTIONS = 100; |
| |
| /**Get the flow entries that are present on the Lumentum device, called by FlowRuleDriverProvider. |
| * |
| * 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() { |
| Collection<FlowEntry> 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. |
| * |
| * @param rules A collection of Flow Rules to be applied to the Lumentum device |
| * @return The collection of added Flow Entries |
| */ |
| @Override |
| public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) { |
| //Check NETCONF session |
| NetconfSession session = getNetconfSession(); |
| if (session == null) { |
| log.error("Device {} null session", did()); |
| return ImmutableList.of(); |
| } |
| |
| // Apply the rules on the device and add to cache if success |
| Collection<FlowRule> added = new ArrayList<>(); |
| for (FlowRule flowRule : rules) { |
| LumentumFlowRule lumFlowRule = new LumentumFlowRule(flowRule, getLinePorts()); |
| |
| 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<FlowRule> removeFlowRules(Collection<FlowRule> rules) { |
| NetconfSession session = getNetconfSession(); |
| if (session == null) { |
| log.error("Device {} null session", did()); |
| return ImmutableList.of(); |
| } |
| |
| // Remove the rules from the device and from the cache |
| List<FlowRule> 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; |
| } |
| } |
| |
| //Print out number of removed rules from the device (without receiving errors) |
| log.debug("Device {} removeFlowRules removed {}", did(), removed.size()); |
| |
| return removed; |
| } |
| |
| private List<PortNumber> getLinePorts() { |
| DeviceService deviceService = this.handler().get(DeviceService.class); |
| return deviceService.getPorts(data().deviceId()).stream() |
| .filter(p -> p.number().toLong() == LINE_PORT) |
| .map(p -> p.number()) |
| .collect(Collectors.toList()); |
| } |
| |
| /** |
| * Fetches list of connections from device. |
| * |
| * @return list of connections as XML hierarchy |
| */ |
| private List<HierarchicalConfiguration> fetchConnectionsFromDevice() { |
| String reply; |
| |
| StringBuilder requestBuilder = new StringBuilder(); |
| requestBuilder.append("<connections xmlns=\"http://www.lumentum.com/lumentum-ote-connection\">"); |
| requestBuilder.append("</connections>"); |
| |
| NetconfSession session = getNetconfSession(); |
| if (session == null) { |
| log.error("Lumentum NETCONF - session not found for {}", handler().data().deviceId()); |
| return ImmutableList.of(); |
| } |
| |
| try { |
| reply = session.get(requestBuilder.toString(), null); |
| log.debug("Lumentum NETCONF - fetchConnectionsFromDevice reply {}", reply); |
| } catch (NetconfException e) { |
| log.error("Failed to retrieve configuration details for device {}", |
| handler().data().deviceId(), e); |
| return ImmutableList.of(); |
| } |
| |
| HierarchicalConfiguration cfg = |
| XmlConfigParser.loadXml(new ByteArrayInputStream(reply.getBytes())); |
| |
| return cfg.configurationsAt(CONNECTIONS); |
| } |
| |
| // Example input dn: ne=1;chassis=1;card=1;module=2;connection=89 |
| private Pair<Short, Short> parseDn(String dn) { |
| Short module = null; |
| Short connection = null; |
| for (String entry : dn.split(SEMI_COLON)) { |
| String[] keyVal = entry.split(EQUAL); |
| if (keyVal.length != 2) { |
| continue; |
| } |
| if (keyVal[0].equals(MODULE)) { |
| module = Short.valueOf(keyVal[1]); |
| } |
| if (keyVal[0].equals(CONNECTION)) { |
| connection = Short.valueOf(keyVal[1]); |
| } |
| if (module != null && connection != null) { |
| return Pair.of(module, connection); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Builds a flow rule from a connection hierarchy. |
| * |
| * @param connection the connection hierarchy |
| * @return the flow rule |
| */ |
| private FlowRule buildFlowrule(HierarchicalConfiguration connection) { |
| |
| String dn = connection.getString(DN); |
| Pair<Short, Short> 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); |
| double endFreq = config.getDouble(END_FREQ); |
| String inputPortReference = config.getString(INPUT_PORT_REFERENCE); |
| String outputPortReference = config.getString(OUTPUT_PORT_REFERENCE); |
| |
| HierarchicalConfiguration state = connection.configurationAt(STATE); |
| double attenuation = state.getDouble(CHANNEL_ATTENUATION); |
| double inputPower = state.getDouble(CHANNEL_INPUT_POWER); |
| double outputPower = state.getDouble(CHANNEL_OUTPUT_POWER); |
| |
| 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(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 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 (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 { |
| //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); |
| |
| return cacheRule; |
| } |
| } |
| |
| /** |
| * Get the port number. |
| * If this is a MUX connection return input-port. Outport is always MUX_OUT = 4201. |
| * If this is a DEMUX connection return output-port. Inport is always DEMUX_IN= 5101. |
| * |
| * @param module the module (1 for MUX/ADD, 2 for DEMUX/DROP) |
| * @return the add/drop port number |
| */ |
| private PortNumber getPortNumber(short module, String inputPort, String outputPort) { |
| checkArgument(module == 1 || module == 2, "Module must be 1 (MUX/ADD) or 2 (DEMUX/DROP)"); |
| |
| if (module == 1) { |
| return PortNumber.portNumber(inputPort.split(DN_PORT)[1]); |
| } else { |
| return PortNumber.portNumber(outputPort.split(DN_PORT)[1]); |
| } |
| } |
| |
| /** |
| * Converts cross connect flow rule to module and connection. |
| * |
| * Connection number is incremental within the class and associated to the rule hash. |
| * |
| * @param xc the cross connect flow rule |
| * @return pair of module (1 for MUX/ADD, 2 for DEMUX/DROP) and connection number |
| */ |
| private Pair<Short, Short> 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()); |
| } |
| } |
| |
| //Following Lumentum documentation rpc operation to configure a new connection |
| private boolean rpcAddConnection(LumentumFlowRule xc) { |
| |
| int currentConnectionId = generateConnectionId(); |
| |
| if (currentConnectionId == 0) { |
| log.error("Lumentum driver - 100 connections are already configured on the device"); |
| return false; |
| } |
| |
| Pair<Short, Short> pair = setModuleConnection(xc, currentConnectionId); |
| String module = pair.getLeft().toString(); |
| String connectionId = pair.getRight().toString(); |
| |
| //Conversion of ochSignal format (center frequency + diameter) to Lumentum frequency slot format (start - end) |
| Frequency freqRadius = Frequency.ofHz(xc.ochSignal().channelSpacing().frequency().asHz() / 2); |
| Frequency center = xc.ochSignal().centralFrequency(); |
| String startFreq = String.valueOf(center.subtract(freqRadius).asHz() / GHZ); |
| String endFreq = String.valueOf(center.add(freqRadius).asHz() / GHZ); |
| |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">" + "\n"); |
| stringBuilder.append("<add-connection xmlns=\"http://www.lumentum.com/lumentum-ote-connection\">" + "\n"); |
| stringBuilder.append( |
| "<dn>ne=1;chassis=1;card=1;module=" + module + ";connection=" + connectionId + "</dn>" + "\n"); |
| stringBuilder.append("<start-freq>" + startFreq + "</start-freq>" + "\n"); |
| stringBuilder.append("<end-freq>" + endFreq + "</end-freq>" + "\n"); |
| stringBuilder.append("<attenuation>" + "0.0" + "</attenuation>" + "\n"); |
| stringBuilder.append("<blocked>" + "false" + "</blocked>" + "\n"); |
| stringBuilder.append("<maintenance-state>" + "in-service" + "</maintenance-state>" + "\n"); |
| |
| if (xc.isAddRule()) { |
| stringBuilder.append( |
| "<input-port-reference>" + DN_CARD1 + xc.addDrop().toString() + "</input-port-reference>" + "\n"); |
| stringBuilder.append( |
| "<output-port-reference>" + DN_CARD1 + MUX_OUT + "</output-port-reference>" + "\n"); |
| } else { |
| stringBuilder.append( |
| "<input-port-reference>" + DN_CARD1 + DEMUX_IN + "</input-port-reference>" + "\n"); |
| stringBuilder.append( |
| "<output-port-reference>" + DN_CARD1 + xc.addDrop().toString() + "</output-port-reference>" + "\n"); |
| } |
| stringBuilder.append("<custom-name>" + "onos-connection" + "</custom-name>" + "\n"); |
| stringBuilder.append("</add-connection>" + "\n"); |
| stringBuilder.append("</rpc>" + "\n"); |
| |
| 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()); |
| } |
| |
| //Following Lumentum documentation <edit-config> operation to edit connection parameter |
| //Currently only edit the "attenuation" parameter |
| private boolean editConnection(String moduleId, String connectionId, int attenuation) { |
| |
| double attenuationDouble = ((double) attenuation) / 100; |
| |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">" + "\n"); |
| stringBuilder.append("<edit-config>" + "\n"); |
| stringBuilder.append("<target>" + "\n"); |
| stringBuilder.append("<running/>" + "\n"); |
| stringBuilder.append("</target>" + "\n"); |
| stringBuilder.append("<config>" + "\n"); |
| stringBuilder.append("<connections xmlns=\"http://www.lumentum.com/lumentum-ote-connection\">" + "\n"); |
| stringBuilder.append("<connection>" + "\n"); |
| stringBuilder.append("" + |
| "<dn>ne=1;chassis=1;card=1;module=" + moduleId + ";connection=" + connectionId + "</dn>" + "\n"); |
| //Other configurable parameters |
| //stringBuilder.append("<custom-name/>" + "\n"); |
| //stringBuilder.append("<maintenance-state>" + "in-service" + "</maintenance-state>" + "\n"); |
| //stringBuilder.append("<start-freq>" + startFreq + "</start-freq>" + "\n"); |
| //stringBuilder.append("<end-freq>" + endFreq + "</end-freq>" + "\n"); |
| stringBuilder.append("<config>" + "\n"); |
| stringBuilder.append("<attenuation>" + attenuationDouble + "</attenuation>" + "\n"); |
| stringBuilder.append("</config>" + "\n"); |
| stringBuilder.append("</connection>" + "\n"); |
| stringBuilder.append("</connections>" + "\n"); |
| stringBuilder.append("</config>" + "\n"); |
| stringBuilder.append("</edit-config>" + "\n"); |
| stringBuilder.append("</rpc>" + "\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()); |
| } |
| |
| //Following Lumentum documentation rpc operation to delete a new connection |
| private boolean rpcDeleteConnection(LumentumFlowRule xc) { |
| |
| //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"); |
| } |
| |
| |
| int moduleId = ((LumentumFlowRule) cacheRule).getConnectionModule(); |
| int connId = ((LumentumFlowRule) cacheRule).getConnectionId(); |
| |
| |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">" + "\n"); |
| stringBuilder.append("<delete-connection xmlns=\"http://www.lumentum.com/lumentum-ote-connection\">" + "\n"); |
| stringBuilder.append( |
| "<dn>ne=1;chassis=1;card=1;module=" + moduleId + ";connection=" + connId + "</dn>" + "\n"); |
| stringBuilder.append("</delete-connection>" + "\n"); |
| stringBuilder.append("</rpc>" + " \n"); |
| |
| 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 rpcDeleteExternalConnection(short moduleId, short connectionId) { |
| |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">" + "\n"); |
| stringBuilder.append("<delete-connection xmlns=\"http://www.lumentum.com/lumentum-ote-connection\">" + "\n"); |
| stringBuilder.append("<dn>ne=1;chassis=1;card=1;module=" |
| + moduleId + ";connection=" + connectionId + "</dn>" + "\n"); |
| stringBuilder.append("</delete-connection>" + "\n"); |
| stringBuilder.append("</rpc>" + "\n"); |
| |
| 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()); |
| } |
| |
| |
| 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; |
| } |
| } |
| |
| /** |
| * Convert start and end frequencies to OCh signal. |
| * |
| * FIXME: assumes slots of 12.5 GHz while devices allows granularity 6.25 GHz |
| * FIXME: supports channel spacing 50 and 100 |
| * |
| * @param start starting frequency as double in GHz |
| * @param end end frequency as double in GHz |
| * @return OCh signal |
| */ |
| public static OchSignal toOchSignal(double start, double end) { |
| 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; |
| } |
| |
| /** |
| * Generate a valid connectionId, the connectionId is a field required by the device every time |
| * a connection is created/edited/removed. |
| * |
| * |
| * Device only supports connection id < 100 |
| */ |
| 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<FlowRule> rulesForDevice = getConnectionCache().get(did()); |
| |
| if (rulesForDevice == null) { |
| return 1; |
| } else { |
| Set<Integer> connIds = rulesForDevice.stream() |
| .map(flow -> ((LumentumFlowRule) flow).getConnectionId()) |
| .collect(Collectors.toSet()); |
| |
| 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(); |
| } |
| } |