Improve oplink roadm handshaker and PowerConfig driver
Change-Id: I326e3a6b405669d67ec08b0d23f3f164023efab6
diff --git a/drivers/optical/src/main/java/org/onosproject/driver/optical/handshaker/OplinkRoadm.java b/drivers/optical/src/main/java/org/onosproject/driver/optical/handshaker/OplinkRoadm.java
deleted file mode 100644
index 273469b..0000000
--- a/drivers/optical/src/main/java/org/onosproject/driver/optical/handshaker/OplinkRoadm.java
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * 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.driver.optical.handshaker;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.onosproject.drivers.optical.OpticalAdjacencyLinkService;
-import org.onosproject.net.Annotations;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultAnnotations;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DefaultPortDescription;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.device.PortDescription;
-import org.onosproject.net.link.DefaultLinkDescription;
-import org.onosproject.net.link.LinkService;
-import org.onosproject.net.optical.OpticalAnnotations;
-import org.onosproject.openflow.controller.Dpid;
-import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
-import org.onosproject.openflow.controller.PortDescPropertyType;
-import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
-import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
-import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
-import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
-import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
-import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
-import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
-import org.projectfloodlight.openflow.protocol.OFExpExtAdId;
-import org.projectfloodlight.openflow.protocol.OFExpPortAdidOtn;
-import org.projectfloodlight.openflow.protocol.OFExpPortAdjacency;
-import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyId;
-import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyReply;
-import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyRequest;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFObject;
-import org.projectfloodlight.openflow.protocol.OFOplinkPortPower;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFPortOptical;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.OFOplinkPortPowerRequest;
-import org.projectfloodlight.openflow.protocol.OFOplinkPortPowerReply;
-
-
-/**
- * Driver for Oplink single WSS 8D ROADM.
- *
- * Driver implements custom handshaker and supports for Optical channel Port based on OpenFlow OTN extension.
- * The device consists of Och ports, and performances wavelength cross-connect among the ports.
- */
-public class OplinkRoadm extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
-
- private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
- private List<OFPortOptical> opticalPorts;
-
- @Override
- public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
- return ImmutableList.copyOf(opticalPorts);
- }
-
- @Override
- /**
- * Returns a list of standard (Ethernet) ports.
- *
- * @return List of ports
- */
- public List<OFPortDesc> getPorts() {
- return Collections.EMPTY_LIST;
- }
-
- @Override
- public Set<PortDescPropertyType> getPortTypes() {
- return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
- }
-
- @Override
- public Boolean supportNxRole() {
- return false;
- }
-
- @Override
- public void startDriverHandshake() {
- log.warn("Starting driver handshake for sw {}", getStringId());
- if (startDriverHandshakeCalled) {
- throw new SwitchDriverSubHandshakeAlreadyStarted();
- }
- startDriverHandshakeCalled = true;
- try {
- sendHandshakeOFExperimenterPortDescRequest();
- } catch (IOException e) {
- log.error("OPLK ROADM exception while sending experimenter port desc:", e);
- }
- }
-
- @Override
- public boolean isDriverHandshakeComplete() {
- return driverHandshakeComplete.get();
- }
-
- @Override
- public void processDriverHandshakeMessage(OFMessage m) {
-
- if (!startDriverHandshakeCalled) {
- throw new SwitchDriverSubHandshakeNotStarted();
- }
-
- if (driverHandshakeComplete.get()) {
- throw new SwitchDriverSubHandshakeCompleted(m);
- }
-
- switch (m.getType()) {
- case BARRIER_REPLY:
- log.debug("OPLK ROADM Received barrier response");
- break;
- case ERROR:
- log.error("Switch {} Error {}", getStringId(), m);
- break;
- case FEATURES_REPLY:
- break;
- case FLOW_REMOVED:
- break;
- case GET_ASYNC_REPLY:
- break;
- case PACKET_IN:
- break;
- case PORT_STATUS:
- processOFPortStatus((OFCircuitPortStatus) m);
- break;
- case QUEUE_GET_CONFIG_REPLY:
- break;
- case ROLE_REPLY:
- break;
- case STATS_REPLY:
- OFStatsReply stats = (OFStatsReply) m;
- if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
- log.warn("OPLK ROADM : Received multipart (port desc) reply message {}", m);
- //OTN Optical extension 1.0 port-desc
- createOpticalPortList((OFCircuitPortsReply) m);
- driverHandshakeComplete.set(true);
- }
- break;
- default:
- log.warn("Received message {} during switch-driver " +
- "subhandshake " + "from switch {} ... " +
- "Ignoring message", m,
- getStringId());
-
- }
- }
-
- private void processOFPortStatus(OFCircuitPortStatus ps) {
- log.debug("OPLK ROADM ..OF Port Status :", ps);
- }
-
- @Override
- public Device.Type deviceType() {
- return Device.Type.ROADM;
- }
-
- @Override
- public final void sendMsg(OFMessage m) {
- List<OFMessage> messages = new ArrayList<>();
- messages.add(m);
-
- if (m.getType() == OFType.STATS_REQUEST) {
- OFStatsRequest sr = (OFStatsRequest) m;
- log.debug("OPLK ROADM rebuilding stats request type {}", sr.getStatsType());
- switch (sr.getStatsType()) {
- case PORT:
- //add Oplink experiment stats message to get the port's current power
- OFOplinkPortPowerRequest powerRequest = this.factory().buildOplinkPortPowerRequest()
- .setXid(sr.getXid())
- .setFlags(sr.getFlags())
- .build();
- messages.add(powerRequest);
- // add experiment message to get adjacent ports
- OFExpPortAdjacencyRequest adjacencyRequest = this.factory().buildExpPortAdjacencyRequest()
- .setXid(sr.getXid())
- .setFlags(sr.getFlags())
- .build();
- messages.add(adjacencyRequest);
- break;
- default:
- break;
- }
- } else {
- log.debug("OPLK ROADM sends msg:{}, as is", m.getType());
- }
-
- for (OFMessage message : messages) {
- super.sendMsg(message);
- }
- }
-
- private void sendHandshakeOFExperimenterPortDescRequest() throws IOException {
- // send multi part message for port description for optical switches
- OFCircuitPortsRequest circuitPortsRequest = factory()
- .buildCircuitPortsRequest().setXid(getNextTransactionId())
- .build();
- log.info("OPLK ROADM : Sending experimented circuit port stats " +
- "message " +
- "{}",
- circuitPortsRequest);
- this.sendHandshakeMessage(circuitPortsRequest);
- }
-
- /**
- * Builds list of OFPortOptical ports based on the multi-part circuit ports reply.
- * Ensure the optical transport port's signal type is configured correctly.
- *
- * @param wPorts OF reply with circuit ports
- */
- private void createOpticalPortList(OFCircuitPortsReply wPorts) {
- opticalPorts = new ArrayList<>();
- opticalPorts.addAll(wPorts.getEntries());
- }
-
- @Override
- public List<PortDescription> processExpPortStats(OFMessage msg) {
- if (msg instanceof OFOplinkPortPowerReply) {
- return buildPortPowerDescriptions(((OFOplinkPortPowerReply) msg).getEntries());
- } else if (msg instanceof OFExpPortAdjacencyReply) {
- return buildPortAdjacencyDescriptions(((OFExpPortAdjacencyReply) msg).getEntries());
- }
- return Collections.emptyList();
- }
-
- private List<PortDescription> buildPortPowerDescriptions(List<OFOplinkPortPower> portPowers) {
- DeviceService deviceService = this.handler().get(DeviceService.class);
- List<Port> ports = deviceService.getPorts(this.data().deviceId());
- HashMap<Long, OFOplinkPortPower> powerMap = new HashMap<>(portPowers.size());
- portPowers.forEach(power -> powerMap.put((long) power.getPort(), power));
- final List<PortDescription> portDescs = new ArrayList<>();
- for (Port port : ports) {
- DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
- builder.putAll(port.annotations());
- OFOplinkPortPower power = powerMap.get(port.number().toLong());
- if (power != null) {
- builder.set(OpticalAnnotations.CURRENT_POWER, Long.toString(power.getPowerValue()));
- }
- portDescs.add(new DefaultPortDescription(port.number(), port.isEnabled(),
- port.type(), port.portSpeed(), builder.build()));
- }
- return portDescs;
- }
-
- private OplinkPortAdjacency getNeighbor(OFExpPortAdjacency ad) {
- for (OFExpPortAdjacencyId adid : ad.getProperties()) {
- List<OFExpExtAdId> otns = adid.getAdId();
- if (otns != null && !otns.isEmpty()) {
- OFExpPortAdidOtn otn = (OFExpPortAdidOtn) otns.get(0);
- // ITU-T G.7714 ETH MAC Format (in second 16 bytes of the following)
- // |---------------------------------------------------------------------------|
- // | Other format (16 bytes) |
- // |---------------------------------------------------------------------------|
- // | Header (2 bytes) | ID (4 bits) | MAC (6 bytes) | Port (4 bytes) | Unused |
- // |---------------------------------------------------------------------------|
- ChannelBuffer buffer = ChannelBuffers.buffer(32);
- otn.getOpspec().write32Bytes(buffer);
- long mac = buffer.getLong(18) << 4 >>> 16;
- int port = (int) (buffer.getLong(24) << 4 >>> 32);
- // Oplink does not use the 4 most significant bytes of Dpid so Dpid can be
- // constructed from MAC address
- return new OplinkPortAdjacency(DeviceId.deviceId(Dpid.uri(new Dpid(mac))),
- PortNumber.portNumber(port));
- }
- }
- return null;
- }
-
- private List<PortDescription> buildPortAdjacencyDescriptions(List<OFExpPortAdjacency> portAds) {
- DeviceService deviceService = this.handler().get(DeviceService.class);
- List<Port> ports = deviceService.getPorts(this.data().deviceId());
-
- // Map port's number with port's adjacency
- HashMap<Long, OFExpPortAdjacency> adMap = new HashMap<>(portAds.size());
- portAds.forEach(ad -> adMap.put((long) ad.getPortNo().getPortNumber(), ad));
-
- List<PortDescription> portDescs = new ArrayList<>();
- for (Port port : ports) {
- DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
- Annotations oldAnnotations = port.annotations();
- builder.putAll(oldAnnotations);
- OFExpPortAdjacency ad = adMap.get(port.number().toLong());
- if (ad != null) {
- // neighbor discovered, add to port descriptions
- OplinkPortAdjacency neighbor = getNeighbor(ad);
- String newId = neighbor.getDeviceId().toString();
- String newPort = neighbor.getPort().toString();
- // Check if annotation already exists
- if (!newId.equals(oldAnnotations.value(OpticalAnnotations.NEIGHBOR_ID)) ||
- !newPort.equals(oldAnnotations.value(OpticalAnnotations.NEIGHBOR_PORT))) {
- builder.set(OpticalAnnotations.NEIGHBOR_ID, newId);
- builder.set(OpticalAnnotations.NEIGHBOR_PORT, newPort);
- }
- addLink(port.number(), neighbor);
- } else {
- // no neighbors found
- builder.remove(OpticalAnnotations.NEIGHBOR_ID);
- builder.remove(OpticalAnnotations.NEIGHBOR_PORT);
- removeLink(port.number());
- }
- portDescs.add(new DefaultPortDescription(port.number(), port.isEnabled(),
- port.type(), port.portSpeed(), builder.build()));
- }
- return portDescs;
- }
-
- private void addLink(PortNumber portNumber, OplinkPortAdjacency neighbor) {
- ConnectPoint dst = new ConnectPoint(handler().data().deviceId(), portNumber);
- ConnectPoint src = new ConnectPoint(neighbor.getDeviceId(), neighbor.getPort());
- OpticalAdjacencyLinkService adService =
- this.handler().get(OpticalAdjacencyLinkService.class);
- adService.linkDetected(new DefaultLinkDescription(src, dst, Link.Type.OPTICAL));
- }
-
- // Remove incoming link with port if there are any.
- private void removeLink(PortNumber portNumber) {
- ConnectPoint dst = new ConnectPoint(handler().data().deviceId(), portNumber);
- // Check so only incoming links are removed
- Set<Link> links = this.handler().get(LinkService.class).getIngressLinks(dst);
- if (!links.isEmpty()) {
- OpticalAdjacencyLinkService adService =
- this.handler().get(OpticalAdjacencyLinkService.class);
- adService.linksVanished(dst);
- }
- }
-
- private class OplinkPortAdjacency {
- private DeviceId deviceId;
- private PortNumber portNumber;
-
- public OplinkPortAdjacency(DeviceId deviceId, PortNumber portNumber) {
- this.deviceId = deviceId;
- this.portNumber = portNumber;
- }
-
- public DeviceId getDeviceId() {
- return deviceId;
- }
-
- public PortNumber getPort() {
- return portNumber;
- }
- }
-}
diff --git a/drivers/optical/src/main/java/org/onosproject/driver/optical/handshaker/OplinkRoadmHandshaker.java b/drivers/optical/src/main/java/org/onosproject/driver/optical/handshaker/OplinkRoadmHandshaker.java
new file mode 100644
index 0000000..d805f97
--- /dev/null
+++ b/drivers/optical/src/main/java/org/onosproject/driver/optical/handshaker/OplinkRoadmHandshaker.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.driver.optical.handshaker;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.onosproject.net.Device;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
+import org.onosproject.openflow.controller.PortDescPropertyType;
+import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
+import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
+import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
+import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
+import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFObject;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortOptical;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFOplinkPortPowerReply;
+
+import static org.onosproject.net.Device.Type;
+
+/**
+ * Driver for Oplink single WSS 8D ROADM.
+ *
+ * Driver implements custom handshaker and supports optical channel Port based on OpenFlow OTN extension.
+ * The device consists of Och ports, and performances wavelength cross-connect among the ports.
+ */
+public class OplinkRoadmHandshaker extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
+
+ private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
+ private List<OFPortOptical> opticalPorts = new ArrayList<>();
+ private OplinkHandshakerUtil oplinkUtil = new OplinkHandshakerUtil(this);
+
+ @Override
+ public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
+ // Expected type is OPTICAL_TRANSPORT
+ if (type == PortDescPropertyType.OPTICAL_TRANSPORT) {
+ return ImmutableList.copyOf(opticalPorts);
+ }
+ // Any other type, return empty
+ log.warn("Unexpected port description property type: {}", type);
+ return ImmutableList.of();
+ }
+
+ /**
+ * Returns a list of standard (Ethernet) ports.
+ *
+ * @return List of ports
+ */
+ @Override
+ public List<OFPortDesc> getPorts() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public Set<PortDescPropertyType> getPortTypes() {
+ return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
+ }
+
+ @Override
+ public Boolean supportNxRole() {
+ return false;
+ }
+
+ @Override
+ public void startDriverHandshake() {
+ log.info("Starting driver handshake for sw {}", getStringId());
+ if (startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeAlreadyStarted();
+ }
+ startDriverHandshakeCalled = true;
+ try {
+ sendHandshakeOFExperimenterPortDescRequest();
+ } catch (IOException e) {
+ log.error("OPLK ROADM exception while sending experimenter port desc:", e);
+ }
+ }
+
+ @Override
+ public boolean isDriverHandshakeComplete() {
+ return driverHandshakeComplete.get();
+ }
+
+ @Override
+ public void processDriverHandshakeMessage(OFMessage m) {
+
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+
+ if (driverHandshakeComplete.get()) {
+ throw new SwitchDriverSubHandshakeCompleted(m);
+ }
+
+ switch (m.getType()) {
+ case BARRIER_REPLY:
+ log.debug("OPLK ROADM Received barrier response");
+ break;
+ case ERROR:
+ log.error("Switch {} Error {}", getStringId(), m);
+ break;
+ case FEATURES_REPLY:
+ break;
+ case FLOW_REMOVED:
+ break;
+ case GET_ASYNC_REPLY:
+ break;
+ case PACKET_IN:
+ break;
+ case PORT_STATUS:
+ processOFPortStatus((OFCircuitPortStatus) m);
+ break;
+ case QUEUE_GET_CONFIG_REPLY:
+ break;
+ case ROLE_REPLY:
+ break;
+ case STATS_REPLY:
+ OFStatsReply stats = (OFStatsReply) m;
+ if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
+ log.debug("OPLK ROADM : Received multipart (port desc) reply message {}", m);
+ //OTN Optical extension 1.0 port-desc
+ createOpticalPortList((OFCircuitPortsReply) m);
+ driverHandshakeComplete.set(true);
+ }
+ break;
+ default:
+ log.warn("Received message {} during switch-driver " +
+ "subhandshake from switch {} ... " +
+ "Ignoring message", m, getStringId());
+
+ }
+ }
+
+ @Override
+ public Device.Type deviceType() {
+ return Type.ROADM;
+ }
+
+ @Override
+ public final void sendMsg(OFMessage m) {
+ List<OFMessage> messages = new ArrayList<>();
+ messages.add(m);
+
+ if (m.getType() == OFType.STATS_REQUEST) {
+ OFStatsRequest sr = (OFStatsRequest) m;
+ log.debug("OPLK ROADM rebuilding stats request type {}", sr.getStatsType());
+ switch (sr.getStatsType()) {
+ case PORT:
+ // add Oplink experiment message to get the port's current power
+ messages.add(oplinkUtil.buildPortPowerRequest());
+ // add experiment message to get adjacent ports
+ messages.add(oplinkUtil.buildPortAdjacencyRequest());
+ break;
+ default:
+ break;
+ }
+ } else {
+ log.debug("OPLK ROADM sends msg:{}, as is", m.getType());
+ }
+
+ super.sendMsg(messages);
+ }
+
+ @Override
+ public List<PortDescription> processExpPortStats(OFMessage msg) {
+ if (msg instanceof OFOplinkPortPowerReply) {
+ return oplinkUtil.buildPortPowerDescriptions(((OFOplinkPortPowerReply) msg).getEntries());
+ } else if (msg instanceof OFExpPortAdjacencyReply) {
+ return oplinkUtil.buildPortAdjacencyDescriptions(((OFExpPortAdjacencyReply) msg).getEntries());
+ }
+ return Collections.emptyList();
+ }
+
+ private void processOFPortStatus(OFCircuitPortStatus ps) {
+ log.debug("OPLK ROADM ..OF Port Status :", ps);
+ }
+
+ private void sendHandshakeOFExperimenterPortDescRequest() throws IOException {
+ // Send multipart message for port description for optical switches
+ OFCircuitPortsRequest circuitPortsRequest = oplinkUtil.buildCircuitPortsRequest();
+ log.debug("OPLK ROADM : Sending experimented port description message {}", circuitPortsRequest);
+ sendHandshakeMessage(circuitPortsRequest);
+ }
+
+ /**
+ * Builds list of OFPortOptical ports based on the multi-part circuit ports reply.
+ * Ensure the optical transport port's signal type is configured correctly.
+ *
+ * @param wPorts OF reply with circuit ports
+ */
+ private void createOpticalPortList(OFCircuitPortsReply wPorts) {
+ opticalPorts.addAll(wPorts.getEntries());
+ }
+
+}
diff --git a/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkEdfaPowerConfig.java b/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkEdfaPowerConfig.java
index 554df14..4538258 100644
--- a/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkEdfaPowerConfig.java
+++ b/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkEdfaPowerConfig.java
@@ -16,21 +16,12 @@
package org.onosproject.driver.optical.power;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.Optional;
import com.google.common.collect.Range;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
-import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.PowerConfig;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.optical.OpticalAnnotations;
-import org.onosproject.openflow.controller.Dpid;
-import org.onosproject.openflow.controller.OpenFlowController;
-import org.onosproject.openflow.controller.OpenFlowSwitch;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Port Power (Gain and attenuation) implementation for Oplink EDFA device.
@@ -43,148 +34,31 @@
public class OplinkEdfaPowerConfig extends AbstractHandlerBehaviour
implements PowerConfig<Object> {
- /**
- * Input and ouput port number
- * Note:
- * These port number configurations are just in use for a short time.
- * In the future, the port number and direction type would be obtained from physical device.
- */
- private static final int LINE_IN_WEST = 1;
- private static final int LINE_OUT_WEST = 2;
- private static final int LINE_IN_EAST = 3;
- private static final int LINE_OUT_EAST = 4;
-
- /**
- * Power threshold of each port, magnified 100 times
- * Note:
- * These threshold configurations are just in use for a short time.
- * In the future, the power threshold would be obtained from physical device.
- */
- private static final long POWER_IN_WEST_LOW_THRES = -1900L;
- private static final long POWER_IN_WEST_HIGH_THRES = 0L;
- private static final long POWER_IN_EAST_LOW_THRES = -3100L;
- private static final long POWER_IN_EAST_HIGH_THRES = 700L;
- private static final long POWER_OUT_LOW_THRES = 0L;
- private static final long POWER_OUT_HIGH_THRES = 1900L;
-
- // Transaction id to use.
- private final AtomicInteger xidCounter = new AtomicInteger(0);
- // Log
- protected final Logger log = LoggerFactory.getLogger(getClass());
+ // oplink power config utility
+ private OplinkPowerConfigUtil oplinkUtil = new OplinkPowerConfigUtil(this);
@Override
- public Optional<Long> getTargetPower(PortNumber portNum, Object component) {
- Long returnVal = getTargetPortPower(portNum);
- return Optional.ofNullable(returnVal);
+ public Optional<Long> getTargetPower(PortNumber port, Object component) {
+ return Optional.ofNullable(oplinkUtil.getTargetPower(port, component));
}
@Override
- public Optional<Long> currentPower(PortNumber portNum, Object component) {
- Long returnVal = getCurrentPortPower(portNum);
- return Optional.ofNullable(returnVal);
+ public Optional<Long> currentPower(PortNumber port, Object component) {
+ return Optional.ofNullable(oplinkUtil.getCurrentPower(port, component));
}
@Override
- public void setTargetPower(PortNumber portNum, Object component, long power) {
- setTargetPortPower(portNum, power);
+ public void setTargetPower(PortNumber port, Object component, long power) {
+ oplinkUtil.setTargetPower(port, component, power);
}
@Override
public Optional<Range<Long>> getTargetPowerRange(PortNumber port, Object component) {
- Range<Long> range = getTargetPortPowerRange(port);
- return Optional.ofNullable(range);
+ return Optional.ofNullable(oplinkUtil.getTargetPowerRange(port, component));
}
@Override
public Optional<Range<Long>> getInputPowerRange(PortNumber port, Object component) {
- Range<Long> range = getInputPortPowerRange(port);
- return Optional.ofNullable(range);
- }
-
- private OpenFlowSwitch getOpenFlowDevice() {
- final OpenFlowController controller = handler().get(OpenFlowController.class);
- final Dpid dpid = Dpid.dpid(data().deviceId().uri());
- OpenFlowSwitch sw = controller.getSwitch(dpid);
- if (sw == null || !sw.isConnected()) {
- log.warn("OpenFlow handshaker driver not found or device is not connected");
- return null;
- }
- return sw;
- }
-
- private Long getPowerFromPort(PortNumber portNum, String annotation) {
- // Check if switch is connected, otherwise do not return value in store, which is obsolete.
- if (getOpenFlowDevice() == null) {
- // Warning already exists in method getOpenFlowDevice()
- return null;
- }
- DeviceService deviceService = handler().get(DeviceService.class);
- Port port = deviceService.getPort(data().deviceId(), portNum);
- if (port == null) {
- log.warn("Unexpected port: {}", portNum);
- return null;
- }
- String power = port.annotations().value(annotation);
- if (power == null) {
- log.warn("Cannot get {} from port {}.", annotation, portNum);
- return null;
- }
- return Long.valueOf(power);
- }
-
- private Long getTargetPortPower(PortNumber portNum) {
- return getPowerFromPort(portNum, OpticalAnnotations.TARGET_POWER);
- }
-
- private Long getCurrentPortPower(PortNumber portNum) {
- return getPowerFromPort(portNum, OpticalAnnotations.CURRENT_POWER);
- }
-
- private void setTargetPortPower(PortNumber portNum, long power) {
- OpenFlowSwitch device = getOpenFlowDevice();
- // Check if switch is connected, otherwise do not return value in store, which is obsolete.
- if (device == null) {
- // Warning already exists in method getOpenFlowDevice()
- return;
- }
- device.sendMsg(device.factory().buildOplinkPortPowerSet()
- .setXid(xidCounter.getAndIncrement())
- .setPort((int) portNum.toLong())
- .setPowerValue((int) power)
- .build());
- }
-
- // Returns the acceptable target range for an output Port, null otherwise
- private Range<Long> getTargetPortPowerRange(PortNumber port) {
- long portNum = port.toLong();
- // FIXME
- // Short time hard code, we will use port direction type instead in the future.
- // And more, the power range will be also obtained from device configuration.
- switch ((int) portNum) {
- case LINE_OUT_EAST:
- case LINE_OUT_WEST:
- return Range.closed(POWER_OUT_LOW_THRES, POWER_OUT_HIGH_THRES);
- default:
- // Unexpected port. Do not need warning here for port polling.
- return null;
- }
- }
-
- // Returns the working input power range for an input port, null if the port
- // is not an input port.
- private Range<Long> getInputPortPowerRange(PortNumber port) {
- long portNum = port.toLong();
- // FIXME
- // Short time hard code, we will use port direction type instead in the future.
- // And more, the power range will be also obtained from device configuration.
- switch ((int) portNum) {
- case LINE_IN_EAST:
- return Range.closed(POWER_IN_EAST_LOW_THRES, POWER_IN_EAST_HIGH_THRES);
- case LINE_IN_WEST:
- return Range.closed(POWER_IN_WEST_LOW_THRES, POWER_IN_WEST_HIGH_THRES);
- default:
- // Unexpected port. Do not need warning here for port polling.
- return null;
- }
+ return Optional.ofNullable(oplinkUtil.getInputPowerRange(port, component));
}
}
diff --git a/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkPowerConfigUtil.java b/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkPowerConfigUtil.java
new file mode 100644
index 0000000..a24df09
--- /dev/null
+++ b/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkPowerConfigUtil.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.driver.optical.power;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.List;
+
+import com.google.common.collect.Range;
+
+import org.onosproject.driver.extensions.OplinkAttenuation;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.Direction;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.HandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.OchSignalCriterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.optical.OpticalAnnotations;
+import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.OpenFlowController;
+import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.PortDescPropertyType;
+import org.projectfloodlight.openflow.protocol.OFObject;
+import org.projectfloodlight.openflow.protocol.OFPortOptical;
+
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import static org.onosproject.net.Device.Type;
+
+/**
+ * Oplink power config utility.
+ */
+public class OplinkPowerConfigUtil {
+
+ // Parent driver handler behaviour
+ private HandlerBehaviour behaviour;
+ // Transaction id to use.
+ private final AtomicInteger xidCounter = new AtomicInteger(0);
+ // Log
+ private final Logger log = getLogger(getClass());
+
+ // Component type
+ private enum ComponentType {
+ NONE,
+ PORT,
+ CHANNEL
+ }
+
+ // Port properties for oplink devices, currently supports EDFA and ROADM.
+ // This type is mapped to OFPortDescPropOpticalTransport#getPortType() value.
+ private enum PortDescType {
+ NONE,
+ PA_LINE_IN,
+ PA_LINE_OUT,
+ BA_LINE_IN,
+ BA_LINE_OUT,
+ EXP_IN,
+ EXP_OUT,
+ AUX_IN,
+ AUX_OUT,
+ }
+
+ /**
+ * Power threshold of each port, in 0.01 dB
+ * Note:
+ * These threshold configurations are just in use for a short time.
+ * In the future, the power threshold would be obtained from physical device.
+ */
+ // EDFA
+ private static final long EDFA_POWER_IN_WEST_LOW_THRES = -1900L;
+ private static final long EDFA_POWER_IN_WEST_HIGH_THRES = 0L;
+ private static final long EDFA_POWER_IN_EAST_LOW_THRES = -3100L;
+ private static final long EDFA_POWER_IN_EAST_HIGH_THRES = 700L;
+ private static final long EDFA_POWER_OUT_LOW_THRES = 0L;
+ private static final long EDFA_POWER_OUT_HIGH_THRES = 1900L;
+ // ROADM
+ private static final long ROADM_POWER_LINE_IN_LOW_THRES = -3000L;
+ private static final long ROADM_POWER_LINE_IN_HIGH_THRES = 2350L;
+ private static final long ROADM_POWER_LINE_OUT_LOW_THRES = 0L;
+ private static final long ROADM_POWER_LINE_OUT_HIGH_THRES = 2350L;
+ private static final long ROADM_POWER_OTHER_IN_LOW_THRES = -1500L;
+ private static final long ROADM_POWER_OTHER_IN_HIGH_THRES = 2000L;
+ private static final long ROADM_POWER_OTHER_OUT_LOW_THRES = -600L;
+ private static final long ROADM_POWER_OTHER_OUT_HIGH_THRES = 1500L;
+ private static final long ROADM_MIN_ATTENUATION = 0L;
+ private static final long ROADM_MAX_ATTENUATION = 2500L;
+
+ /**
+ * Create a new OplinkPowerConfigUtil.
+ * @param behaviour driver handler behaviour
+ */
+ public OplinkPowerConfigUtil(HandlerBehaviour behaviour) {
+ this.behaviour = behaviour;
+ }
+
+ /**
+ * Obtains specified port/channel target power.
+ *
+ * @param port the port number
+ * @param component the port component
+ * @return target power value in .01 dBm
+ */
+ public Long getTargetPower(PortNumber port, Object component) {
+ switch (getComponentType(component)) {
+ case PORT:
+ return getPortPower(port, OpticalAnnotations.TARGET_POWER);
+ case CHANNEL:
+ return getChannelAttenuation(port, (OchSignal) component);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Obtains specified port/channel current power.
+ *
+ * @param port the port number
+ * @param component the port component
+ * @return current power value in .01 dBm
+ */
+ public Long getCurrentPower(PortNumber port, Object component) {
+ switch (getComponentType(component)) {
+ case PORT:
+ return getPortPower(port, OpticalAnnotations.CURRENT_POWER);
+ case CHANNEL:
+ return getCurrentChannelPower(port, (OchSignal) component);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Sets specified port target power or channel attenuation.
+ *
+ * @param port the port number
+ * @param component the port component
+ * @param power target power in .01 dBm
+ */
+ public void setTargetPower(PortNumber port, Object component, long power) {
+ switch (getComponentType(component)) {
+ case PORT:
+ setPortPower(port, power);
+ break;
+ case CHANNEL:
+ setChannelAttenuation(port, (OchSignal) component, power);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Returns the acceptable target range for an output port/channel, null otherwise.
+ *
+ * @param port the port number
+ * @param component the port component
+ * @return power range
+ */
+ public Range<Long> getTargetPowerRange(PortNumber port, Object component) {
+ switch (getComponentType(component)) {
+ case PORT:
+ return getTargetPortPowerRange(port);
+ case CHANNEL:
+ return getChannelAttenuationRange(port);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Returns the working input power range for an input port, null otherwise.
+ *
+ * @param port the port number
+ * @param component the port component
+ * @return power range
+ */
+ public Range<Long> getInputPowerRange(PortNumber port, Object component) {
+ switch (getComponentType(component)) {
+ case PORT:
+ return getInputPortPowerRange(port);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Returns specified component type.
+ *
+ * @param component the port component
+ * @return component type
+ */
+ private ComponentType getComponentType(Object component) {
+ if (component == null || component instanceof Direction) {
+ return ComponentType.PORT;
+ } else if (component instanceof OchSignal) {
+ return ComponentType.CHANNEL;
+ }
+ return ComponentType.NONE;
+ }
+
+ /**
+ * Returns current switch known to this OF controller.
+ *
+ * @return current switch
+ */
+ private OpenFlowSwitch getOpenFlowDevice() {
+ final DriverHandler handler = behaviour.handler();
+ final OpenFlowController controller = handler.get(OpenFlowController.class);
+ final Dpid dpid = Dpid.dpid(handler.data().deviceId().uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ if (sw == null || !sw.isConnected()) {
+ log.warn("OpenFlow handshaker driver not found or device is not connected, dpid = {}", dpid);
+ return null;
+ }
+ return sw;
+ }
+
+ /**
+ * Find oplink port description type from optical ports.
+ *
+ * @param opsw switch
+ * @param portNum the port number
+ * @return port oplink port description type
+ */
+ private PortDescType getPortDescType(OpenFlowOpticalSwitch opsw, PortNumber portNum) {
+ for (PortDescPropertyType type : opsw.getPortTypes()) {
+ List<? extends OFObject> portsOf = opsw.getPortsOf(type);
+ for (OFObject op : portsOf) {
+ if (op instanceof OFPortOptical) {
+ OFPortOptical opticalPort = (OFPortOptical) op;
+ if ((long) opticalPort.getPortNo().getPortNumber() == portNum.toLong()) {
+ return PortDescType.values()[opticalPort.getDesc().get(0).getPortType()];
+ }
+ }
+ }
+ }
+ return PortDescType.NONE;
+ }
+
+ /**
+ * Returns the target port power range.
+ *
+ * @param portNum the port number
+ * @return power range
+ */
+ private Range<Long> getTargetPortPowerRange(PortNumber portNum) {
+ OpenFlowSwitch ofs = getOpenFlowDevice();
+ if (ofs == null) {
+ return null;
+ }
+ PortDescType portType = getPortDescType((OpenFlowOpticalSwitch) ofs, portNum);
+ Type devType = ofs.deviceType();
+ // FIXME
+ // Short time hard code.
+ // The power range will be obtained from physical device in the future.
+ switch (devType) {
+ case OPTICAL_AMPLIFIER:
+ if (portType == PortDescType.PA_LINE_OUT || portType == PortDescType.BA_LINE_OUT) {
+ return Range.closed(EDFA_POWER_OUT_LOW_THRES, EDFA_POWER_OUT_HIGH_THRES);
+ }
+ break;
+ case ROADM:
+ if (portType == PortDescType.PA_LINE_OUT) {
+ return Range.closed(ROADM_POWER_LINE_OUT_LOW_THRES, ROADM_POWER_LINE_OUT_HIGH_THRES);
+ } else if (portType == PortDescType.EXP_OUT || portType == PortDescType.AUX_OUT) {
+ return Range.closed(ROADM_POWER_OTHER_OUT_LOW_THRES, ROADM_POWER_OTHER_OUT_HIGH_THRES);
+ }
+ break;
+ default:
+ log.warn("Unexpected device type: {}", devType);
+ break;
+ }
+ // Unexpected port or device type. Do not need warning here for port polling.
+ return null;
+ }
+
+ /**
+ * Returns the input port power range.
+ *
+ * @param portNum the port number
+ * @return power range
+ */
+ private Range<Long> getInputPortPowerRange(PortNumber portNum) {
+ OpenFlowSwitch ofs = getOpenFlowDevice();
+ if (ofs == null) {
+ return null;
+ }
+ PortDescType portType = getPortDescType((OpenFlowOpticalSwitch) ofs, portNum);
+ Type devType = ofs.deviceType();
+ // FIXME
+ // Short time hard code.
+ // The port type and power range will be obtained from physical device in the future.
+ switch (devType) {
+ case OPTICAL_AMPLIFIER:
+ if (portType == PortDescType.PA_LINE_IN) {
+ return Range.closed(EDFA_POWER_IN_WEST_LOW_THRES, EDFA_POWER_IN_WEST_HIGH_THRES);
+ } else if (portType == PortDescType.BA_LINE_IN) {
+ return Range.closed(EDFA_POWER_IN_EAST_LOW_THRES, EDFA_POWER_IN_EAST_HIGH_THRES);
+ }
+ break;
+ case ROADM:
+ if (portType == PortDescType.PA_LINE_IN) {
+ return Range.closed(ROADM_POWER_LINE_IN_LOW_THRES, ROADM_POWER_LINE_IN_HIGH_THRES);
+ } else if (portType == PortDescType.EXP_IN || portType == PortDescType.AUX_IN) {
+ return Range.closed(ROADM_POWER_OTHER_IN_LOW_THRES, ROADM_POWER_OTHER_IN_HIGH_THRES);
+ }
+ break;
+ default:
+ log.warn("Unexpected device type: {}", devType);
+ break;
+ }
+ // Unexpected port or device type. Do not need warning here for port polling.
+ return null;
+ }
+
+ /**
+ * Returns the acceptable attenuation range for a connection (represented as
+ * a flow with attenuation instruction). Port can be either the input or
+ * output port of the connection. Returns null if the connection does not
+ * support attenuation.
+ *
+ * @param portNum the port number
+ * @return attenuation range
+ */
+ private Range<Long> getChannelAttenuationRange(PortNumber portNum) {
+ OpenFlowSwitch ofs = getOpenFlowDevice();
+ if (ofs == null) {
+ return null;
+ }
+ if (ofs.deviceType() != Type.ROADM) {
+ return null;
+ }
+ PortDescType portType = getPortDescType((OpenFlowOpticalSwitch) ofs, portNum);
+ // Short time hard code.
+ // The port type and attenuation range will be obtained from physical device in the future.
+ if (portType == PortDescType.PA_LINE_OUT || portType == PortDescType.EXP_IN ||
+ portType == PortDescType.AUX_IN) {
+ return Range.closed(ROADM_MIN_ATTENUATION, ROADM_MAX_ATTENUATION);
+ }
+ // Unexpected port. Do not need warning here for port polling.
+ return null;
+ }
+
+ /**
+ * Find specified port power from port description.
+ *
+ * @param portNum the port number
+ * @param annotation annotation in port description
+ * @return power value in 0.01 dBm
+ */
+ private Long getPortPower(PortNumber portNum, String annotation) {
+ // Check if switch is connected, otherwise do not return value in store, which is obsolete.
+ if (getOpenFlowDevice() == null) {
+ // Warning already exists in method getOpenFlowDevice()
+ return null;
+ }
+ final DriverHandler handler = behaviour.handler();
+ DeviceService deviceService = handler.get(DeviceService.class);
+ Port port = deviceService.getPort(handler.data().deviceId(), portNum);
+ if (port == null) {
+ log.warn("Unexpected port: {}", portNum);
+ return null;
+ }
+ String power = port.annotations().value(annotation);
+ if (power == null) {
+ log.warn("Cannot get {} from port {}.", annotation, portNum);
+ return null;
+ }
+ return Long.valueOf(power);
+ }
+
+ /**
+ * Sets specified port power value.
+ *
+ * @param portNum the port number
+ * @param power power value
+ */
+ private void setPortPower(PortNumber portNum, long power) {
+ OpenFlowSwitch device = getOpenFlowDevice();
+ // Check if switch is connected
+ if (device == null) {
+ return;
+ }
+ device.sendMsg(device.factory().buildOplinkPortPowerSet()
+ .setXid(xidCounter.getAndIncrement())
+ .setPort((int) portNum.toLong())
+ .setPowerValue((int) power)
+ .build());
+ }
+
+ /**
+ * Gets specified channel attenuation.
+ *
+ * @param portNum the port number
+ * @param och channel signal
+ * @return atteuation in 0.01 dB
+ */
+ private Long getChannelAttenuation(PortNumber portNum, OchSignal och) {
+ FlowEntry flowEntry = findFlow(portNum, och);
+ if (flowEntry == null) {
+ return null;
+ }
+ List<Instruction> instructions = flowEntry.treatment().allInstructions();
+ for (Instruction ins : instructions) {
+ if (ins.type() != Instruction.Type.EXTENSION) {
+ continue;
+ }
+ ExtensionTreatment ext = ((Instructions.ExtensionInstructionWrapper) ins).extensionInstruction();
+ if (ext.type() == ExtensionTreatmentType.ExtensionTreatmentTypes.OPLINK_ATTENUATION.type()) {
+ return (long) ((OplinkAttenuation) ext).getAttenuation();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sets specified channle attenuation.
+ *
+ * @param portNum the port number
+ * @param och channel signal
+ * @param power attenuation in 0.01 dB
+ */
+ private void setChannelAttenuation(PortNumber portNum, OchSignal och, long power) {
+ FlowEntry flowEntry = findFlow(portNum, och);
+ if (flowEntry == null) {
+ log.warn("Target channel power not set");
+ return;
+ }
+ final DriverHandler handler = behaviour.handler();
+ for (Instruction ins : flowEntry.treatment().allInstructions()) {
+ if (ins.type() != Instruction.Type.EXTENSION) {
+ continue;
+ }
+ ExtensionTreatment ext = ((Instructions.ExtensionInstructionWrapper) ins).extensionInstruction();
+ if (ext.type() == ExtensionTreatmentType.ExtensionTreatmentTypes.OPLINK_ATTENUATION.type()) {
+ ((OplinkAttenuation) ext).setAttenuation((int) power);
+ FlowRuleService service = handler.get(FlowRuleService.class);
+ service.applyFlowRules(flowEntry);
+ return;
+ }
+ }
+ addAttenuation(flowEntry, power);
+ }
+
+ /**
+ * Gets specified channle current power.
+ *
+ * @param portNum the port number
+ * @param och channel signal
+ * @return power value in 0.01 dBm
+ */
+ private Long getCurrentChannelPower(PortNumber portNum, OchSignal och) {
+ FlowEntry flowEntry = findFlow(portNum, och);
+ if (flowEntry != null) {
+ // TODO put somewhere else if possible
+ // We put channel power in packets
+ return flowEntry.packets();
+ }
+ return null;
+ }
+
+ /**
+ * Find matching flow on device.
+ *
+ * @param portNum the port number
+ * @param och channel signal
+ * @return flow entry
+ */
+ private FlowEntry findFlow(PortNumber portNum, OchSignal och) {
+ final DriverHandler handler = behaviour.handler();
+ FlowRuleService service = handler.get(FlowRuleService.class);
+ Iterable<FlowEntry> flowEntries = service.getFlowEntries(handler.data().deviceId());
+
+ // Return first matching flow
+ for (FlowEntry entry : flowEntries) {
+ TrafficSelector selector = entry.selector();
+ OchSignalCriterion entrySigid =
+ (OchSignalCriterion) selector.getCriterion(Criterion.Type.OCH_SIGID);
+ // Check channel
+ if (entrySigid != null && och.equals(entrySigid.lambda())) {
+ // Check input port
+ PortCriterion entryPort =
+ (PortCriterion) selector.getCriterion(Criterion.Type.IN_PORT);
+ if (entryPort != null && portNum.equals(entryPort.port())) {
+ return entry;
+ }
+
+ // Check output port
+ TrafficTreatment treatment = entry.treatment();
+ for (Instruction instruction : treatment.allInstructions()) {
+ if (instruction.type() == Instruction.Type.OUTPUT &&
+ ((Instructions.OutputInstruction) instruction).port().equals(portNum)) {
+ return entry;
+ }
+ }
+ }
+ }
+ log.warn("No matching flow found");
+ return null;
+ }
+
+ /**
+ * Replace flow with new flow containing Oplink attenuation extension instruction. Also resets metrics.
+ *
+ * @param flowEntry flow entry
+ * @param power power value
+ */
+ private void addAttenuation(FlowEntry flowEntry, long power) {
+ FlowRule.Builder flowBuilder = new DefaultFlowRule.Builder()
+ .withCookie(flowEntry.id().value())
+ .withPriority(flowEntry.priority())
+ .forDevice(flowEntry.deviceId())
+ .forTable(flowEntry.tableId());
+ if (flowEntry.isPermanent()) {
+ flowBuilder.makePermanent();
+ } else {
+ flowBuilder.makeTemporary(flowEntry.timeout());
+ }
+ flowBuilder.withSelector(flowEntry.selector());
+ // Copy original instructions and add attenuation instruction
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+ flowEntry.treatment().allInstructions().forEach(ins -> treatmentBuilder.add(ins));
+ final DriverHandler handler = behaviour.handler();
+ treatmentBuilder.add(Instructions.extension(new OplinkAttenuation((int) power), handler.data().deviceId()));
+ flowBuilder.withTreatment(treatmentBuilder.build());
+
+ FlowRuleService service = handler.get(FlowRuleService.class);
+ service.applyFlowRules(flowBuilder.build());
+ }
+}
diff --git a/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkRoadmPowerConfig.java b/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkRoadmPowerConfig.java
index 3a7dc0c..4904168 100644
--- a/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkRoadmPowerConfig.java
+++ b/drivers/optical/src/main/java/org/onosproject/driver/optical/power/OplinkRoadmPowerConfig.java
@@ -16,38 +16,12 @@
package org.onosproject.driver.optical.power;
-import java.util.List;
import java.util.Optional;
import com.google.common.collect.Range;
-import org.onosproject.driver.extensions.OplinkAttenuation;
-import org.onosproject.net.OchSignal;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
-import org.onosproject.net.Direction;
-import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.PowerConfig;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.DefaultFlowRule;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowEntry;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.FlowRuleService;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criterion;
-import org.onosproject.net.flow.criteria.OchSignalCriterion;
-import org.onosproject.net.flow.criteria.PortCriterion;
-import org.onosproject.net.flow.instructions.ExtensionTreatment;
-import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.optical.OpticalAnnotations;
-import org.onosproject.openflow.controller.Dpid;
-import org.onosproject.openflow.controller.OpenFlowController;
-import org.onosproject.openflow.controller.OpenFlowSwitch;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Port Power (Gain and attenuation) implementation for Oplink 1-SLOT-8D ROADM.
@@ -60,314 +34,31 @@
public class OplinkRoadmPowerConfig extends AbstractHandlerBehaviour
implements PowerConfig<Object> {
- private static final int LINE_IN = 1;
- private static final int LINE_OUT = 2;
- private static final int AUX_OUT_1 = 3;
- private static final int AUX_OUT_2 = 4;
- private static final int EXPRESS_OUT_1 = 5;
- private static final int EXPRESS_OUT_2 = 6;
- private static final int EXPRESS_OUT_3 = 7;
- private static final int EXPRESS_OUT_4 = 8;
- private static final int EXPRESS_OUT_5 = 9;
- private static final int EXPRESS_OUT_6 = 10;
- private static final int EXPRESS_OUT_7 = 11;
- private static final int AUX_IN_1 = 12;
- private static final int AUX_IN_2 = 13;
- private static final int EXPRESS_IN_1 = 14;
- private static final int EXPRESS_IN_2 = 15;
- private static final int EXPRESS_IN_3 = 16;
- private static final int EXPRESS_IN_4 = 17;
- private static final int EXPRESS_IN_5 = 18;
- private static final int EXPRESS_IN_6 = 19;
- private static final int EXPRESS_IN_7 = 20;
+ // oplink power config utility
+ private OplinkPowerConfigUtil oplinkUtil = new OplinkPowerConfigUtil(this);
- protected final Logger log = LoggerFactory.getLogger(getClass());
-
- // Component type
- private enum Type {
- NONE,
- PORT,
- CHANNEL
- }
-
- // Get the type if component is valid
- private Type getType(Object component) {
- if (component == null || component instanceof Direction) {
- return Type.PORT;
- } else if (component instanceof OchSignal) {
- return Type.CHANNEL;
- } else {
- return Type.NONE;
- }
- }
-
- private OpenFlowSwitch getOpenFlowDevice() {
- final OpenFlowController controller = this.handler().get(OpenFlowController.class);
- final Dpid dpid = Dpid.dpid(this.data().deviceId().uri());
- OpenFlowSwitch sw = controller.getSwitch(dpid);
- if (sw == null || !sw.isConnected()) {
- return null;
- } else {
- return sw;
- }
- }
-
- // Find matching flow on device
- private FlowEntry findFlow(PortNumber portNum, OchSignal och) {
- FlowRuleService service = this.handler().get(FlowRuleService.class);
- Iterable<FlowEntry> flowEntries = service.getFlowEntries(this.data().deviceId());
-
- // Return first matching flow
- for (FlowEntry entry : flowEntries) {
- TrafficSelector selector = entry.selector();
- OchSignalCriterion entrySigid =
- (OchSignalCriterion) selector.getCriterion(Criterion.Type.OCH_SIGID);
- // Check channel
- if (entrySigid != null && och.equals(entrySigid.lambda())) {
- // Check input port
- PortCriterion entryPort =
- (PortCriterion) selector.getCriterion(Criterion.Type.IN_PORT);
- if (entryPort != null && portNum.equals(entryPort.port())) {
- return entry;
- }
-
- // Check output port
- TrafficTreatment treatment = entry.treatment();
- for (Instruction instruction : treatment.allInstructions()) {
- if (instruction.type() == Instruction.Type.OUTPUT &&
- ((Instructions.OutputInstruction) instruction).port().equals(portNum)) {
- return entry;
- }
- }
- }
- }
- log.warn("No matching flow found");
- return null;
+ @Override
+ public Optional<Long> getTargetPower(PortNumber port, Object component) {
+ return Optional.ofNullable(oplinkUtil.getTargetPower(port, component));
}
@Override
- public Optional<Long> getTargetPower(PortNumber portNum, Object component) {
- Long returnVal = null;
- // Check if switch is connected, otherwise do not return value in store,
- // which is obsolete.
- if (getOpenFlowDevice() != null) {
- switch (getType(component)) {
- case PORT:
- // Will be implemented in the future.
- break;
- case CHANNEL:
- returnVal = getChannelAttenuation(portNum, (OchSignal) component);
- break;
- default:
- break;
- }
- }
- return Optional.ofNullable(returnVal);
+ public Optional<Long> currentPower(PortNumber port, Object component) {
+ return Optional.ofNullable(oplinkUtil.getCurrentPower(port, component));
}
@Override
- public Optional<Long> currentPower(PortNumber portNum, Object component) {
- Long returnVal = null;
- // Check if switch is connected, otherwise do not return value in store,
- // which is obsolete.
- if (getOpenFlowDevice() != null) {
- switch (getType(component)) {
- case PORT:
- returnVal = getCurrentPortPower(portNum);
- break;
- case CHANNEL:
- returnVal = getCurrentChannelPower(portNum, (OchSignal) component);
- break;
- default:
- break;
- }
- }
- return Optional.ofNullable(returnVal);
- }
-
- @Override
- public void setTargetPower(PortNumber portNum, Object component, long power) {
- if (getOpenFlowDevice() != null) {
- switch (getType(component)) {
- case PORT:
- setTargetPortPower(portNum, power);
- break;
- case CHANNEL:
- setChannelAttenuation(portNum, (OchSignal) component, power);
- break;
- default:
- break;
- }
- } else {
- log.warn("OpenFlow handshaker driver not found or device is not connected");
- }
+ public void setTargetPower(PortNumber port, Object component, long power) {
+ oplinkUtil.setTargetPower(port, component, power);
}
@Override
public Optional<Range<Long>> getTargetPowerRange(PortNumber port, Object component) {
- Range<Long> range = null;
- switch (getType(component)) {
- case PORT:
- range = getTargetPortPowerRange(port);
- break;
- case CHANNEL:
- range = getChannelAttenuationRange(port);
- break;
- default:
- break;
- }
- return Optional.ofNullable(range);
+ return Optional.ofNullable(oplinkUtil.getTargetPowerRange(port, component));
}
@Override
public Optional<Range<Long>> getInputPowerRange(PortNumber port, Object component) {
- Range<Long> range = null;
- switch (getType(component)) {
- case PORT:
- range = getInputPortPowerRange(port);
- break;
- default:
- break;
- }
- return Optional.ofNullable(range);
- }
-
- private Long getChannelAttenuation(PortNumber portNum, OchSignal och) {
- FlowEntry flowEntry = findFlow(portNum, och);
- if (flowEntry != null) {
- List<Instruction> instructions = flowEntry.treatment().allInstructions();
- for (Instruction ins : instructions) {
- if (ins.type() == Instruction.Type.EXTENSION) {
- ExtensionTreatment ext = ((Instructions.ExtensionInstructionWrapper) ins).extensionInstruction();
- if (ext.type() == ExtensionTreatmentType.ExtensionTreatmentTypes.OPLINK_ATTENUATION.type()) {
- return (long) ((OplinkAttenuation) ext).getAttenuation();
- }
- }
- }
- }
- return null;
- }
-
- private Long getCurrentPortPower(PortNumber portNum) {
- DeviceService deviceService = this.handler().get(DeviceService.class);
- Port port = deviceService.getPort(this.data().deviceId(), portNum);
- if (port != null) {
- String currentPower = port.annotations().value(OpticalAnnotations.CURRENT_POWER);
- if (currentPower != null) {
- return Long.valueOf(currentPower);
- }
- }
- return null;
- }
-
- private Long getCurrentChannelPower(PortNumber portNum, OchSignal och) {
- FlowEntry flowEntry = findFlow(portNum, och);
- if (flowEntry != null) {
- // TODO put somewhere else if possible
- // We put channel power in packets
- return flowEntry.packets();
- }
- return null;
- }
-
- private void setTargetPortPower(PortNumber portNum, long power) {
- OpenFlowSwitch device = getOpenFlowDevice();
- device.sendMsg(device.factory().buildOplinkPortPowerSet()
- .setXid(0)
- .setPort((int) portNum.toLong())
- .setPowerValue((int) power)
- .build());
- }
-
- private void setChannelAttenuation(PortNumber portNum, OchSignal och, long power) {
- FlowEntry flowEntry = findFlow(portNum, och);
- if (flowEntry != null) {
- List<Instruction> instructions = flowEntry.treatment().allInstructions();
- for (Instruction ins : instructions) {
- if (ins.type() == Instruction.Type.EXTENSION) {
- ExtensionTreatment ext = ((Instructions.ExtensionInstructionWrapper) ins).extensionInstruction();
- if (ext.type() == ExtensionTreatmentType.ExtensionTreatmentTypes.OPLINK_ATTENUATION.type()) {
- ((OplinkAttenuation) ext).setAttenuation((int) power);
- FlowRuleService service = this.handler().get(FlowRuleService.class);
- service.applyFlowRules(flowEntry);
- return;
- }
- }
- }
- addAttenuation(flowEntry, power);
- } else {
- log.warn("Target channel power not set");
- }
- }
-
- // Replace flow with new flow containing Oplink attenuation extension instruction. Also resets
- // metrics.
- private void addAttenuation(FlowEntry flowEntry, long power) {
- FlowRule.Builder flowBuilder = new DefaultFlowRule.Builder();
- flowBuilder.withCookie(flowEntry.id().value());
- flowBuilder.withPriority(flowEntry.priority());
- flowBuilder.forDevice(flowEntry.deviceId());
- flowBuilder.forTable(flowEntry.tableId());
- if (flowEntry.isPermanent()) {
- flowBuilder.makePermanent();
- } else {
- flowBuilder.makeTemporary(flowEntry.timeout());
- }
-
- flowBuilder.withSelector(flowEntry.selector());
-
- // Copy original instructions and add attenuation instruction
- TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
- flowEntry.treatment().allInstructions().forEach(ins -> treatmentBuilder.add(ins));
- treatmentBuilder.add(Instructions.extension(new OplinkAttenuation((int) power), this.data().deviceId()));
- flowBuilder.withTreatment(treatmentBuilder.build());
-
- FlowRuleService service = this.handler().get(FlowRuleService.class);
- service.applyFlowRules(flowBuilder.build());
- }
-
- // Returns the acceptable target range for an output Port, null otherwise
- private Range<Long> getTargetPortPowerRange(PortNumber port) {
- Range<Long> range = null;
- long num = port.toLong();
- if (num == LINE_OUT) {
- range = Range.closed(100L, 2040L);
- } else if (num >= AUX_OUT_1 && num <= EXPRESS_OUT_7) {
- range = Range.closed(-680L, 1530L);
- }
- return range;
- }
-
- // Returns the acceptable attenuation range for a connection (represented as
- // a flow with attenuation instruction). Port can be either the input or
- // output port of the connection. Returns null if the connection does not
- // support attenuation.
- private Range<Long> getChannelAttenuationRange(PortNumber port) {
- Range<Long> range = null;
- long num = port.toLong();
- // Only connections from AuxIn to LineOut or ExpressIn to LineOut support
- // attenuation.
- if (num == LINE_OUT ||
- num >= AUX_IN_1 && num <= EXPRESS_IN_7) {
- range = Range.closed(0L, 2550L);
- }
- return range;
- }
-
- // Returns the working input power range for an input port, null if the port
- // is not an input port.
- private Range<Long> getInputPortPowerRange(PortNumber port) {
- Range<Long> range = null;
- long portNum = port.toLong();
- if (portNum == LINE_IN) {
- // TODO implement support for IR and ER range
- // only supports LR right now
- range = Range.closed(-2600L, 540L);
- } else if (portNum == AUX_IN_1 || portNum == AUX_IN_2) {
- range = Range.closed(-1250L, 1590L);
- } else if (portNum >= EXPRESS_IN_1 && portNum <= EXPRESS_IN_7) {
- range = Range.closed(-1420L, 1420L);
- }
- return range;
+ return Optional.ofNullable(oplinkUtil.getInputPowerRange(port, component));
}
}
diff --git a/drivers/optical/src/main/java/org/onosproject/driver/optical/query/OplinkRoadmLambdaQuery.java b/drivers/optical/src/main/java/org/onosproject/driver/optical/query/OplinkRoadmLambdaQuery.java
index d797979..1532a80 100644
--- a/drivers/optical/src/main/java/org/onosproject/driver/optical/query/OplinkRoadmLambdaQuery.java
+++ b/drivers/optical/src/main/java/org/onosproject/driver/optical/query/OplinkRoadmLambdaQuery.java
@@ -36,13 +36,13 @@
public class OplinkRoadmLambdaQuery extends AbstractHandlerBehaviour implements LambdaQuery {
- private static final int LAMBDA_COUNT = 88;
- private static final int CENTER_OFFSET = 29;
+ private static final int MIN_CHANNEL = -28;
+ private static final int MAX_CHANNEL = 59;
@Override
public Set<OchSignal> queryLambdas(PortNumber port) {
- return IntStream.rangeClosed(1, LAMBDA_COUNT)
- .mapToObj(x -> OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, x - CENTER_OFFSET))
+ return IntStream.rangeClosed(MIN_CHANNEL, MAX_CHANNEL)
+ .mapToObj(x -> OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, x))
.collect(Collectors.toSet());
}
}
\ No newline at end of file
diff --git a/drivers/optical/src/main/resources/optical-drivers.xml b/drivers/optical/src/main/resources/optical-drivers.xml
index 65ed00f..ca4016f 100644
--- a/drivers/optical/src/main/resources/optical-drivers.xml
+++ b/drivers/optical/src/main/resources/optical-drivers.xml
@@ -51,7 +51,7 @@
manufacturer="Oplink a Molex company" hwVersion="ROADM"
swVersion="of-agent">
<behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
- impl="org.onosproject.driver.optical.handshaker.OplinkRoadm"/>
+ impl="org.onosproject.driver.optical.handshaker.OplinkRoadmHandshaker"/>
<behaviour api="org.onosproject.net.behaviour.LambdaQuery"
impl="org.onosproject.driver.optical.query.OplinkRoadmLambdaQuery"/>
<behaviour api="org.onosproject.net.optical.OpticalDevice"