Interfaces for passing port information from OF switch drivers to DeviceProviders.

Change-Id: I14039f5999c930a211c30138caf81c0513d398e2
Reference: ONOS-1911
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 2c0749c..e1461e3 100644
--- a/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitchImplLINC13.java
+++ b/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitchImplLINC13.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.driver.handshaker;
 
+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;
@@ -23,28 +25,29 @@
 import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
 import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
 import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFObject;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFPortOptical;
 import org.projectfloodlight.openflow.protocol.OFStatsReply;
 import org.projectfloodlight.openflow.protocol.OFStatsType;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * LINC-OE Optical Emulator switch class.
  */
-public class OFOpticalSwitchImplLINC13 extends AbstractOpenFlowSwitch {
+public class OFOpticalSwitchImplLINC13
+ extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
 
     private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
     private long barrierXidToWaitFor = -1;
 
-    private OFPortDescStatsReply wPorts;
+    private OFCircuitPortsReply wPorts;
 
     @Override
     public void startDriverHandshake() {
@@ -105,8 +108,7 @@
                 OFStatsReply stats = (OFStatsReply) m;
                 if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
                     log.warn("LINC-OE : Received stats reply message {}", m);
-                    processHandshakeOFExperimenterPortDescRequest(
-                            (OFCircuitPortsReply) m);
+                    wPorts = (OFCircuitPortsReply) m;
                     driverHandshakeComplete.set(true);
                 }
                 break;
@@ -124,30 +126,6 @@
 
     }
 
-    private void processHandshakeOFExperimenterPortDescRequest(
-            OFCircuitPortsReply sr) {
-        Collection<OFPortOptical> entries = sr.getEntries();
-        List<OFPortDesc> ofPortDescList = new ArrayList<>(entries.size());
-        for (OFPortOptical entry : entries) {
-            log.warn("LINC:OE port message {}", entry.toString());
-            ofPortDescList.add(factory().buildPortDesc().
-                    setPortNo(entry.getPortNo())
-                                           .setConfig(entry.getConfig())
-                                           .setState(entry.getState())
-                                           .setHwAddr(entry.getHwAddr())
-                                           .setName(entry.getName())
-                                           .build());
-
-        }
-        setExperimenterPortDescReply(factory().buildPortDescStatsReply().
-                setEntries(ofPortDescList).build());
-    }
-
-    private void setExperimenterPortDescReply(OFPortDescStatsReply reply) {
-        wPorts = reply;
-    }
-
-
     private void sendHandshakeOFExperimenterPortDescRequest() throws
             IOException {
         // send multi part message for port description for optical switches
@@ -162,13 +140,13 @@
     }
 
     @Override
+    /**
+     * Returns a list of standard (Ethernet) ports.
+     *
+     * @return List of ports
+     */
     public List<OFPortDesc> getPorts() {
-        List<OFPortDesc> portEntries = new ArrayList<>();
-        portEntries.addAll(super.getPorts());
-        if (wPorts != null) {
-            portEntries.addAll(wPorts.getEntries());
-        }
-        return Collections.unmodifiableList(portEntries);
+        return ImmutableList.copyOf(super.getPorts());
     }
 
 
@@ -182,4 +160,14 @@
         return true;
     }
 
+    @Override
+    public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
+        return ImmutableList.copyOf(wPorts.getEntries());
+    }
+
+    @Override
+    public Set<PortDescPropertyType> getPortTypes() {
+        return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
+    }
+
 }
diff --git a/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowOpticalSwitch.java b/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowOpticalSwitch.java
new file mode 100644
index 0000000..271e183
--- /dev/null
+++ b/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowOpticalSwitch.java
@@ -0,0 +1,8 @@
+package org.onosproject.openflow.controller;
+
+/**
+ * A marker interface for optical switches, which require the ability to pass
+ * port information to a Device provider.
+ */
+public interface OpenFlowOpticalSwitch extends OpenFlowSwitch, WithTypedPorts {
+}
diff --git a/openflow/api/src/main/java/org/onosproject/openflow/controller/PortDescPropertyType.java b/openflow/api/src/main/java/org/onosproject/openflow/controller/PortDescPropertyType.java
new file mode 100644
index 0000000..b5d4743
--- /dev/null
+++ b/openflow/api/src/main/java/org/onosproject/openflow/controller/PortDescPropertyType.java
@@ -0,0 +1,24 @@
+package org.onosproject.openflow.controller;
+
+/**
+ * Port description property types (OFPPDPT enums) in OF 1.3 &lt;.
+ */
+public enum PortDescPropertyType {
+    ETHERNET(0),            /* Ethernet port */
+    OPTICAL(1),             /* Optical port */
+    OPTICAL_TRANSPORT(2),   /* OF1.3 Optical transport extension */
+    PIPELINE_INPUT(2),      /* Ingress pipeline */
+    PIPELINE_OUTPUT(3),     /* Egress pipeline */
+    RECIRCULATE(4),         /* Recirculation */
+    EXPERIMENTER(0xffff);   /* Experimenter-implemented */
+
+    private final int value;
+
+    PortDescPropertyType(int v) {
+        value = v;
+    }
+
+    public int valueOf() {
+        return value;
+    }
+}
diff --git a/openflow/api/src/main/java/org/onosproject/openflow/controller/WithTypedPorts.java b/openflow/api/src/main/java/org/onosproject/openflow/controller/WithTypedPorts.java
new file mode 100644
index 0000000..b78124b
--- /dev/null
+++ b/openflow/api/src/main/java/org/onosproject/openflow/controller/WithTypedPorts.java
@@ -0,0 +1,30 @@
+package org.onosproject.openflow.controller;
+
+import java.util.List;
+import java.util.Set;
+
+import org.projectfloodlight.openflow.protocol.OFObject;
+
+/**
+ * An interface implemented by OpenFlow devices that enables providers to
+ * retrieve ports based on port property.
+ */
+public interface WithTypedPorts {
+
+    /**
+     * Return a list of interfaces (ports) of the type associated with this
+     * OpenFlow switch.
+     *
+     * @param type The port description property type of requested ports
+     * @return A potentially empty list of ports.
+     */
+    List<? extends OFObject> getPortsOf(PortDescPropertyType type);
+
+    /**
+     * Returns the port property types supported by the driver implementing this
+     * interface.
+     *
+     * @return A set of port property types
+     */
+    Set<PortDescPropertyType> getPortTypes();
+}
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index e23c7d6..eb72230 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -17,6 +17,7 @@
 
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -44,8 +45,10 @@
 import org.onosproject.openflow.controller.Dpid;
 import org.onosproject.openflow.controller.OpenFlowController;
 import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
 import org.onosproject.openflow.controller.OpenFlowSwitch;
 import org.onosproject.openflow.controller.OpenFlowSwitchListener;
+import org.onosproject.openflow.controller.PortDescPropertyType;
 import org.onosproject.openflow.controller.RoleState;
 import org.onlab.packet.ChassisId;
 import org.projectfloodlight.openflow.protocol.OFFactory;
@@ -53,6 +56,7 @@
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortFeatures;
+import org.projectfloodlight.openflow.protocol.OFPortOptical;
 import org.projectfloodlight.openflow.protocol.OFPortReason;
 import org.projectfloodlight.openflow.protocol.OFPortState;
 import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
@@ -262,7 +266,7 @@
                                                  sw.serialNumber(),
                                                  cId, annotations);
             providerService.deviceConnected(did, description);
-            providerService.updatePorts(did, buildPortDescriptions(sw.getPorts()));
+            providerService.updatePorts(did, buildPortDescriptions(sw));
 
             PortStatsCollector psc = new PortStatsCollector(
                         controller.getSwitch(dpid), POLL_INTERVAL);
@@ -290,7 +294,7 @@
             }
             DeviceId did = deviceId(uri(dpid));
             OpenFlowSwitch sw = controller.getSwitch(dpid);
-            providerService.updatePorts(did, buildPortDescriptions(sw.getPorts()));
+            providerService.updatePorts(did, buildPortDescriptions(sw));
         }
 
         @Override
@@ -333,10 +337,19 @@
          * @param ports the list of ports
          * @return list of portdescriptions
          */
-        private List<PortDescription> buildPortDescriptions(List<OFPortDesc> ports) {
-            final List<PortDescription> portDescs = new ArrayList<>(ports.size());
-            for (OFPortDesc port : ports) {
-                portDescs.add(buildPortDescription(port));
+        private List<PortDescription> buildPortDescriptions(OpenFlowSwitch sw) {
+            final List<PortDescription> portDescs = new ArrayList<>(sw.getPorts().size());
+            sw.getPorts().forEach(port -> portDescs.add(buildPortDescription(port)));
+            if (sw.isOptical()) {
+                OpenFlowOpticalSwitch opsw = (OpenFlowOpticalSwitch) sw;
+                opsw.getPortTypes().forEach(type -> {
+                    LOG.info("ports: {}", opsw.getPortsOf(type));
+                    opsw.getPortsOf(type).forEach(
+                        op -> {
+                            portDescs.add(buildPortDescription(type, (OFPortOptical) op));
+                        }
+                    );
+                });
             }
             return portDescs;
         }
@@ -348,9 +361,9 @@
          * @return annotation containing the port name if one is found,
          *         null otherwise
          */
-        private SparseAnnotations makePortNameAnnotation(OFPortDesc port) {
+        private SparseAnnotations makePortNameAnnotation(String port) {
             SparseAnnotations annotations = null;
-            String portName = Strings.emptyToNull(port.getName());
+            String portName = Strings.emptyToNull(port);
             if (portName != null) {
                 annotations = DefaultAnnotations.builder()
                         .set(AnnotationKeys.PORT_NAME, portName).build();
@@ -359,7 +372,7 @@
         }
 
         /**
-         * Build a portDescription from a given port.
+         * Build a portDescription from a given Ethernet port description.
          *
          * @param port the port to build from.
          * @return portDescription for the port.
@@ -370,11 +383,38 @@
                     !port.getState().contains(OFPortState.LINK_DOWN) &&
                             !port.getConfig().contains(OFPortConfig.PORT_DOWN);
             Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER;
-            SparseAnnotations annotations = makePortNameAnnotation(port);
+            SparseAnnotations annotations = makePortNameAnnotation(port.getName());
             return new DefaultPortDescription(portNo, enabled, type,
                                               portSpeed(port), annotations);
         }
 
+        /**
+         * Build a portDescription from a given a port description describing some
+         * Optical port.
+         *
+         * @param port description property type.
+         * @param port the port to build from.
+         * @return portDescription for the port.
+         */
+        private PortDescription buildPortDescription(PortDescPropertyType ptype, OFPortOptical port) {
+            // Minimally functional fixture. This needs to be fixed as we add better support.
+            PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+            boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN)
+                    && !port.getConfig().contains(OFPortConfig.PORT_DOWN);
+            SparseAnnotations annotations = makePortNameAnnotation(port.getName());
+            Port.Type type = FIBER;
+
+            if (port.getVersion() == OFVersion.OF_13
+                    && ptype == PortDescPropertyType.OPTICAL_TRANSPORT) {
+                // At this point, not much is carried in the optical port message.
+                LOG.info("Optical transport port message {}", port.toString());
+            } else {
+                // removable once 1.4+ support complete.
+                LOG.warn("Unsupported optical port properties");
+            }
+            return new DefaultPortDescription(portNo, enabled, type, 0, annotations);
+        }
+
         private PortDescription buildPortDescription(OFPortStatus status) {
             OFPortDesc port = status.getDesc();
             if (status.getReason() != OFPortReason.DELETE) {
@@ -382,7 +422,7 @@
             } else {
                 PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
                 Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER;
-                SparseAnnotations annotations = makePortNameAnnotation(port);
+                SparseAnnotations annotations = makePortNameAnnotation(port.getName());
                 return new DefaultPortDescription(portNo, false, type,
                                                   portSpeed(port), annotations);
             }