Driver and flow stats handling for Calient fiber switch S160.
Bump loxigen to 0.4.1.onos-SNAPSHOT.

Change-Id: Ieb8aa4fe716e12f89b83770eff617561f30cdd08
diff --git a/core/api/src/main/java/org/onosproject/net/Device.java b/core/api/src/main/java/org/onosproject/net/Device.java
index 8066a7a..80e6e48 100644
--- a/core/api/src/main/java/org/onosproject/net/Device.java
+++ b/core/api/src/main/java/org/onosproject/net/Device.java
@@ -26,7 +26,7 @@
      * Coarse classification of the type of the infrastructure device.
      */
     public enum Type {
-        SWITCH, ROUTER, ROADM, OTN, ROADM_OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, VIRTUAL, OTHER
+        SWITCH, ROUTER, ROADM, OTN, ROADM_OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, VIRTUAL, FIBER_SWITCH, OTHER
     }
 
     /**
diff --git a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
index d7ed927..2cd392f 100644
--- a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
+++ b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
@@ -194,8 +194,7 @@
      * @param request the packet request
      */
     private void pushRule(Device device, PacketRequest request) {
-        // Everything is pre-provisioned on ROADMs
-        if (device.type().equals(Device.Type.ROADM)) {
+        if (!device.type().equals(Device.Type.SWITCH)) {
             return;
         }
 
@@ -217,8 +216,7 @@
      * @param request the packet request
      */
     private void removeRule(Device device, PacketRequest request) {
-        // Everything is pre-provisioned on ROADMs
-        if (device.type().equals(Device.Type.ROADM)) {
+        if (!device.type().equals(Device.Type.SWITCH)) {
             return;
         }
 
diff --git a/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java b/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java
new file mode 100644
index 0000000..df4dfa5
--- /dev/null
+++ b/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java
@@ -0,0 +1,181 @@
+/*
+ * 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 com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+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.OFCalientFlowStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFObject;
+import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class CalientFiberSwitchHandshaker extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
+
+    private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
+    private List<OFCalientPortDescStatsEntry> fiberPorts = new ArrayList<>();
+
+
+    @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("Exception while sending experimenter port desc:", e.getMessage());
+            e.printStackTrace();
+        }
+
+    }
+
+    private void sendHandshakeOFExperimenterPortDescRequest() throws IOException {
+        // send multi part message for port description for optical switches
+        OFCalientPortDescStatsRequest portsRequest = factory()
+                .buildCalientPortDescStatsRequest()
+                .build();
+        log.warn("Sending experimenter port description message {}",
+                portsRequest.toString());
+        this.sendHandshakeMessage(portsRequest);
+    }
+
+    @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:
+                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:
+                break;
+            case QUEUE_GET_CONFIG_REPLY:
+                break;
+            case ROLE_REPLY:
+                break;
+            case STATS_REPLY:
+                log.warn("Received port desc reply");
+                OFCalientPortDescStatsReply descStatsReply = (OFCalientPortDescStatsReply) m;
+                fiberPorts.addAll(descStatsReply.getPortDesc());
+                // Multi-part message
+                if (!descStatsReply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
+                    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 Device.Type.FIBER_SWITCH;
+    }
+
+    @Override
+    public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
+        return ImmutableList.copyOf(fiberPorts);
+    }
+
+    @Override
+    public Set<PortDescPropertyType> getPortTypes() {
+        return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
+    }
+
+    @Override
+    public final void sendMsg(OFMessage m) {
+        OFMessage newMsg = m;
+
+        if (m.getType() == OFType.STATS_REQUEST) {
+            OFStatsRequest sr = (OFStatsRequest) m;
+            log.debug("Rebuilding stats request type {}", sr.getStatsType());
+            switch (sr.getStatsType()) {
+                case FLOW:
+                    OFCalientFlowStatsRequest request = this.factory().buildCalientFlowStatsRequest()
+                            .setCookie(((OFFlowStatsRequest) sr).getCookie())
+                            .setCookieMask(((OFFlowStatsRequest) sr).getCookieMask())
+                            .setMatch(this.factory().matchWildcardAll())
+                            .setOutGroup(((OFFlowStatsRequest) sr).getOutGroup().getGroupNumber())
+                            .setOutPort(OFPort.ANY)
+                            .setTableId(TableId.ALL)
+                            .setXid(sr.getXid())
+                            .setFlags(sr.getFlags())
+                            .build();
+                    newMsg = request;
+                    break;
+                case PORT:
+                    // TODO
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        super.sendMsg(newMsg);
+    }
+}
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 ec449b7..1e270b0 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,7 @@
  */
 package org.onosproject.driver.handshaker;
 
+import org.onosproject.net.Device;
 import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
 import org.onosproject.openflow.controller.PortDescPropertyType;
 import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
@@ -156,8 +157,8 @@
     }
 
     @Override
-    public boolean isOptical() {
-        return true;
+    public Device.Type deviceType() {
+        return Device.Type.ROADM;
     }
 
     @Override
diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml
index ee954a3..413328b 100644
--- a/drivers/src/main/resources/onos-drivers.xml
+++ b/drivers/src/main/resources/onos-drivers.xml
@@ -105,5 +105,11 @@
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
                    impl="org.onosproject.driver.pipeline.CpqdOFDPA1Pipeline"/>
     </driver>
+    <driver name="calient" extends="default"
+            manufacturer="calient inc" hwVersion="calient hardware"
+            swVersion="ocs switch">
+        <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
+                   impl="org.onosproject.driver.handshaker.CalientFiberSwitchHandshaker"/>
+    </driver>
 </drivers>
 
diff --git a/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java b/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java
index 49ca5a8..1b6810b 100644
--- a/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java
+++ b/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.openflow.controller;
 
+import org.onosproject.net.Device;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
@@ -136,11 +137,11 @@
     void returnRoleReply(RoleState requested, RoleState response);
 
     /**
-     * Indicates if this switch is optical.
+     * Returns the switch device type.
      *
-     * @return true if optical
+     * @return device type
      */
-    boolean isOptical();
+    Device.Type deviceType();
 
     /**
      * Identifies the channel used to communicate with the switch.
diff --git a/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java b/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
index 8ac1e22..2f6357b 100644
--- a/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
+++ b/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
@@ -18,6 +18,7 @@
 
 import org.jboss.netty.channel.Channel;
 import org.onlab.packet.IpAddress;
+import org.onosproject.net.Device;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 import org.onosproject.openflow.controller.Dpid;
 import org.onosproject.openflow.controller.RoleState;
@@ -95,7 +96,7 @@
     }
 
     @Override
-    public final void sendMsg(OFMessage m) {
+    public void sendMsg(OFMessage m) {
         if (role == RoleState.MASTER && channel.isConnected()) {
             channel.write(Collections.singletonList(m));
         }
@@ -413,8 +414,8 @@
 
 
     @Override
-    public boolean isOptical() {
-        return false;
+    public Device.Type deviceType() {
+        return Device.Type.SWITCH;
     }
 
 
diff --git a/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java b/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
index 416abd3..4ef4d81 100644
--- a/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -38,6 +38,8 @@
 import org.onosproject.openflow.controller.RoleState;
 import org.onosproject.openflow.controller.driver.OpenFlowAgent;
 import org.osgi.service.component.ComponentContext;
+import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
 import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
 import org.projectfloodlight.openflow.protocol.OFExperimenter;
 import org.projectfloodlight.openflow.protocol.OFFactories;
@@ -55,12 +57,17 @@
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.projectfloodlight.openflow.protocol.OFStatsReply;
 import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -290,7 +297,7 @@
                             (OFGroupDescStatsReply) reply);
                     if (groupDescStats != null) {
                         OFGroupDescStatsReply.Builder rep =
-                            OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
+                                OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
                         rep.setEntries(Lists.newLinkedList(groupDescStats));
                         rep.setXid(reply.getXid());
                         executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
@@ -299,16 +306,63 @@
                 case PORT:
                     executorMsgs.submit(new OFMessageHandler(dpid, reply));
                     break;
+                case EXPERIMENTER:
+                    if (reply instanceof OFCalientFlowStatsReply) {
+                        // Convert Calient flow statistics to regular flow stats
+                        // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
+                        OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
+                        List<OFFlowStatsEntry> entries = new LinkedList<>();
+                        for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
+
+                            // Single instruction, i.e., output to port
+                            OFActionOutput action = OFFactories
+                                    .getFactory(msg.getVersion())
+                                    .actions()
+                                    .buildOutput()
+                                    .setPort(entry.getOutPort())
+                                    .build();
+                            OFInstruction instruction = OFFactories
+                                    .getFactory(msg.getVersion())
+                                    .instructions()
+                                    .applyActions(Collections.singletonList(action));
+                            OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
+                                    .setMatch(entry.getMatch())
+                                    .setTableId(entry.getTableId())
+                                    .setDurationSec(entry.getDurationSec())
+                                    .setDurationNsec(entry.getDurationNsec())
+                                    .setPriority(entry.getPriority())
+                                    .setIdleTimeout(entry.getIdleTimeout())
+                                    .setHardTimeout(entry.getHardTimeout())
+                                    .setFlags(entry.getFlags())
+                                    .setCookie(entry.getCookie())
+                                    .setInstructions(Collections.singletonList(instruction))
+                                    .build();
+                            entries.add(fs);
+                        }
+                        fsr.setEntries(entries);
+
+                        flowStats = publishFlowStats(dpid, fsr.build());
+                        if (flowStats != null) {
+                            OFFlowStatsReply.Builder rep =
+                                    OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
+                            rep.setEntries(Lists.newLinkedList(flowStats));
+                            executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
+                        }
+                    } else {
+                        log.warn("Unsupported stats type : {}", reply.getStatsType());
+                    }
+                    break;
                 default:
-                    log.warn("Unsupported stats type : {}", reply.getStatsType());
+                    break;
             }
             break;
         case BARRIER_REPLY:
             executorBarrier.submit(new OFMessageHandler(dpid, msg));
             break;
         case EXPERIMENTER:
-            // Handle optical port stats
-            if (((OFExperimenter) msg).getExperimenter() == 0x748771) {
+            long experimenter = ((OFExperimenter) msg).getExperimenter();
+            if (experimenter == 0x748771) {
+                // LINC-OE port stats
                 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
                 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
                 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
diff --git a/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java b/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java
index ad10783..0a71a40 100644
--- a/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java
+++ b/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java
@@ -19,6 +19,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onosproject.net.Device;
 import org.onosproject.net.driver.DriverData;
 import org.onosproject.net.driver.DriverHandler;
 import org.onosproject.openflow.controller.Dpid;
@@ -181,8 +182,8 @@
         }
 
         @Override
-        public boolean isOptical() {
-            return false;
+        public Device.Type deviceType() {
+            return Device.Type.SWITCH;
         }
 
         @Override
diff --git a/pom.xml b/pom.xml
index a8564ab..f33f95b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,7 +74,7 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <netty4.version>4.0.23.Final</netty4.version>
         <copycat.version>0.5.0.onos12-SNAPSHOT</copycat.version>
-        <openflowj.version>0.4.0.onos</openflowj.version>
+        <openflowj.version>0.4.1.onos-SNAPSHOT</openflowj.version>
         <karaf.version>3.0.3</karaf.version>
         <jersey.version>1.19</jersey.version>
     </properties>
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 656702b..9177e70 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
@@ -29,9 +29,10 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.ChassisId;
 import org.onosproject.cfg.ComponentConfigService;
+import org.onlab.util.Frequency;
+import org.onlab.util.Spectrum;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
-import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.Port;
@@ -44,6 +45,7 @@
 import org.onosproject.net.device.DeviceProvider;
 import org.onosproject.net.device.DeviceProviderRegistry;
 import org.onosproject.net.device.DeviceProviderService;
+import org.onosproject.net.device.OmsPortDescription;
 import org.onosproject.net.device.PortDescription;
 import org.onosproject.net.device.PortStatistics;
 import org.onosproject.net.provider.AbstractProvider;
@@ -57,6 +59,7 @@
 import org.onosproject.openflow.controller.PortDescPropertyType;
 import org.onosproject.openflow.controller.RoleState;
 import org.osgi.service.component.ComponentContext;
+import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsEntry;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
@@ -290,8 +293,6 @@
             DeviceId did = deviceId(uri(dpid));
             OpenFlowSwitch sw = controller.getSwitch(dpid);
 
-            Device.Type deviceType = sw.isOptical() ? Device.Type.ROADM :
-                    Device.Type.SWITCH;
             ChassisId cId = new ChassisId(dpid.value());
 
             SparseAnnotations annotations = DefaultAnnotations.builder()
@@ -300,7 +301,7 @@
                     .build();
 
             DeviceDescription description =
-                    new DefaultDeviceDescription(did.uri(), deviceType,
+                    new DefaultDeviceDescription(did.uri(), sw.deviceType(),
                                                  sw.manufacturerDescription(),
                                                  sw.hardwareDescription(),
                                                  sw.softwareDescription(),
@@ -380,16 +381,33 @@
         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 -> {
-                    opsw.getPortsOf(type).forEach(
-                        op -> {
-                            portDescs.add(buildPortDescription(type, (OFPortOptical) op));
-                        }
-                    );
-                });
+
+            OpenFlowOpticalSwitch opsw;
+            switch (sw.deviceType()) {
+                case ROADM:
+                    opsw = (OpenFlowOpticalSwitch) sw;
+                    opsw.getPortTypes().forEach(type -> {
+                        opsw.getPortsOf(type).forEach(
+                                op -> {
+                                    portDescs.add(buildPortDescription(type, (OFPortOptical) op));
+                                }
+                        );
+                    });
+                    break;
+                case FIBER_SWITCH:
+                    opsw = (OpenFlowOpticalSwitch) sw;
+                    opsw.getPortTypes().forEach(type -> {
+                        opsw.getPortsOf(type).forEach(
+                                op -> {
+                                    portDescs.add(buildPortDescription((OFCalientPortDescStatsEntry) op));
+                                }
+                        );
+                    });
+                    break;
+                default:
+                    break;
             }
+
             return portDescs;
         }
 
@@ -454,6 +472,28 @@
             return new DefaultPortDescription(portNo, enabled, FIBER, 0, annotations);
         }
 
+        /**
+         * Build a portDescription from a given port description describing a fiber switch optical port.
+         *
+         * @param port description property type.
+         * @param port the port to build from.
+         * @return portDescription for the port.
+         */
+        private PortDescription buildPortDescription(OFCalientPortDescStatsEntry port) {
+            PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+
+            // FIXME when Calient OF agent reports port status
+            boolean enabled = true;
+            SparseAnnotations annotations = makePortNameAnnotation(port.getName());
+
+            // Wavelength range: 1260 - 1630 nm (S160 data sheet)
+            // Grid is irrelevant for this type of switch
+            Frequency minFreq = Spectrum.O_BAND_MAX;
+            Frequency maxFreq = Spectrum.U_BAND_MIN;
+            Frequency grid = Frequency.ofGHz(100);
+            return new OmsPortDescription(portNo, enabled, minFreq, maxFreq, grid, annotations);
+        }
+
         private PortDescription buildPortDescription(OFPortStatus status) {
             OFPortDesc port = status.getDesc();
             if (status.getReason() != OFPortReason.DELETE) {
diff --git a/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java b/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
index 4f46759..7b4d792 100644
--- a/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
+++ b/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
@@ -384,8 +384,8 @@
         }
 
         @Override
-        public boolean isOptical() {
-            return false;
+        public Device.Type deviceType() {
+            return Device.Type.SWITCH;
         }
 
         @Override
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
index f9d415e..de079e0 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -370,7 +370,7 @@
                                               + " tell us which one.");
                         }
                     }
-
+                    break;
                 default:
                     log.debug("Unhandled message type: {}", msg.getType());
             }
diff --git a/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java b/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
index e139e73..d66ba09 100644
--- a/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
+++ b/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
@@ -6,6 +6,7 @@
 import org.junit.Test;
 import org.onosproject.core.DefaultGroupId;
 import org.onosproject.core.GroupId;
+import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -383,8 +384,8 @@
         }
 
         @Override
-        public boolean isOptical() {
-            return false;
+        public Device.Type deviceType() {
+            return Device.Type.SWITCH;
         }
 
         @Override
diff --git a/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java b/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java
index 84c3544..5fded92 100644
--- a/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java
+++ b/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java
@@ -22,6 +22,7 @@
 import org.junit.Test;
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
+import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -412,13 +413,12 @@
         }
 
         @Override
-        public boolean isOptical() {
-            return false;
-        }
-
-        @Override
         public void returnRoleReply(RoleState requested, RoleState reponse) {
         }
+        @Override
+        public Device.Type deviceType() {
+            return Device.Type.SWITCH;
+        }
 
         @Override
         public String channelId() {
diff --git a/utils/misc/src/main/java/org/onlab/util/Spectrum.java b/utils/misc/src/main/java/org/onlab/util/Spectrum.java
new file mode 100644
index 0000000..42d7609
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/util/Spectrum.java
@@ -0,0 +1,51 @@
+/*
+ * 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.onlab.util;
+
+/**
+ * Telecom optical wavelength bands: O, E, S, C, L and U bands.
+ *
+ * See ITU-T G-Series Recommendations, Supplement 39
+ */
+public final class Spectrum {
+
+    private Spectrum() {
+    }
+
+    // O band (original): 1260 to 1360 nm
+    public static final Frequency O_BAND_MIN = Frequency.ofTHz(220.436);
+    public static final Frequency O_BAND_MAX = Frequency.ofTHz(237.931);
+
+    // E band (extended): 1360 to 1460 nm
+    public static final Frequency E_BAND_MIN = Frequency.ofTHz(205.337);
+    public static final Frequency E_BAND_MAX = Frequency.ofTHz(220.436);
+
+    // S band (short wavelength): 1460 to 1530 nm
+    public static final Frequency S_BAND_MIN = Frequency.ofTHz(195.943);
+    public static final Frequency S_BAND_MAX = Frequency.ofTHz(205.337);
+
+    // C band (conventional): 1530 to 1565 nm
+    public static final Frequency C_BAND_MIN = Frequency.ofTHz(191.561);
+    public static final Frequency C_BAND_MAX = Frequency.ofTHz(195.943);
+
+    // L band (long wavelength): 1565 to 1625 nm
+    public static final Frequency L_BAND_MIN = Frequency.ofTHz(184.488);
+    public static final Frequency L_BAND_MAX = Frequency.ofTHz(191.561);
+
+    // U band (ultra-long wavelength): 1625 to 1675 nm
+    public static final Frequency U_BAND_MIN = Frequency.ofTHz(178.981);
+    public static final Frequency U_BAND_MAX = Frequency.ofTHz(184.488);
+}