ONOS-2581 Add codec for tunnel id

Change-Id: I6ff456b0419b427945cc53fb74fd0a91cdfa758e
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
index 8a6a729..76f621f 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
@@ -60,6 +60,7 @@
     protected static final String SPACING_MULIPLIER = "spacingMultiplier";
     protected static final String SLOT_GRANULARITY = "slotGranularity";
     protected static final String OCH_SIGNAL_ID = "ochSignalId";
+    protected static final String TUNNEL_ID = "tunnelId";
 
     @Override
     public ObjectNode encode(Criterion criterion, CodecContext context) {
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
index 1a86284..e5f8896 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
@@ -93,6 +93,7 @@
         decoderMap.put(Criterion.Type.IPV6_EXTHDR.name(), new IpV6ExthdrDecoder());
         decoderMap.put(Criterion.Type.OCH_SIGID.name(), new OchSigIdDecoder());
         decoderMap.put(Criterion.Type.OCH_SIGTYPE.name(), new OchSigTypeDecoder());
+        decoderMap.put(Criterion.Type.TUNNEL_ID.name(), new TunnelIdDecoder());
     }
 
     private class EthTypeDecoder implements CriterionDecoder {
@@ -417,6 +418,15 @@
         }
     }
 
+    private class TunnelIdDecoder implements CriterionDecoder {
+        @Override
+        public Criterion decodeCriterion(ObjectNode json) {
+            long tunnelId = nullIsIllegal(json.get(CriterionCodec.TUNNEL_ID),
+                    CriterionCodec.TUNNEL_ID + MISSING_MEMBER_MESSAGE).asLong();
+            return Criteria.matchTunnelId(tunnelId);
+        }
+    }
+
     /**
      * Decodes the JSON into a criterion object.
      *
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
index 21968c2..568fa76 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
@@ -88,6 +88,10 @@
             return Instructions.popVlan();
         } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) {
             return Instructions.pushVlan();
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.TUNNEL_ID.name())) {
+            long tunnelId = nullIsIllegal(json.get(InstructionCodec.TUNNEL_ID),
+                    InstructionCodec.TUNNEL_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong();
+            return Instructions.modTunnelId(tunnelId);
         }
         throw new IllegalArgumentException("L2 Instruction subtype "
                 + subType + " is not supported");
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
index 0783c5e..7edbd78 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
@@ -41,6 +41,7 @@
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.SctpPortCriterion;
 import org.onosproject.net.flow.criteria.TcpPortCriterion;
+import org.onosproject.net.flow.criteria.TunnelIdCriterion;
 import org.onosproject.net.flow.criteria.UdpPortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.criteria.VlanPcpCriterion;
@@ -105,6 +106,7 @@
         formatMap.put(Criterion.Type.IPV6_EXTHDR, new FormatIpV6Exthdr());
         formatMap.put(Criterion.Type.OCH_SIGID, new FormatOchSigId());
         formatMap.put(Criterion.Type.OCH_SIGTYPE, new FormatOchSigType());
+        formatMap.put(Criterion.Type.TUNNEL_ID, new FormatTunnelId());
         formatMap.put(Criterion.Type.DUMMY, new FormatDummyType());
 
         // Currently unimplemented
@@ -116,7 +118,6 @@
         formatMap.put(Criterion.Type.MPLS_TC, new FormatUnknown());
         formatMap.put(Criterion.Type.MPLS_BOS, new FormatUnknown());
         formatMap.put(Criterion.Type.PBB_ISID, new FormatUnknown());
-        formatMap.put(Criterion.Type.TUNNEL_ID, new FormatUnknown());
         formatMap.put(Criterion.Type.UNASSIGNED_40, new FormatUnknown());
         formatMap.put(Criterion.Type.PBB_UCA, new FormatUnknown());
         formatMap.put(Criterion.Type.TCP_FLAGS, new FormatUnknown());
@@ -354,6 +355,15 @@
         }
     }
 
+    private static class FormatTunnelId implements CriterionTypeFormatter {
+        @Override
+        public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
+            final TunnelIdCriterion tunnelIdCriterion =
+                    (TunnelIdCriterion) criterion;
+            return root.put(CriterionCodec.TUNNEL_ID, tunnelIdCriterion.tunnelId());
+        }
+    }
+
     private class FormatDummyType implements CriterionTypeFormatter {
 
         @Override
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
index 850334d..6927680 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
@@ -123,6 +123,12 @@
                            pushHeaderInstructions.ethernetType().toShort());
                 break;
 
+            case TUNNEL_ID:
+                final L2ModificationInstruction.ModTunnelIdInstruction modTunnelIdInstruction =
+                        (L2ModificationInstruction.ModTunnelIdInstruction) instruction;
+                result.put(InstructionCodec.TUNNEL_ID, modTunnelIdInstruction.tunnelId());
+                break;
+
             default:
                 log.info("Cannot convert L2 subtype of {}", instruction.subtype());
                 break;
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
index 6f680c8..6fa4ae0 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
@@ -47,6 +47,7 @@
     protected static final String SPACING_MULTIPLIER = "spacingMultiplier";
     protected static final String SLOT_GRANULARITY = "slotGranularity";
     protected static final String ETHERNET_TYPE = "ethernetType";
+    protected static final String TUNNEL_ID = "tunnelId";
 
     protected static final String MISSING_MEMBER_MESSAGE =
             " member is required in Instruction";
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java
index 9c778fb..f2786b6 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java
@@ -58,6 +58,7 @@
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.SctpPortCriterion;
 import org.onosproject.net.flow.criteria.TcpPortCriterion;
+import org.onosproject.net.flow.criteria.TunnelIdCriterion;
 import org.onosproject.net.flow.criteria.UdpPortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.criteria.VlanPcpCriterion;
@@ -205,7 +206,7 @@
                             instruction.type().name() + "/" + subType, instruction);
                 });
 
-        assertThat(rule.treatment().allInstructions().size(), is(19));
+        assertThat(rule.treatment().allInstructions().size(), is(20));
 
         Instruction instruction;
 
@@ -273,6 +274,12 @@
         assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
         assertThat(instruction, instanceOf(L2ModificationInstruction.PushHeaderInstructions.class));
 
+        instruction = getInstruction(Instruction.Type.L2MODIFICATION,
+                L2ModificationInstruction.L2SubType.TUNNEL_ID.name());
+        assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
+        assertThat(((L2ModificationInstruction.ModTunnelIdInstruction) instruction)
+                        .tunnelId(), is(100L));
+
         instruction = getInstruction(Instruction.Type.L3MODIFICATION,
                 L3ModificationInstruction.L3SubType.IPV4_SRC.name());
         assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION));
@@ -347,7 +354,7 @@
 
         checkCommonData(rule);
 
-        assertThat(rule.selector().criteria().size(), is(32));
+        assertThat(rule.selector().criteria().size(), is(33));
 
         rule.selector().criteria()
                 .stream()
@@ -479,6 +486,10 @@
         criterion = getCriterion(Criterion.Type.OCH_SIGID);
         assertThat(((IndexedLambdaCriterion) criterion).lambda(),
                 is(Lambda.indexedLambda(122)));
+
+        criterion = getCriterion(Criterion.Type.TUNNEL_ID);
+        assertThat(((TunnelIdCriterion) criterion).tunnelId(),
+                is(100L));
     }
 
     /**
diff --git a/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json b/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json
index 7061820..1a96e92 100644
--- a/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json
+++ b/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json
@@ -37,7 +37,8 @@
             {"type":"IPV6_ND_TLL", "mac":"00:11:22:33:44:57"},
             {"type":"MPLS_LABEL", "label":123},
             {"type":"IPV6_EXTHDR", "exthdrFlags":99},
-            {"type":"OCH_SIGID", "lambda":122}
+            {"type":"OCH_SIGID", "lambda":122},
+            {"type":"TUNNEL_ID", "tunnelId":100}
           ]
       }
 }
diff --git a/core/common/src/test/resources/org/onosproject/codec/impl/instructions-flow.json b/core/common/src/test/resources/org/onosproject/codec/impl/instructions-flow.json
index a57731b..b3e4e4c 100644
--- a/core/common/src/test/resources/org/onosproject/codec/impl/instructions-flow.json
+++ b/core/common/src/test/resources/org/onosproject/codec/impl/instructions-flow.json
@@ -19,6 +19,7 @@
         {"type":"L2MODIFICATION","subtype":"DEC_MPLS_TTL"},
         {"type":"L2MODIFICATION","subtype":"VLAN_POP"},
         {"type":"L2MODIFICATION","subtype":"VLAN_PUSH"},
+        {"type":"L2MODIFICATION","subtype":"TUNNEL_ID", "tunnelId":100},
         {"type":"L3MODIFICATION","subtype":"IPV4_SRC", "ip":"1.2.3.4"},
         {"type":"L3MODIFICATION","subtype":"IPV4_DST", "ip":"1.2.3.3"},
         {"type":"L3MODIFICATION","subtype":"IPV6_SRC", "ip":"1.2.3.2"},