Implementation of lambda query behaviour for LINC and Calient drivers.

ONOS-3431

Change-Id: I03b7e7c9d2b0ba7e55d09745cfc6ceb57cc6eb5e
diff --git a/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java b/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java
index df4dfa5..270008f 100644
--- a/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java
+++ b/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java
@@ -17,7 +17,14 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import org.onlab.util.Spectrum;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.DefaultOchSignalComparator;
 import org.onosproject.net.Device;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.LambdaQuery;
 import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
 import org.onosproject.openflow.controller.PortDescPropertyType;
 import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
@@ -41,9 +48,24 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
-public class CalientFiberSwitchHandshaker extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
+/**
+ * Driver for Calient S160 Optical Circuit Switch. Untested on Calient S320 but probably works ok.
+ *
+ * Driver implements custom handshaker, and rewrites flow stats as expected by the device. Port stats are currently
+ * not supported.
+ *
+ * The device consists of OMS ports only, and each port exposes lambda resources covering the whole
+ * usable optical spectrum (U to O band, see {@link Spectrum} for spectrum definitions).
+ */
+public class CalientFiberSwitchHandshaker
+        extends AbstractOpenFlowSwitch
+        implements OpenFlowOpticalSwitch, LambdaQuery {
 
     private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
     private List<OFCalientPortDescStatsEntry> fiberPorts = new ArrayList<>();
@@ -178,4 +200,22 @@
 
         super.sendMsg(newMsg);
     }
+
+    @Override
+    public SortedSet<OchSignal> queryLambdas(PortNumber port) {
+        // S160 data sheet
+        // Wavelength range: 1260 - 1630 nm
+        long startSpacingMultiplier = Spectrum.U_BAND_MIN.subtract(Spectrum.CENTER_FREQUENCY).asHz() /
+                ChannelSpacing.CHL_12P5GHZ.frequency().asHz();
+        long stopSpacingMultiplier = Spectrum.O_BAND_MAX.subtract(Spectrum.CENTER_FREQUENCY).asHz() /
+                ChannelSpacing.CHL_12P5GHZ.frequency().asHz();
+        List<OchSignal> lambdas = IntStream.rangeClosed((int) startSpacingMultiplier, (int) stopSpacingMultiplier)
+                .mapToObj(x -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_12P5GHZ, x, 1))
+                .collect(Collectors.toList());
+
+        SortedSet<OchSignal> result = new TreeSet<>(new DefaultOchSignalComparator());
+        result.addAll(lambdas);
+
+        return result;
+    }
 }
diff --git a/drivers/src/main/java/org/onosproject/driver/handshaker/OfOpticalSwitchImplLinc13.java b/drivers/src/main/java/org/onosproject/driver/handshaker/OfOpticalSwitchImplLinc13.java
index f91e2a7..23378e9 100644
--- a/drivers/src/main/java/org/onosproject/driver/handshaker/OfOpticalSwitchImplLinc13.java
+++ b/drivers/src/main/java/org/onosproject/driver/handshaker/OfOpticalSwitchImplLinc13.java
@@ -16,7 +16,13 @@
 package org.onosproject.driver.handshaker;
 
 import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.DefaultOchSignalComparator;
 import org.onosproject.net.Device;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.LambdaQuery;
 import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
 import org.onosproject.openflow.controller.PortDescPropertyType;
 import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
@@ -42,7 +48,6 @@
 import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxmExpOchSigId;
 import org.projectfloodlight.openflow.types.CircuitSignalID;
-import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.U8;
 
 import java.io.IOException;
@@ -51,7 +56,11 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /**
  * LINC-OE Optical Emulator switch class.
@@ -65,10 +74,13 @@
  * As LINC implements custom OF optical extensions (in contrast to the final standard as specified in
  * ONF TS-022 (March 15, 2015), we need to rewrite flow stat requests and flow mods in {@link #sendMsg(OFMessage)}.
  *
+ * LINC exposes OchSignal resources: 80 lambdas of 50 GHz around ITU-T G.694.1 center frequency 193.1 GHz.
+ *
  */
 public class OfOpticalSwitchImplLinc13
- extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
+ extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch, LambdaQuery {
 
+    private static final int LAMBDA_COUNT = 80;
     private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
     private long barrierXidToWaitFor = -1;
 
@@ -267,13 +279,13 @@
     /**
      * Checks if given port is also part of the regular port desc stats, i.e., is the port a tap port.
      *
-     * @param port given OF port
+     * @param port given port number
      * @return true if the port is a tap (OCh), false otherwise (OMS port)
      */
-    private boolean hasPort(OFPort port) {
+    private boolean isOChPort(long port) {
         for (OFPortDescStatsReply reply : this.ports) {
             for (OFPortDesc p : reply.getEntries()) {
-                if (p.getPortNo().equals(port)) {
+                if (p.getPortNo().getPortNumber() == port) {
                     return true;
                 }
             }
@@ -328,7 +340,7 @@
             short signalType;
 
             // FIXME: use constants once loxi has full optical extensions
-            if (hasPort(p.getPortNo())) {
+            if (isOChPort(p.getPortNo().getPortNumber())) {
                 signalType = 5;      // OCH port
             } else {
                 signalType = 2;      // OMS port
@@ -351,4 +363,23 @@
     public Set<PortDescPropertyType> getPortTypes() {
         return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
     }
+
+    @Override
+    public SortedSet<OchSignal> queryLambdas(PortNumber port) {
+        // OCh ports don't have lambdas
+        if (isOChPort(port.toLong())) {
+            return Collections.emptySortedSet();
+        }
+
+        // OMS ports expose 80 lambdas of 50GHz width, centered around the ITU-T center frequency.
+        // We report these with a spacing of 12.5 GHz.
+        List<OchSignal> lambdas = IntStream.range(0, LAMBDA_COUNT)
+                .mapToObj(x -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_12P5GHZ, x - (LAMBDA_COUNT / 2), 1))
+                .collect(Collectors.toList());
+
+        SortedSet<OchSignal> result = new TreeSet<>(new DefaultOchSignalComparator());
+        result.addAll(lambdas);
+
+        return result;
+    }
 }
diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml
index 6989683..2494e12 100644
--- a/drivers/src/main/resources/onos-drivers.xml
+++ b/drivers/src/main/resources/onos-drivers.xml
@@ -74,6 +74,8 @@
             swVersion="LINC-OE OpenFlow Software Switch 1.1">
         <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
                    impl="org.onosproject.driver.handshaker.OfOpticalSwitchImplLinc13"/>
+        <behaviour api="org.onosproject.net.behaviour.LambdaQuery"
+                   impl="org.onosproject.driver.handshaker.OfOpticalSwitchImplLinc13"/>
     </driver>
     <driver name="corsa"
             manufacturer="Corsa" hwVersion="Corsa Element" swVersion="2.3.1">
@@ -135,6 +137,8 @@
             swVersion="ocs switch">
         <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
                    impl="org.onosproject.driver.handshaker.CalientFiberSwitchHandshaker"/>
+        <behaviour api="org.onosproject.net.behaviour.LambdaQuery"
+                   impl="org.onosproject.driver.handshaker.CalientFiberSwitchHandshaker"/>
     </driver>
     <driver name="onosfw" extends="ovs"
             manufacturer="" hwVersion="" swVersion="">