Handle ModOchSignalInstruction in FlowModBuidlerVer13

To support OCh (Optical Channel) according to ONF
"Optical Transport Protocol Extension Version 1.0"

Change-Id: I00d0d61a9c2a2808cf5a02df608a6f3a35afaf28
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
index bcaf476..5fa3baf 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -18,6 +18,9 @@
 import com.google.common.collect.Lists;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip6Address;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignal;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficTreatment;
@@ -27,6 +30,7 @@
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
+import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
@@ -246,9 +250,14 @@
         L0ModificationInstruction l0m = (L0ModificationInstruction) i;
         switch (l0m.subtype()) {
             case LAMBDA:
-                ModLambdaInstruction ml = (ModLambdaInstruction) i;
-                return factory().actions().circuit(factory().oxms().ochSigidBasic(
-                        new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
+                return buildModLambdaInstruction((ModLambdaInstruction) i);
+            case OCH:
+                try {
+                    return buildModOchSignalInstruction((ModOchSignalInstruction) i);
+                } catch (UnsupportedGridTypeException | UnsupportedChannelSpacingException e) {
+                    log.warn(e.getMessage());
+                    break;
+                }
             default:
                 log.warn("Unimplemented action type {}.", l0m.subtype());
                 break;
@@ -256,6 +265,64 @@
         return null;
     }
 
+    private OFAction buildModLambdaInstruction(ModLambdaInstruction instruction) {
+        return factory().actions().circuit(factory().oxms().ochSigidBasic(
+                new CircuitSignalID((byte) 1, (byte) 2, instruction.lambda(), (short) 1)));
+    }
+
+    private OFAction buildModOchSignalInstruction(ModOchSignalInstruction instruction) {
+        OchSignal signal = instruction.lambda();
+        byte gridType = convertGridType(signal.gridType());
+        byte channelSpacing = convertChannelSpacing(signal.channelSpacing());
+
+        return factory().actions().circuit(factory().oxms().ochSigidBasic(
+                new CircuitSignalID(gridType, channelSpacing,
+                        (short) signal.spacingMultiplier(), (short) signal.slotGranularity())
+        ));
+    }
+
+    private byte convertGridType(GridType type) {
+        // See ONF "Optical Transport Protocol Extensions Version 1.0"
+        // for the following values
+        switch (type) {
+            case DWDM:
+                // OFPGRIDT_DWDM of enum ofp_grid_type
+                return 1;
+            case CWDM:
+                // OFPGRIDT_CWDM of enum ofp_grid_type
+                return 2;
+            case FLEX:
+                // OFPGRIDT_FLEX of enum ofp_grid_type
+                return 3;
+            default:
+                throw new UnsupportedGridTypeException(type);
+        }
+    }
+
+    private byte convertChannelSpacing(ChannelSpacing spacing) {
+        // See ONF "Optical Transport Protocol Extensions Version 1.0"
+        // for the following values
+        switch (spacing) {
+            case CHL_100GHZ:
+                // OFPCS_100GHZ of enum ofp_chl_spacing
+                return 1;
+            case CHL_50GHZ:
+                // OFPCS_50GHZ of enum ofp_chl_spacing
+                return 2;
+            case CHL_25GHZ:
+                // OFPCS_25GHZ of enum ofp_chl_spacing
+                return 3;
+            case CHL_12P5GHZ:
+                // OFPCS_12P5GHZ of enum ofp_chl_spacing
+                return 4;
+            case CHL_6P25GHZ:
+                // OFPCS_6P25GHZ of enum ofp_chl_spacing
+                return 5;
+            default:
+                throw new UnsupportedChannelSpacingException(spacing);
+        }
+    }
+
     private OFAction buildL2Modification(Instruction i) {
         L2ModificationInstruction l2m = (L2ModificationInstruction) i;
         ModEtherInstruction eth;