[Emu] Open Flow Optical Port Description

Change-Id: I8da4d7a1e1dea18d56cba9673f70b1ec69a5adcf
diff --git a/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
index 494273c..e2d3e6d 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Open Networking Laboratory
+ * Copyright 2015 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.
@@ -22,8 +22,12 @@
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
+import org.onlab.util.Frequency;
 import org.onosproject.cli.Comparators;
 import org.onosproject.net.Device;
+import org.onosproject.net.OchPort;
+import org.onosproject.net.OduCltPort;
+import org.onosproject.net.OmsPort;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
@@ -41,7 +45,10 @@
          description = "Lists all ports or all ports of a device")
 public class DevicePortsListCommand extends DevicesListCommand {
 
-    private static final String FMT = "  port=%s, state=%s, type=%s, speed=%s%s";
+    private static final String FMT = "  port=%s, state=%s, type=%s, speed=%s %s";
+    private static final String FMT_OCH = "  port=%s, state=%s, type=%s, signalType=%s, isTunable=%s %s";
+    private static final String FMT_ODUCLT = "  port=%s, state=%s, type=%s, signalType=%s %s";
+    private static final String FMT_OMS = "  port=%s, state=%s, type=%s, Freqs= %s / %s / %s GHz, totalChannels=%s %s";
 
     @Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports",
             required = false, multiValued = false)
@@ -137,13 +144,34 @@
         List<Port> ports = new ArrayList<>(service.getPorts(device.id()));
         Collections.sort(ports, Comparators.PORT_COMPARATOR);
         for (Port port : ports) {
-            if (isIncluded(port)) {
-                print(FMT, portName(port.number()),
-                      port.isEnabled() ? "enabled" : "disabled",
-                      port.type().toString().toLowerCase(), port.portSpeed(),
-                      annotations(port.annotations()));
+            if (!isIncluded(port)) {
+                continue;
+            }
+            String portName = portName(port.number());
+            Object portIsEnabled = port.isEnabled() ? "enabled" : "disabled";
+            String portType = port.type().toString().toLowerCase();
+            String annotations = annotations(port.annotations());
+            switch (port.type()) {
+                case OCH:
+                     print(FMT_OCH, portName, portIsEnabled, portType,
+                             ((OchPort) port).signalType().toString(),
+                             ((OchPort) port).isTunable() ? "yes" : "no", annotations);
+                     break;
+                case ODUCLT:
+                     print(FMT_ODUCLT, portName, portIsEnabled, portType,
+                            ((OduCltPort) port).signalType().toString(), annotations);
+                     break;
+                case OMS:
+                     print(FMT_OMS, portName, portIsEnabled, portType,
+                                ((OmsPort) port).minFrequency().asHz() / Frequency.ofGHz(1).asHz(),
+                                ((OmsPort) port).maxFrequency().asHz() / Frequency.ofGHz(1).asHz(),
+                                ((OmsPort) port).grid().asHz() / Frequency.ofGHz(1).asHz(),
+                                ((OmsPort) port).totalChannels(), annotations);
+                    break;
+                default:
+                     print(FMT, portName, portIsEnabled, portType, port.portSpeed(), annotations);
+                    break;
             }
         }
     }
-
 }
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index b0b3abe..e35dc0c 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -15,8 +15,26 @@
  */
 package org.onosproject.net.device.impl;
 
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.MastershipRole.MASTER;
+import static org.onosproject.net.MastershipRole.NONE;
+import static org.onosproject.net.MastershipRole.STANDBY;
+import static org.onosproject.security.AppGuard.checkPermission;
+import static org.onosproject.security.AppPermission.Type.DEVICE_READ;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -26,12 +44,6 @@
 import org.apache.felix.scr.annotations.Service;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.NodeId;
-import org.onosproject.net.provider.AbstractListenerProviderRegistry;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.config.basics.BasicDeviceConfig;
-import org.onosproject.net.config.basics.OpticalPortConfig;
 import org.onosproject.mastership.MastershipEvent;
 import org.onosproject.mastership.MastershipListener;
 import org.onosproject.mastership.MastershipService;
@@ -44,6 +56,11 @@
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
+import org.onosproject.net.config.basics.OpticalPortConfig;
 import org.onosproject.net.device.DefaultDeviceDescription;
 import org.onosproject.net.device.DefaultPortDescription;
 import org.onosproject.net.device.DeviceAdminService;
@@ -58,27 +75,11 @@
 import org.onosproject.net.device.DeviceStoreDelegate;
 import org.onosproject.net.device.PortDescription;
 import org.onosproject.net.device.PortStatistics;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.MastershipRole.*;
-import static org.onosproject.security.AppGuard.checkPermission;
-import static org.slf4j.LoggerFactory.getLogger;
-import static org.onosproject.security.AppPermission.Type.*;
+import com.google.common.util.concurrent.Futures;
 
 /**
  * Provides implementation of the device SB &amp; NB APIs.
@@ -347,11 +348,15 @@
             log.info("Device {} disconnected from this node", deviceId);
 
             List<Port> ports = store.getPorts(deviceId);
-            List<PortDescription> descs = Lists.newArrayList();
-            ports.forEach(port ->
-                                  descs.add(new DefaultPortDescription(port.number(),
-                                                                       false, port.type(),
-                                                                       port.portSpeed())));
+            final Device device = getDevice(deviceId);
+
+            List<PortDescription> descs = ports.stream().map(
+              port -> (!(Device.Type.ROADM.equals(device.type()))) ?
+                  new DefaultPortDescription(port.number(), false,
+                          port.type(), port.portSpeed()) :
+                      OpticalPortOperator.descriptionOf(port, false)
+                 ).collect(Collectors.toList());
+
             store.updatePorts(this.provider().id(), deviceId, descs);
             try {
                 if (mastershipService.isLocalMaster(deviceId)) {
@@ -430,6 +435,12 @@
                           portDescription);
                 return;
             }
+            final Device device = getDevice(deviceId);
+            if ((Device.Type.ROADM.equals(device.type()))) {
+                Port port = getPort(deviceId, portDescription.portNumber());
+                portDescription = OpticalPortOperator.descriptionOf(port, portDescription.isEnabled());
+            }
+
             portDescription = consolidate(deviceId, portDescription);
             final DeviceEvent event = store.updatePortStatus(this.provider().id(),
                                                              deviceId, portDescription);
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java b/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
index b2fd02c..8f2bda0 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
@@ -151,8 +151,25 @@
      */
     public static PortDescription descriptionOf(Port port) {
         checkNotNull(port, "Must supply non-null Port");
+        final boolean isUp = port.isEnabled();
+        return descriptionOfPort(port, isUp);
+    }
+
+    /**
+     * Returns a description built from an existing port and reported status.
+     *
+     * @param port
+     * @param isEnabled
+     * @return a PortDescription based on the port
+     */
+    static PortDescription descriptionOf(Port port, boolean isEnabled) {
+        checkNotNull(port, "Must supply non-null Port");
+        final boolean isup = isEnabled;
+        return descriptionOfPort(port, isup);
+    }
+
+    private static PortDescription descriptionOfPort(Port port, final boolean isup) {
         final PortNumber ptn = port.number();
-        final boolean isup = port.isEnabled();
         final SparseAnnotations an = (SparseAnnotations) port.annotations();
         switch (port.type()) {
             case OMS:
diff --git a/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitch13.java b/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitch13.java
new file mode 100644
index 0000000..a62b93c
--- /dev/null
+++ b/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitch13.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2015 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.handshaker;
+
+import org.projectfloodlight.openflow.protocol.OFExpPort;
+import org.projectfloodlight.openflow.protocol.OFExpPortDescReply;
+import org.projectfloodlight.openflow.protocol.OFExpPortDescRequest;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+import org.onosproject.net.Device;
+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.OFObject;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+
+/**
+ * Open Flow Optical Switch handshaker - for Open Flow 13.
+ */
+public class OFOpticalSwitch13 extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
+
+    private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
+    private List<OFExpPort> expPortDes = new ArrayList<>();
+
+    @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;
+
+        log.debug("sendHandshakeOFExperimenterPortDescRequest for sw {}", getStringId());
+
+        try {
+            sendHandshakeOFExperimenterPortDescRequest();
+        } catch (IOException e) {
+            log.error("Failed to send handshaker message OFExperimenterPortDescRequestfor sw {}, {}",
+                     getStringId(), e.getMessage());
+            e.printStackTrace();
+        }
+    }
+
+     @Override
+    public void processDriverHandshakeMessage(OFMessage m) {
+        if (!startDriverHandshakeCalled) {
+            throw new SwitchDriverSubHandshakeNotStarted();
+        }
+        if (driverHandshakeComplete.get()) {
+            throw new SwitchDriverSubHandshakeCompleted(m);
+        }
+
+        log.debug("processDriverHandshakeMessage for sw {}", getStringId());
+
+        switch (m.getType()) {
+        case STATS_REPLY: // multipart message is reported as STAT
+            processOFMultipartReply((OFStatsReply) m);
+            break;
+        default:
+            log.warn("Received message {} during switch-driver " +
+                    "subhandshake " + "from switch {} ... " +
+                    "Ignoring message", m,
+                    getStringId());
+        }
+    }
+
+    private void processOFMultipartReply(OFStatsReply stats) {
+        log.debug("Received message {} during switch-driver " +
+                   "subhandshake " + "from switch {} ... " +
+                   stats,
+                   getStringId());
+
+         if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
+             try {
+               OFExpPortDescReply expPortDescReply =  (OFExpPortDescReply) stats;
+               expPortDes.addAll(expPortDescReply.getEntries());
+               if (!expPortDescReply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
+                   driverHandshakeComplete.set(true);
+                   return;
+               }
+              } catch (ClassCastException e) {
+                  log.error("Unexspected Experimenter Multipart message type {} "
+                          , stats.getClass().getName());
+            }
+        }
+    }
+
+
+    @Override
+    public boolean isDriverHandshakeComplete() {
+        return driverHandshakeComplete.get();
+    }
+
+    private void sendHandshakeOFExperimenterPortDescRequest() throws
+            IOException {
+
+        OFExpPortDescRequest preq = factory()
+                .buildExpPortDescRequest()
+                .setXid(getNextTransactionId())
+                .build();
+
+        log.debug("Sending experimented port description " +
+                "message " +
+                "{}",
+                preq.toString());
+
+        this.sendHandshakeMessage(preq);
+    }
+
+    @Override
+    public Device.Type deviceType() {
+        return Device.Type.ROADM;
+    }
+
+    /*
+     * OduClt ports are reported as regular ETH ports.
+     */
+    @Override
+    public List<OFPortDesc> getPorts() {
+        return ImmutableList.copyOf(
+                ports.stream().flatMap(p -> p.getEntries().stream())
+                .collect(Collectors.toList()));
+    }
+
+    @Override
+    public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
+        return ImmutableList.copyOf(expPortDes);
+    }
+
+   @Override
+    public Set<PortDescPropertyType> getPortTypes() {
+        return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
+    }
+
+}
diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml
index ac307c2..aea743f 100644
--- a/drivers/src/main/resources/onos-drivers.xml
+++ b/drivers/src/main/resources/onos-drivers.xml
@@ -120,5 +120,10 @@
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
                    impl="org.onosproject.driver.pipeline.OpenVSwitchPipeline"/>
     </driver>
+    <driver name="eci" extends="default"
+            manufacturer="ECI Telecom" hwVersion="optical" swVersion="V_1_0">
+        <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
+                   impl="org.onosproject.driver.handshaker.OFOpticalSwitch13"/>
+    </driver>
 </drivers>
 
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 cb19dc5..0aea805 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
@@ -15,10 +15,24 @@
  */
 package org.onosproject.provider.of.device.impl;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.Port.Type.COPPER;
+import static org.onosproject.net.Port.Type.FIBER;
+import static org.onosproject.openflow.controller.Dpid.dpid;
+import static org.onosproject.openflow.controller.Dpid.uri;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -28,15 +42,17 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.ChassisId;
 import org.onlab.util.Frequency;
-import org.onosproject.cfg.ComponentConfigService;
 import org.onlab.util.Spectrum;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.GridType;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OduSignalType;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
@@ -49,6 +65,7 @@
 import org.onosproject.net.device.DeviceProviderRegistry;
 import org.onosproject.net.device.DeviceProviderService;
 import org.onosproject.net.device.OchPortDescription;
+import org.onosproject.net.device.OduCltPortDescription;
 import org.onosproject.net.device.OmsPortDescription;
 import org.onosproject.net.device.PortDescription;
 import org.onosproject.net.device.PortStatistics;
@@ -64,13 +81,19 @@
 import org.onosproject.openflow.controller.RoleState;
 import org.osgi.service.component.ComponentContext;
 import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFExpPort;
+import org.projectfloodlight.openflow.protocol.OFExpPortDescPropOpticalTransport;
+import org.projectfloodlight.openflow.protocol.OFExpPortOpticalTransportLayerEntry;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFObject;
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortDescPropOpticalTransport;
 import org.projectfloodlight.openflow.protocol.OFPortFeatures;
 import org.projectfloodlight.openflow.protocol.OFPortOptical;
+import org.projectfloodlight.openflow.protocol.OFPortOpticalTransportLayerClass;
+import org.projectfloodlight.openflow.protocol.OFPortOpticalTransportSignalType;
 import org.projectfloodlight.openflow.protocol.OFPortReason;
 import org.projectfloodlight.openflow.protocol.OFPortState;
 import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
@@ -83,23 +106,10 @@
 import org.projectfloodlight.openflow.types.PortSpeed;
 import org.slf4j.Logger;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static org.onlab.util.Tools.get;
-import static org.onosproject.net.DeviceId.deviceId;
-import static org.onosproject.net.Port.Type.COPPER;
-import static org.onosproject.net.Port.Type.FIBER;
-import static org.onosproject.openflow.controller.Dpid.dpid;
-import static org.onosproject.openflow.controller.Dpid.uri;
-import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 /**
  * Provider which uses an OpenFlow controller to detect network
@@ -110,6 +120,9 @@
 
     private static final Logger LOG = getLogger(OpenFlowDeviceProvider.class);
     private static final long MBPS = 1_000 * 1_000;
+    private static final Frequency FREQ100 = Frequency.ofGHz(100);
+    private static final Frequency FREQ193_1 = Frequency.ofTHz(193.1);
+    private static final Frequency FREQ4_4 = Frequency.ofTHz(4.4);
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceProviderRegistry providerRegistry;
@@ -386,18 +399,27 @@
          */
         private List<PortDescription> buildPortDescriptions(OpenFlowSwitch sw) {
             final List<PortDescription> portDescs = new ArrayList<>(sw.getPorts().size());
-            sw.getPorts().forEach(port -> portDescs.add(buildPortDescription(port)));
+            if (!(Device.Type.ROADM.equals(sw.deviceType()))) {
+                  sw.getPorts().forEach(port -> portDescs.add(buildPortDescription(port)));
+            }
 
             OpenFlowOpticalSwitch opsw;
             switch (sw.deviceType()) {
                 case ROADM:
                     opsw = (OpenFlowOpticalSwitch) sw;
+                    List<OFPortDesc> ports = opsw.getPorts();
+                    LOG.debug("SW ID {} , ETH- ODU CLT Ports {}", opsw.getId(), ports);
+                    // ODU client ports are reported as ETH
+                    ports.forEach(port -> portDescs.add(buildOduCltPortDescription(port)));
+
                     opsw.getPortTypes().forEach(type -> {
-                        opsw.getPortsOf(type).forEach(
-                                op -> {
-                                    portDescs.add(buildPortDescription(type, (OFPortOptical) op));
-                                }
-                        );
+                    List<? extends OFObject> portsOf = opsw.getPortsOf(type);
+                    LOG.debug("Ports Of{}", portsOf);
+                    portsOf.forEach(
+                        op -> {
+                            portDescs.add(buildPortDescription(type, (OFObject) op));
+                        }
+                     );
                     });
                     break;
                 case FIBER_SWITCH:
@@ -417,6 +439,105 @@
             return portDescs;
         }
 
+        private PortDescription buildOduCltPortDescription(OFPortDesc port) {
+            PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+            boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN) &&
+                              !port.getConfig().contains(OFPortConfig.PORT_DOWN);
+            Long portSpeed = portSpeed(port);
+            OduCltPort.SignalType sigType = null;
+
+            switch (portSpeed.toString()) {
+                case "1":
+                    sigType = OduCltPort.SignalType.CLT_1GBE;
+                    break;
+                case "10":
+                    sigType = OduCltPort.SignalType.CLT_10GBE;
+                    break;
+                case "40":
+                    sigType = OduCltPort.SignalType.CLT_40GBE;
+                    break;
+                case "100":
+                    sigType = OduCltPort.SignalType.CLT_100GBE;
+                    break;
+                default:
+                    throw new RuntimeException("Un recognize OduClt speed: " + portSpeed.toString());
+            }
+
+            SparseAnnotations annotations = buildOduCltAnnotation(port);
+            return new OduCltPortDescription(portNo, enabled, sigType, annotations);
+        }
+
+        private SparseAnnotations buildOduCltAnnotation(OFPortDesc port) {
+            SparseAnnotations annotations = null;
+            String portName = Strings.emptyToNull(port.getName());
+            if (portName != null) {
+                 annotations = DefaultAnnotations.builder()
+                        .set(AnnotationKeys.PORT_NAME, portName)
+                        .set(AnnotationKeys.STATIC_PORT, Boolean.TRUE.toString()).build();
+            }
+            return annotations;
+        }
+
+        private PortDescription buildPortDescription(PortDescPropertyType ptype, OFObject port) {
+            if (port instanceof  OFPortOptical) {
+               return buildPortDescription(ptype, (OFPortOptical) port);
+            }
+            return buildPortDescription(ptype, (OFExpPort) port);
+        }
+
+        /**
+         * Build a portDescription from a given a port description describing some
+         * Optical port.
+         *
+         * @param ptype description property type.
+         * @param port the port to build from.
+         * @return portDescription for the port.
+         */
+        private PortDescription buildPortDescription(PortDescPropertyType ptype, OFExpPort port) {
+            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());
+
+            OFExpPortDescPropOpticalTransport firstProp = port.getProperties().get(0);
+            OFPortOpticalTransportSignalType sigType = firstProp.getPortSignalType();
+
+            DefaultPortDescription portDes = null;
+            switch (sigType) {
+            case OMSN:
+                portDes =  new OmsPortDescription(portNo, enabled, FREQ193_1, FREQ193_1.add(FREQ4_4),
+                       FREQ100, annotations);
+                break;
+            case OCH:
+                OFExpPortOpticalTransportLayerEntry entry = firstProp.getFeatures().get(0).getValue().get(0);
+                OFPortOpticalTransportLayerClass layerClass =  entry.getLayerClass();
+                if (!OFPortOpticalTransportLayerClass.ODU.equals(layerClass)) {
+                    LOG.error("Unsupported layer Class {} ", layerClass);
+                    return null;
+                }
+
+                // convert to ONOS OduSignalType
+                OduSignalType oduSignalType = OpenFlowDeviceValueMapper.
+                        lookupOduSignalType((byte) entry.getSignalType());
+                //OchSignal is needed for OchPortDescription constructor,
+                //yet not relevant for tunable OCH port, creating with default parameters
+                OchSignal signalId = new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 1, 1);
+
+                portDes = new OchPortDescription(portNo, enabled,
+                        oduSignalType, true, signalId, annotations);
+
+                break;
+            case OTU2:
+            case OTU4:
+                  LOG.error("Signal tpye OTU2/4 not supported yet ", port.toString());
+                  break;
+            default:
+                break;
+            }
+
+            return portDes;
+        }
+
         /**
          * Creates an annotation for the port name if one is available.
          *
@@ -565,5 +686,4 @@
             }
         }
     }
-
 }
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceValueMapper.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceValueMapper.java
new file mode 100644
index 0000000..7bdf06f
--- /dev/null
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceValueMapper.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 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.provider.of.device.impl;
+
+import org.onosproject.net.OduSignalType;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.EnumHashBiMap;
+
+/**
+ * Collection of helper methods to convert protocol agnostic models to values used in OpenFlow spec.
+ */
+final class OpenFlowDeviceValueMapper {
+
+    // prohibit instantiation
+    private OpenFlowDeviceValueMapper() {}
+
+    private static final BiMap<OduSignalType, Byte> ODU_SIGNAL_TYPES = EnumHashBiMap.create(OduSignalType.class);
+    static {
+        // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values
+        ODU_SIGNAL_TYPES.put(OduSignalType.ODU1, (byte) 1);         // OFPODUT_ODU1 of enum ofp_odu_signal_type
+        ODU_SIGNAL_TYPES.put(OduSignalType.ODU2, (byte) 2);         // OFPODUT_ODU2 of enum ofp_odu_signal_type
+        ODU_SIGNAL_TYPES.put(OduSignalType.ODU3, (byte) 3);         // OFPODUT_ODU3 of enum ofp_odu_signal_type
+        ODU_SIGNAL_TYPES.put(OduSignalType.ODU4, (byte) 4);         // OFPODUT_ODU4 of enum ofp_odu_signal_type
+        ODU_SIGNAL_TYPES.put(OduSignalType.ODU0, (byte) 10);        // OFPODUT_ODU0 of enum ofp_odu_signal_type
+        ODU_SIGNAL_TYPES.put(OduSignalType.ODU2e, (byte) 11);       // OFPODUT_ODU2E of enum ofp_odu_signal_type
+    }
+
+    /**
+     * Looks up the specified input value to the corresponding value with the specified map.
+     *
+     * @param map bidirectional mapping
+     * @param input input value
+     * @param cls class of output value
+     * @param <I> type of input value
+     * @param <O> type of output value
+     * @return the corresponding value stored in the specified map
+     */
+    private static <I, O> O lookup(BiMap<I, O> map, I input, Class<O> cls) {
+        if (!map.containsKey(input)) {
+            throw new RuntimeException(
+                    String.format("No mapping found for %s when converting to %s", input, cls.getName()));
+        }
+
+        return map.get(input);
+    }
+
+    /**
+     * Looks up the the corresponding {@link OduSignalType} instance
+     * from the specified byte value for ODU signal type defined in
+     * ONF "Optical Transport Protocol Extensions Version 1.0".
+     *
+     * @param signalType byte value as ODU (Optical channel Data Unit) signal type defined the spec
+     * @return the corresponding OchSignalType instance
+     */
+    static OduSignalType lookupOduSignalType(byte signalType) {
+        return lookup(ODU_SIGNAL_TYPES.inverse(), signalType, OduSignalType.class);
+    }
+
+}