| /* |
| * 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.driver.optical.flowrule.CrossConnectCache; |
| import org.onosproject.driver.optical.flowrule.CrossConnectFlowRule; |
| import org.onosproject.drivers.utilities.XmlConfigParser; |
| import org.onosproject.net.ChannelSpacing; |
| import org.onosproject.net.GridType; |
| import org.onosproject.net.OchSignal; |
| import org.onosproject.net.OchSignalType; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.net.device.DeviceService; |
| import org.onosproject.net.driver.AbstractHandlerBehaviour; |
| import org.onosproject.net.flow.DefaultFlowEntry; |
| import org.onosproject.net.flow.DefaultFlowRule; |
| import org.onosproject.net.flow.DefaultTrafficSelector; |
| import org.onosproject.net.flow.DefaultTrafficTreatment; |
| import org.onosproject.net.flow.FlowEntry; |
| import org.onosproject.net.flow.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.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.stream.Collectors; |
| import java.util.Collection; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.List; |
| import java.util.HashSet; |
| |
| 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 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<LumentumConnection> CONNECTION_SET = new HashSet<>(); |
| |
| /**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() { |
| 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())); |
| } |
| |
| /**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) { |
| // Apply the rules on the device |
| Collection<FlowRule> added = rules.stream() |
| .map(r -> new CrossConnectFlowRule(r, getLinePorts())) |
| .filter(xc -> rpcAddConnection(xc)) |
| .collect(Collectors.toList()); |
| |
| // Cache the cookie/priority |
| CrossConnectCache cache = this.handler().get(CrossConnectCache.class); |
| added.forEach(xc -> cache.set( |
| Objects.hash(data().deviceId(), xc.selector(), xc.treatment()), |
| xc.id(), |
| xc.priority())); |
| |
| added.forEach(xc -> log.debug("Lumentum build cached FlowRule selector {} treatment {}", |
| xc.selector().toString(), xc.treatment().toString())); |
| |
| return added; |
| } |
| |
| @Override |
| public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) { |
| // Remove the valid rules from the device |
| Collection<FlowRule> removed = rules.stream() |
| .map(r -> new CrossConnectFlowRule(r, getLinePorts())) |
| .filter(xc -> rpcDeleteConnection(xc)) |
| .collect(Collectors.toList()); |
| |
| // Remove flow rule from cache |
| CrossConnectCache cache = this.handler().get(CrossConnectCache.class); |
| removed.forEach(xc -> cache.remove( |
| Objects.hash(data().deviceId(), xc.selector(), xc.treatment()))); |
| |
| removed.forEach(xc -> log.debug("Lumentum NETCONF - removed cached FlowRule selector {} treatment {}", |
| xc.selector(), xc.treatment())); |
| |
| 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.info("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); |
| |
| 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); |
| |
| if (pair == null) { |
| return null; |
| } |
| |
| PortNumber portNumber = getPortNumber(pair.getLeft(), inputPortReference, outputPortReference); |
| |
| TrafficSelector selector = DefaultTrafficSelector.builder() |
| .matchInPort(pair.getLeft() == 1 ? portNumber : LINE_PORT_NUMBER) |
| .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID)) |
| .add(Criteria.matchLambda(toOchSignal(startFreq, endFreq))) |
| .build(); |
| TrafficTreatment treatment = DefaultTrafficTreatment.builder() |
| .setOutput(pair.getLeft() == 1 ? LINE_PORT_NUMBER : portNumber) |
| .build(); |
| |
| log.debug("Lumentum NETCONF - retrieved FlowRule startFreq {} endFreq {}", startFreq, endFreq); |
| |
| // Lookup flow ID and priority |
| int hash = Objects.hash(data().deviceId(), selector, treatment); |
| CrossConnectCache cache = this.handler().get(CrossConnectCache.class); |
| Pair<FlowId, Integer> lookup = cache.get(hash); |
| |
| LumentumConnection conn = CONNECTION_SET.stream() |
| .filter(c -> hash == c.getHash()) |
| .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; |
| } else { |
| log.debug("Lumentum NETCONF attenuation and parameters set {} for connection id {}", |
| attenuation, |
| conn.getConnectionId()); |
| |
| conn.setAttenuation(attenuation); |
| conn.setInputPower(inputPower); |
| conn.setOutputPower(outputPower); |
| } |
| |
| return DefaultFlowRule.builder() |
| .forDevice(data().deviceId()) |
| .makePermanent() |
| .withSelector(selector) |
| .withTreatment(treatment) |
| .withPriority(lookup.getRight()) |
| .withCookie(lookup.getLeft().value()) |
| .build(); |
| } |
| |
| /** |
| * 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(CrossConnectFlowRule xc, Integer id) { |
| if (xc.isAddRule()) { |
| return Pair.of((short) 1, id.shortValue()); |
| } else { |
| 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 rule |
| * @return pair of module (1 for MUX/ADD, 2 for DEMUX/DROP) and connection number |
| */ |
| private Pair<Short, Short> retrieveModuleConnection(CrossConnectFlowRule xc) { |
| |
| int hash = Objects.hash(data().deviceId(), xc.selector(), xc.treatment()); |
| |
| 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(CrossConnectFlowRule xc) { |
| |
| int currentConnectionId = generateConnectionId(); |
| |
| if (currentConnectionId == 0) { |
| log.error("Lumentum driver - 100 connections are already configured on the device"); |
| return false; |
| } |
| |
| LumentumConnection connection = new LumentumConnection(currentConnectionId, |
| Objects.hash(data().deviceId(), xc.selector(), xc.treatment()), xc); |
| |
| CONNECTION_SET.add(connection); |
| |
| 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 NETCONF - RPC add-connection {}", 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 {} - edit-connection {}", data().deviceId(), stringBuilder); |
| |
| return editCrossConnect(stringBuilder.toString()); |
| } |
| |
| //Following Lumentum documentation rpc operation to delete a new connection |
| private boolean rpcDeleteConnection(CrossConnectFlowRule xc) { |
| Pair<Short, Short> pair = retrieveModuleConnection(xc); |
| |
| if (pair == 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(); |
| |
| 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=" + module + ";connection=" + connection + "</dn>" + "\n"); |
| stringBuilder.append("</delete-connection>" + "\n"); |
| stringBuilder.append("</rpc>" + " \n"); |
| |
| log.info("Lumentum RPC delete-connection {}", 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) { |
| |
| 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=1;connection=" + connectionId + "</dn>" + "\n"); |
| stringBuilder.append("</delete-connection>" + "\n"); |
| stringBuilder.append("</rpc>" + "\n"); |
| |
| log.info("Lumentum {} - RPC delete-connection unwanted {}", data().deviceId(), 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; |
| } |
| } |
| |
| 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 |
| * 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 static Integer generateConnectionId() { |
| |
| //Device only supports connection id < 100 |
| for (int i = 1; i < MAX_CONNECTIONS; i++) { |
| Set<Integer> connIds = CONNECTION_SET.stream() |
| .map(conn -> conn.getConnectionId()) |
| .collect(Collectors.toSet()); |
| |
| if (!connIds.contains(i)) { |
| return i; |
| } |
| } |
| return 0; |
| } |
| } |