[Emu] ODU SIGID and SIGTYPE FlowEntryBuilder and FlowModBuilder implementations

Change-Id: I6b332f98dd74250d1cdb289a00780d0d16ae7fb2
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
index d4494f1..b12d8a6 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
@@ -27,6 +27,7 @@
 import org.onosproject.core.DefaultGroupId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Lambda;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.driver.DefaultDriverData;
 import org.onosproject.net.driver.DefaultDriverHandler;
@@ -83,15 +84,21 @@
 import org.projectfloodlight.openflow.types.U64;
 import org.projectfloodlight.openflow.types.U8;
 import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.OduSignalID;
 import org.slf4j.Logger;
 
 import java.util.List;
 
 import static org.onosproject.net.flow.criteria.Criteria.matchLambda;
 import static org.onosproject.net.flow.criteria.Criteria.matchOchSignalType;
+import static org.onosproject.net.flow.criteria.Criteria.matchOduSignalType;
+import static org.onosproject.net.flow.criteria.Criteria.matchOduSignalId;
+import static org.onosproject.net.flow.instructions.Instructions.modL0Lambda;
+import static org.onosproject.net.flow.instructions.Instructions.modL1OduSignalId;
 import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupChannelSpacing;
 import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupGridType;
 import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOchSignalType;
+import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOduSignalType;
 import static org.slf4j.LoggerFactory.getLogger;
 
 public class FlowEntryBuilder {
@@ -454,6 +461,29 @@
                 builder.extension(interpreter.mapAction(action), DeviceId.deviceId(Dpid.uri(dpid)));
             }
             break;
+       case EXP_ODU_SIG_ID:
+            @SuppressWarnings("unchecked")
+            OFOxm<OduSignalID> oduID = (OFOxm<OduSignalID>) oxm;
+            OduSignalID oduSignalID = oduID.getValue();
+            OduSignalId oduSignalId = OduSignalId.oduSignalId(oduSignalID.getTpn(),
+                    oduSignalID.getTslen(),
+                    oduSignalID.getTsmap());
+            builder.add(modL1OduSignalId(oduSignalId));
+            break;
+        case EXP_OCH_SIG_ID:
+            try {
+                @SuppressWarnings("unchecked")
+                OFOxm<CircuitSignalID> ochId = (OFOxm<CircuitSignalID>) oxm;
+                CircuitSignalID circuitSignalID = ochId.getValue();
+                builder.add(modL0Lambda(Lambda.ochSignal(
+                        lookupGridType(circuitSignalID.getGridType()),
+                        lookupChannelSpacing(circuitSignalID.getChannelSpacing()),
+                        circuitSignalID.getChannelNumber(), circuitSignalID.getSpectralWidth())));
+            } catch (NoMappingFoundException e) {
+                log.warn(e.getMessage());
+                break;
+            }
+            break;
         case ARP_OP:
         case ARP_SHA:
         case ARP_SPA:
@@ -501,6 +531,8 @@
         case OCH_SIGTYPE_BASIC:
         case SCTP_DST:
         case SCTP_SRC:
+        case EXP_ODU_SIGTYPE:
+        case EXP_OCH_SIGTYPE:
         default:
             log.warn("Set field type {} not yet implemented.", oxm.getMatchField().id);
             break;
@@ -704,6 +736,41 @@
                 U8 sigType = match.get(MatchField.OCH_SIGTYPE);
                 builder.add(matchOchSignalType(lookupOchSignalType((byte) sigType.getValue())));
                 break;
+            case EXP_OCH_SIG_ID:
+                try {
+                    CircuitSignalID expSigId = match.get(MatchField.EXP_OCH_SIG_ID);
+                    builder.add(matchLambda(Lambda.ochSignal(
+                            lookupGridType(expSigId.getGridType()), lookupChannelSpacing(expSigId.getChannelSpacing()),
+                            expSigId.getChannelNumber(), expSigId.getSpectralWidth())));
+                } catch (NoMappingFoundException e) {
+                    log.warn(e.getMessage());
+                    break;
+                }
+                break;
+            case EXP_OCH_SIGTYPE:
+                try {
+                    U8 expOchSigType = match.get(MatchField.EXP_OCH_SIGTYPE);
+                    builder.add(matchOchSignalType(lookupOchSignalType((byte) expOchSigType.getValue())));
+                } catch (NoMappingFoundException e) {
+                    log.warn(e.getMessage());
+                    break;
+                }
+                break;
+            case EXP_ODU_SIG_ID:
+                OduSignalId oduSignalId = OduSignalId.oduSignalId(match.get(MatchField.EXP_ODU_SIG_ID).getTpn(),
+                        match.get(MatchField.EXP_ODU_SIG_ID).getTslen(),
+                        match.get(MatchField.EXP_ODU_SIG_ID).getTsmap());
+                builder.add(matchOduSignalId(oduSignalId));
+            break;
+            case EXP_ODU_SIGTYPE:
+                try {
+                    U8 oduSigType = match.get(MatchField.EXP_ODU_SIGTYPE);
+                    builder.add(matchOduSignalType(lookupOduSignalType((byte) oduSigType.getValue())));
+                } catch (NoMappingFoundException e) {
+                    log.warn(e.getMessage());
+                    break;
+                }
+                break;
             case TUNNEL_ID:
                 long tunnelId = match.get(MatchField.TUNNEL_ID).getValue();
                 builder.matchTunnelId(tunnelId);
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
index e6f2f74..7a6aeea 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
@@ -26,6 +26,7 @@
 import org.onosproject.net.driver.DefaultDriverHandler;
 import org.onosproject.net.driver.Driver;
 import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.criteria.ArpHaCriterion;
@@ -53,6 +54,8 @@
 import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.OchSignalCriterion;
 import org.onosproject.net.flow.criteria.OchSignalTypeCriterion;
+import org.onosproject.net.flow.criteria.OduSignalIdCriterion;
+import org.onosproject.net.flow.criteria.OduSignalTypeCriterion;
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.SctpPortCriterion;
 import org.onosproject.net.flow.criteria.TcpPortCriterion;
@@ -92,6 +95,7 @@
 import org.projectfloodlight.openflow.types.U8;
 import org.projectfloodlight.openflow.types.VlanPcp;
 import org.projectfloodlight.openflow.types.VlanVid;
+import org.projectfloodlight.openflow.types.OduSignalID;
 import org.slf4j.Logger;
 
 import java.util.Optional;
@@ -408,7 +412,7 @@
                     OchSignal signal = ochSignalCriterion.lambda();
                     byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType());
                     byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing());
-                    mBuilder.setExact(MatchField.OCH_SIGID,
+                    mBuilder.setExact(MatchField.EXP_OCH_SIG_ID,
                             new CircuitSignalID(gridType, channelSpacing,
                                     (short) signal.spacingMultiplier(), (short) signal.slotGranularity()));
                 } catch (NoMappingFoundException e) {
@@ -416,9 +420,30 @@
                 }
                 break;
             case OCH_SIGTYPE:
-                OchSignalTypeCriterion sc = (OchSignalTypeCriterion) c;
-                byte signalType = OpenFlowValueMapper.lookupOchSignalType(sc.signalType());
-                mBuilder.setExact(MatchField.OCH_SIGTYPE, U8.of(signalType));
+                try {
+                    OchSignalTypeCriterion sc = (OchSignalTypeCriterion) c;
+                    byte signalType = OpenFlowValueMapper.lookupOchSignalType(sc.signalType());
+                    mBuilder.setExact(MatchField.EXP_OCH_SIGTYPE, U8.of(signalType));
+                } catch (NoMappingFoundException e) {
+                    log.warn(e.getMessage());
+                }
+                break;
+            case ODU_SIGID:
+                OduSignalIdCriterion oduSignalIdCriterion = (OduSignalIdCriterion) c;
+                OduSignalId oduSignalId = oduSignalIdCriterion.oduSignalId();
+                mBuilder.setExact(MatchField.EXP_ODU_SIG_ID,
+                        new OduSignalID((short) oduSignalId.tributaryPortNumber(),
+                                (short) oduSignalId.tributarySlotLength(),
+                                oduSignalId.tributarySlotBitmap()));
+                break;
+            case ODU_SIGTYPE:
+                try {
+                    OduSignalTypeCriterion oduSignalTypeCriterion = (OduSignalTypeCriterion) c;
+                    byte oduSigType = OpenFlowValueMapper.lookupOduSignalType(oduSignalTypeCriterion.signalType());
+                    mBuilder.setExact(MatchField.EXP_ODU_SIGTYPE, U8.of(oduSigType));
+                } catch (NoMappingFoundException e) {
+                    log.warn(e.getMessage());
+                }
                 break;
             case TUNNEL_ID:
                 TunnelIdCriterion tunnelId = (TunnelIdCriterion) c;
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
index bdea09d..d4ebb4f 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
@@ -181,6 +181,7 @@
                 acts.add(queueBuilder.build());
                 break;
             case L0MODIFICATION:
+            case L1MODIFICATION:
             case GROUP:
             case TABLE:
             case METADATA:
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 3521ca4..a3182e7 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
@@ -19,6 +19,7 @@
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip6Address;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.driver.DefaultDriverData;
 import org.onosproject.net.driver.DefaultDriverHandler;
@@ -35,6 +36,8 @@
 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.L1ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
@@ -76,6 +79,7 @@
 import org.projectfloodlight.openflow.types.OFGroup;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.OduSignalID;
 import org.projectfloodlight.openflow.types.TableId;
 import org.projectfloodlight.openflow.types.TransportPort;
 import org.projectfloodlight.openflow.types.U32;
@@ -234,6 +238,9 @@
                 case L0MODIFICATION:
                     actions.add(buildL0Modification(i));
                     break;
+                case L1MODIFICATION:
+                    actions.add(buildL1Modification(i));
+                    break;
                 case L2MODIFICATION:
                     actions.add(buildL2Modification(i));
                     break;
@@ -303,20 +310,31 @@
 
     private OFAction buildL0Modification(Instruction i) {
         L0ModificationInstruction l0m = (L0ModificationInstruction) i;
+        OFOxm<?> oxm = null;
         switch (l0m.subtype()) {
             case LAMBDA:
                 return buildModLambdaInstruction((ModLambdaInstruction) i);
             case OCH:
                 try {
-                    return buildModOchSignalInstruction((ModOchSignalInstruction) i);
+                    ModOchSignalInstruction modOchSignalInstruction = (ModOchSignalInstruction) l0m;
+                    OchSignal signal = modOchSignalInstruction.lambda();
+                    byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType());
+                    byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing());
+                    oxm = factory().oxms().expOchSigId(
+                            new CircuitSignalID(gridType, channelSpacing,
+                                    (short) signal.spacingMultiplier(), (short) signal.slotGranularity()));
                 } catch (NoMappingFoundException e) {
                     log.warn(e.getMessage());
                     break;
                 }
+                break;
             default:
                 log.warn("Unimplemented action type {}.", l0m.subtype());
                 break;
         }
+        if (oxm != null) {
+            return factory().actions().buildSetField().setField(oxm).build();
+        }
         return null;
     }
 
@@ -336,6 +354,31 @@
         ));
     }
 
+    private OFAction buildL1Modification(Instruction i) {
+        L1ModificationInstruction l1m = (L1ModificationInstruction) i;
+        OFOxm<?> oxm = null;
+        switch (l1m.subtype()) {
+        case ODU_SIGID:
+            ModOduSignalIdInstruction modOduSignalIdInstruction = (ModOduSignalIdInstruction) l1m;
+            OduSignalId oduSignalId = modOduSignalIdInstruction.oduSignalId();
+
+            OduSignalID oduSignalID = new OduSignalID((short) oduSignalId.tributaryPortNumber(),
+                    (short) oduSignalId.tributarySlotLength(),
+                    oduSignalId.tributarySlotBitmap());
+
+            oxm = factory().oxms().expOduSigId(oduSignalID);
+            break;
+        default:
+            log.warn("Unimplemented action type {}.", l1m.subtype());
+            break;
+        }
+
+        if (oxm != null) {
+            return factory().actions().buildSetField().setField(oxm).build();
+        }
+        return null;
+    }
+
     private OFAction buildL2Modification(Instruction i) {
         L2ModificationInstruction l2m = (L2ModificationInstruction) i;
         ModEtherInstruction eth;
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java
index 2f0831c..556f76f 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java
@@ -20,6 +20,7 @@
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.OchSignalType;
+import org.onosproject.net.OduSignalType;
 
 /**
  * Collection of helper methods to convert protocol agnostic models to values used in OpenFlow spec.
@@ -54,6 +55,17 @@
         OCH_SIGNAL_TYPES.put(OchSignalType.FLEX_GRID, (byte) 2);  // OFPOCHT_FLEX_GRID of enum ofp_och_signal_type
     }
 
+    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.
      *
@@ -149,4 +161,30 @@
     static OchSignalType lookupOchSignalType(byte signalType) {
         return lookup(OCH_SIGNAL_TYPES.inverse(), signalType, OchSignalType.class);
     }
+
+    /**
+     * Looks up the corresponding byte value for ODU signal type defined in
+     * ONF "Optical Transport Protocol Extensions Version 1.0"
+     * from the specified {@link OchSignalType} instance.
+     *
+     * @param signalType ODU (Optical channel Data Unit) signal type
+     * @return byte value corresponding to the specified ODU signal type
+     * @throws NoMappingFoundException if the specified ODU signal type is not found
+     */
+    static byte lookupOduSignalType(OduSignalType signalType) {
+        return lookup(ODU_SIGNAL_TYPES, signalType, Byte.class);
+    }
+
+    /**
+     * Looks up the the corresponding {@link OchSignalType} 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
+     * @throws NoMappingFoundException if the specified ODU signal type is not found
+     */
+    static OduSignalType lookupOduSignalType(byte signalType) {
+        return lookup(ODU_SIGNAL_TYPES.inverse(), signalType, OduSignalType.class);
+    }
 }