Implement some of the missing Selector and Match Conditions

Work toward ONOS-509

The following match conditions are added/implemented:
  - IN_PHY_PORT
  - IP_DSCP
  - IP_ECN
  - METADATA

Change-Id: I6f529ee90b2b9e0d5046f83c034e8be3faf86d8b
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
index 21b1832..aa9405db 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
@@ -135,6 +135,16 @@
         }
 
         @Override
+        public Builder matchInPhyPort(PortNumber port) {
+            return add(Criteria.matchInPhyPort(port));
+        }
+
+        @Override
+        public Builder matchMetadata(Long metadata) {
+            return add(Criteria.matchMetadata(metadata));
+        }
+
+        @Override
         public Builder matchEthDst(MacAddress addr) {
             return add(Criteria.matchEthDst(addr));
         }
@@ -160,6 +170,16 @@
         }
 
         @Override
+        public Builder matchIPDscp(Byte ipDscp) {
+            return add(Criteria.matchIPDscp(ipDscp));
+        }
+
+        @Override
+        public Builder matchIPEcn(Byte ipEcn) {
+            return add(Criteria.matchIPEcn(ipEcn));
+        }
+
+        @Override
         public Builder matchIPProtocol(Byte proto) {
             return add(Criteria.matchIPProtocol(proto));
         }
@@ -273,7 +293,5 @@
         public TrafficSelector build() {
             return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values()));
         }
-
     }
-
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
index e6fdeb2..1ecab71 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
@@ -68,6 +68,22 @@
         public Builder matchInPort(PortNumber port);
 
         /**
+         * Matches a physical inport.
+         *
+         * @param port the physical inport
+         * @return a selection builder
+         */
+        public Builder matchInPhyPort(PortNumber port);
+
+        /**
+         * Matches a metadata.
+         *
+         * @param metadata the metadata
+         * @return a selection builder
+         */
+        public Builder matchMetadata(Long metadata);
+
+        /**
          * Matches a l2 dst address.
          *
          * @param addr a l2 address
@@ -108,6 +124,22 @@
         public Builder matchVlanPcp(Byte vlanPcp);
 
         /**
+         * Matches an IP DSCP (6 bits in ToS field).
+         *
+         * @param ipDscp an IP DSCP value
+         * @return a selection builder
+         */
+        public Builder matchIPDscp(Byte ipDscp);
+
+        /**
+         * Matches an IP ECN (2 bits in ToS field).
+         *
+         * @param ipEcn an IP ECN value
+         * @return a selection builder
+         */
+        public Builder matchIPEcn(Byte ipEcn);
+
+        /**
          * Matches the l3 protocol.
          *
          * @param proto a l3 protocol
diff --git a/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java b/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
index d4ec124..f972d9e 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
@@ -43,7 +43,27 @@
      * @return match criterion
      */
     public static Criterion matchInPort(PortNumber port) {
-        return new PortCriterion(port);
+        return new PortCriterion(port, Type.IN_PORT);
+    }
+
+    /**
+     * Creates a match on IN_PHY_PORT field using the specified value.
+     *
+     * @param port inport value
+     * @return match criterion
+     */
+    public static Criterion matchInPhyPort(PortNumber port) {
+        return new PortCriterion(port, Type.IN_PHY_PORT);
+    }
+
+    /**
+     * Creates a match on METADATA field using the specified value.
+     *
+     * @param metadata metadata value
+     * @return match criterion
+     */
+    public static Criterion matchMetadata(Long metadata) {
+        return new MetadataCriterion(metadata);
     }
 
     /**
@@ -99,6 +119,26 @@
     }
 
     /**
+     * Creates a match on IP DSCP field using the specified value.
+     *
+     * @param ipDscp ip dscp value
+     * @return match criterion
+     */
+    public static Criterion matchIPDscp(Byte ipDscp) {
+        return new IPDscpCriterion(ipDscp);
+    }
+
+    /**
+     * Creates a match on IP ECN field using the specified value.
+     *
+     * @param ipEcn ip ecn value
+     * @return match criterion
+     */
+    public static Criterion matchIPEcn(Byte ipEcn) {
+        return new IPEcnCriterion(ipEcn);
+    }
+
+    /**
      * Creates a match on IP proto field using the specified value.
      *
      * @param proto ip protocol value
@@ -327,19 +367,23 @@
      */
     public static final class PortCriterion implements Criterion {
         private final PortNumber port;
+        private final Type type;
 
         /**
          * Constructor.
          *
          * @param port the input port number to match
+         * @param type the match type. Should be either Type.IN_PORT or
+         * Type.IN_PHY_PORT
          */
-        public PortCriterion(PortNumber port) {
+        public PortCriterion(PortNumber port, Type type) {
             this.port = port;
+            this.type = type;
         }
 
         @Override
         public Type type() {
-            return Type.IN_PORT;
+            return this.type;
         }
 
         /**
@@ -371,7 +415,61 @@
                 PortCriterion that = (PortCriterion) obj;
                 return Objects.equals(port, that.port) &&
                         Objects.equals(this.type(), that.type());
+            }
+            return false;
+        }
+    }
 
+    /**
+     * Implementation of Metadata criterion.
+     */
+    public static final class MetadataCriterion implements Criterion {
+        private final Long metadata;
+
+        /**
+         * Constructor.
+         *
+         * @param metadata the metadata to match
+         */
+        public MetadataCriterion(Long metadata) {
+            this.metadata = metadata;
+        }
+
+        @Override
+        public Type type() {
+            return Type.METADATA;
+        }
+
+        /**
+         * Gets the metadata to match.
+         *
+         * @return the metadata to match
+         */
+        public Long metadata() {
+            return metadata;
+        }
+
+        @Override
+        public String toString() {
+            return toStringHelper(type().toString())
+                    .add("metadata", Long.toHexString(metadata))
+                    .toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type(), metadata);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof MetadataCriterion) {
+                MetadataCriterion that = (MetadataCriterion) obj;
+                return Objects.equals(metadata, that.metadata) &&
+                        Objects.equals(this.type(), that.type());
             }
             return false;
         }
@@ -601,6 +699,118 @@
     }
 
     /**
+     * Implementation of IP DSCP criterion (6-bit Differentiated Services
+     * Code Point).
+     */
+    public static final class IPDscpCriterion implements Criterion {
+        private static final byte DSCP_MASK = 0x3f;
+        private final Byte ipDscp;              // IP DSCP value: 6 bits
+
+        /**
+         * Constructor.
+         *
+         * @param ipDscp the IP DSCP value to match
+         */
+        public IPDscpCriterion(Byte ipDscp) {
+            this.ipDscp = (byte) (ipDscp & DSCP_MASK);
+        }
+
+        @Override
+        public Type type() {
+            return Type.IP_DSCP;
+        }
+
+        /**
+         * Gets the IP DSCP value to match.
+         *
+         * @return the IP DSCP value to match
+         */
+        public Byte ipDscp() {
+            return ipDscp;
+        }
+
+        @Override
+        public String toString() {
+            return toStringHelper(type().toString())
+                    .add("ipDscp", ipDscp).toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type(), ipDscp);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof IPDscpCriterion) {
+                IPDscpCriterion that = (IPDscpCriterion) obj;
+                return Objects.equals(ipDscp, that.ipDscp) &&
+                        Objects.equals(this.type(), that.type());
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Implementation of IP ECN criterion (3-bit Explicit Congestion
+     * Notification).
+     */
+    public static final class IPEcnCriterion implements Criterion {
+        private static final byte ECN_MASK = 0x3;
+        private final Byte ipEcn;               // IP ECN value: 3 bits
+
+        /**
+         * Constructor.
+         *
+         * @param ipEcn the IP ECN value to match
+         */
+        public IPEcnCriterion(Byte ipEcn) {
+            this.ipEcn = (byte) (ipEcn & ECN_MASK);
+        }
+
+        @Override
+        public Type type() {
+            return Type.IP_ECN;
+        }
+
+        /**
+         * Gets the IP ECN value to match.
+         *
+         * @return the IP ECN value to match
+         */
+        public Byte ipEcn() {
+            return ipEcn;
+        }
+
+        @Override
+        public String toString() {
+            return toStringHelper(type().toString())
+                    .add("ipEcn", ipEcn).toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type(), ipEcn);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof IPEcnCriterion) {
+                IPEcnCriterion that = (IPEcnCriterion) obj;
+                return Objects.equals(ipEcn, that.ipEcn) &&
+                        Objects.equals(this.type(), that.type());
+            }
+            return false;
+        }
+    }
+
+    /**
      * Implementation of Internet Protocol Number criterion.
      */
     public static final class IPProtocolCriterion implements Criterion {
diff --git a/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java b/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
index e232647..3fb62a7 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
@@ -127,9 +127,12 @@
     public void testCriteriaCreation() {
         TrafficSelector selector;
 
+        final long longValue = 0x12345678;
         final int intValue = 22;
         final short shortValue = 33;
         final byte byteValue = 44;
+        final byte dscpValue = 0xf;
+        final byte ecnValue = 3;
         final MacAddress macValue = MacAddress.valueOf("11:22:33:44:55:66");
         final IpPrefix ipPrefixValue = IpPrefix.valueOf("192.168.1.0/24");
         final IpPrefix ipv6PrefixValue = IpPrefix.valueOf("fe80::1/64");
@@ -140,6 +143,14 @@
         assertThat(selector, hasCriterionWithType(Type.IN_PORT));
 
         selector = DefaultTrafficSelector.builder()
+                .matchInPhyPort(PortNumber.portNumber(11)).build();
+        assertThat(selector, hasCriterionWithType(Type.IN_PHY_PORT));
+
+        selector = DefaultTrafficSelector.builder()
+                .matchMetadata(longValue).build();
+        assertThat(selector, hasCriterionWithType(Type.METADATA));
+
+        selector = DefaultTrafficSelector.builder()
                 .matchEthDst(macValue).build();
         assertThat(selector, hasCriterionWithType(Type.ETH_DST));
 
@@ -160,6 +171,14 @@
         assertThat(selector, hasCriterionWithType(Type.VLAN_PCP));
 
         selector = DefaultTrafficSelector.builder()
+                .matchIPDscp(dscpValue).build();
+        assertThat(selector, hasCriterionWithType(Type.IP_DSCP));
+
+        selector = DefaultTrafficSelector.builder()
+                .matchIPEcn(ecnValue).build();
+        assertThat(selector, hasCriterionWithType(Type.IP_ECN));
+
+        selector = DefaultTrafficSelector.builder()
                 .matchIPProtocol(byteValue).build();
         assertThat(selector, hasCriterionWithType(Type.IP_PROTO));
 
diff --git a/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java b/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
index 3cebd8e..ba01133 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
@@ -45,6 +45,16 @@
     Criterion sameAsMatchInPort1 = Criteria.matchInPort(port1);
     Criterion matchInPort2 = Criteria.matchInPort(port2);
 
+    Criterion matchInPhyPort1 = Criteria.matchInPhyPort(port1);
+    Criterion sameAsMatchInPhyPort1 = Criteria.matchInPhyPort(port1);
+    Criterion matchInPhyPort2 = Criteria.matchInPhyPort(port2);
+
+    long metadata1 = 1;
+    long metadata2 = 2;
+    Criterion matchMetadata1 = Criteria.matchMetadata(metadata1);
+    Criterion sameAsMatchMetadata1 = Criteria.matchMetadata(metadata1);
+    Criterion matchMetadata2 = Criteria.matchMetadata(metadata2);
+
     private static final String MAC1 = "00:00:00:00:00:01";
     private static final String MAC2 = "00:00:00:00:00:02";
     private MacAddress mac1 = MacAddress.valueOf(MAC1);
@@ -73,6 +83,18 @@
     Criterion sameAsMatchVlanPcp1 = Criteria.matchVlanPcp(vlanPcp1);
     Criterion matchVlanPcp2 = Criteria.matchVlanPcp(vlanPcp2);
 
+    byte ipDscp1 = 1;
+    byte ipDscp2 = 2;
+    Criterion matchIpDscp1 = Criteria.matchIPDscp(ipDscp1);
+    Criterion sameAsMatchIpDscp1 = Criteria.matchIPDscp(ipDscp1);
+    Criterion matchIpDscp2 = Criteria.matchIPDscp(ipDscp2);
+
+    byte ipEcn1 = 1;
+    byte ipEcn2 = 2;
+    Criterion matchIpEcn1 = Criteria.matchIPEcn(ipEcn1);
+    Criterion sameAsMatchIpEcn1 = Criteria.matchIPEcn(ipEcn1);
+    Criterion matchIpEcn2 = Criteria.matchIPEcn(ipEcn2);
+
     byte protocol1 = 1;
     byte protocol2 = 2;
     Criterion matchIpProtocol1 = Criteria.matchIPProtocol(protocol1);
@@ -214,10 +236,13 @@
     @Test
     public void testCriteriaImmutability() {
         assertThatClassIsImmutable(Criteria.PortCriterion.class);
+        assertThatClassIsImmutable(Criteria.MetadataCriterion.class);
         assertThatClassIsImmutable(Criteria.EthCriterion.class);
         assertThatClassIsImmutable(Criteria.EthTypeCriterion.class);
         assertThatClassIsImmutable(Criteria.VlanIdCriterion.class);
         assertThatClassIsImmutable(Criteria.VlanPcpCriterion.class);
+        assertThatClassIsImmutable(Criteria.IPDscpCriterion.class);
+        assertThatClassIsImmutable(Criteria.IPEcnCriterion.class);
         assertThatClassIsImmutable(Criteria.IPProtocolCriterion.class);
         assertThatClassIsImmutable(Criteria.IPCriterion.class);
         assertThatClassIsImmutable(Criteria.TcpPortCriterion.class);
@@ -252,6 +277,20 @@
     }
 
     /**
+     * Test the matchInPhyPort method.
+     */
+    @Test
+    public void testMatchInPhyPortMethod() {
+        PortNumber p1 = portNumber(1);
+        Criterion matchInPhyPort = Criteria.matchInPhyPort(p1);
+        Criteria.PortCriterion portCriterion =
+                checkAndConvert(matchInPhyPort,
+                                Criterion.Type.IN_PHY_PORT,
+                                Criteria.PortCriterion.class);
+        assertThat(portCriterion.port(), is(equalTo(p1)));
+    }
+
+    /**
      * Test the equals() method of the PortCriterion class.
      */
     @Test
@@ -260,6 +299,38 @@
                 .addEqualityGroup(matchInPort1, sameAsMatchInPort1)
                 .addEqualityGroup(matchInPort2)
                 .testEquals();
+
+        new EqualsTester()
+                .addEqualityGroup(matchInPhyPort1, sameAsMatchInPhyPort1)
+                .addEqualityGroup(matchInPhyPort2)
+                .testEquals();
+    }
+
+    // MetadataCriterion class
+
+    /**
+     * Test the matchMetadata method.
+     */
+    @Test
+    public void testMatchMetadataMethod() {
+        Long metadata = 12L;
+        Criterion matchMetadata = Criteria.matchMetadata(metadata);
+        Criteria.MetadataCriterion metadataCriterion =
+                checkAndConvert(matchMetadata,
+                                Criterion.Type.METADATA,
+                                Criteria.MetadataCriterion.class);
+        assertThat(metadataCriterion.metadata(), is(equalTo(metadata)));
+    }
+
+    /**
+     * Test the equals() method of the MetadataCriterion class.
+     */
+    @Test
+    public void testMetadataCriterionEquals() {
+        new EqualsTester()
+                .addEqualityGroup(matchMetadata1, sameAsMatchMetadata1)
+                .addEqualityGroup(matchMetadata2)
+                .testEquals();
     }
 
     // EthCriterion class
@@ -380,6 +451,58 @@
                 .testEquals();
     }
 
+    // IPDscpCriterion class
+
+    /**
+     * Test the matchIPDscp method.
+     */
+    @Test
+    public void testMatchIPDscpMethod() {
+        Criterion matchIPDscp = Criteria.matchIPDscp(ipDscp1);
+        Criteria.IPDscpCriterion ipDscpCriterion =
+                checkAndConvert(matchIPDscp,
+                        Criterion.Type.IP_DSCP,
+                        Criteria.IPDscpCriterion.class);
+        assertThat(ipDscpCriterion.ipDscp(), is(equalTo(ipDscp1)));
+    }
+
+    /**
+     * Test the equals() method of the IPDscpCriterion class.
+     */
+    @Test
+    public void testIPDscpCriterionEquals() {
+        new EqualsTester()
+                .addEqualityGroup(matchIpDscp1, sameAsMatchIpDscp1)
+                .addEqualityGroup(matchIpDscp2)
+                .testEquals();
+    }
+
+    // IPEcnCriterion class
+
+    /**
+     * Test the matchIPEcn method.
+     */
+    @Test
+    public void testMatchIPEcnMethod() {
+        Criterion matchIPEcn = Criteria.matchIPEcn(ipEcn1);
+        Criteria.IPEcnCriterion ipEcnCriterion =
+                checkAndConvert(matchIPEcn,
+                        Criterion.Type.IP_ECN,
+                        Criteria.IPEcnCriterion.class);
+        assertThat(ipEcnCriterion.ipEcn(), is(equalTo(ipEcn1)));
+    }
+
+    /**
+     * Test the equals() method of the IPEcnCriterion class.
+     */
+    @Test
+    public void testIPEcnCriterionEquals() {
+        new EqualsTester()
+                .addEqualityGroup(matchIpEcn1, sameAsMatchIpEcn1)
+                .addEqualityGroup(matchIpEcn2)
+                .testEquals();
+    }
+
     // IpProtocolCriterion class
 
     /**
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 5c445a8..95e37d0 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
@@ -355,6 +355,15 @@
                 builder.matchInPort(PortNumber
                         .portNumber(match.get(MatchField.IN_PORT).getPortNumber()));
                 break;
+            case IN_PHY_PORT:
+                builder.matchInPhyPort(PortNumber
+                        .portNumber(match.get(MatchField.IN_PHY_PORT).getPortNumber()));
+                break;
+            case METADATA:
+                long metadata =
+                    match.get(MatchField.METADATA).getValue().getValue();
+                builder.matchMetadata(metadata);
+                break;
             case ETH_DST:
                 mac = MacAddress.valueOf(match.get(MatchField.ETH_DST).getLong());
                 builder.matchEthDst(mac);
@@ -386,6 +395,14 @@
                 byte vlanPcp = match.get(MatchField.VLAN_PCP).getValue();
                 builder.matchVlanPcp(vlanPcp);
                 break;
+            case IP_DSCP:
+                byte ipDscp = match.get(MatchField.IP_DSCP).getDscpValue();
+                builder.matchIPDscp(ipDscp);
+                break;
+            case IP_ECN:
+                byte ipEcn = match.get(MatchField.IP_ECN).getEcnValue();
+                builder.matchIPEcn(ipEcn);
+                break;
             case IP_PROTO:
                 short proto = match.get(MatchField.IP_PROTO).getIpProtocolNumber();
                 builder.matchIPProtocol((byte) proto);
@@ -514,10 +531,6 @@
             case ARP_SPA:
             case ARP_THA:
             case ARP_TPA:
-            case IN_PHY_PORT:
-            case IP_DSCP:
-            case IP_ECN:
-            case METADATA:
             case MPLS_TC:
             case TUNNEL_ID:
             default:
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 dc954da..076bfd6 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
@@ -30,11 +30,14 @@
 import org.onosproject.net.flow.criteria.Criteria.Icmpv6CodeCriterion;
 import org.onosproject.net.flow.criteria.Criteria.Icmpv6TypeCriterion;
 import org.onosproject.net.flow.criteria.Criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.Criteria.IPDscpCriterion;
+import org.onosproject.net.flow.criteria.Criteria.IPEcnCriterion;
 import org.onosproject.net.flow.criteria.Criteria.IPProtocolCriterion;
 import org.onosproject.net.flow.criteria.Criteria.IPv6FlowLabelCriterion;
 import org.onosproject.net.flow.criteria.Criteria.IPv6NDLinkLayerAddressCriterion;
 import org.onosproject.net.flow.criteria.Criteria.IPv6NDTargetAddressCriterion;
 import org.onosproject.net.flow.criteria.Criteria.LambdaCriterion;
+import org.onosproject.net.flow.criteria.Criteria.MetadataCriterion;
 import org.onosproject.net.flow.criteria.Criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.Criteria.SctpPortCriterion;
 import org.onosproject.net.flow.criteria.Criteria.TcpPortCriterion;
@@ -55,9 +58,12 @@
 import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.types.IPv6Address;
 import org.projectfloodlight.openflow.types.IPv6FlowLabel;
+import org.projectfloodlight.openflow.types.IpDscp;
+import org.projectfloodlight.openflow.types.IpEcn;
 import org.projectfloodlight.openflow.types.IpProtocol;
 import org.projectfloodlight.openflow.types.MacAddress;
 import org.projectfloodlight.openflow.types.Masked;
+import org.projectfloodlight.openflow.types.OFMetadata;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.OFVlanVidMatch;
 import org.projectfloodlight.openflow.types.TransportPort;
@@ -161,8 +167,19 @@
         for (Criterion c : selector.criteria()) {
             switch (c.type()) {
             case IN_PORT:
-                PortCriterion inport = (PortCriterion) c;
-                mBuilder.setExact(MatchField.IN_PORT, OFPort.of((int) inport.port().toLong()));
+                PortCriterion inPort = (PortCriterion) c;
+                mBuilder.setExact(MatchField.IN_PORT,
+                                  OFPort.of((int) inPort.port().toLong()));
+                break;
+            case IN_PHY_PORT:
+                PortCriterion inPhyPort = (PortCriterion) c;
+                mBuilder.setExact(MatchField.IN_PORT,
+                                  OFPort.of((int) inPhyPort.port().toLong()));
+                break;
+            case METADATA:
+                MetadataCriterion metadata = (MetadataCriterion) c;
+                mBuilder.setExact(MatchField.METADATA,
+                                  OFMetadata.ofRaw(metadata.metadata()));
                 break;
             case ETH_DST:
                 ethCriterion = (EthCriterion) c;
@@ -193,6 +210,16 @@
                 VlanPcpCriterion vpcp = (VlanPcpCriterion) c;
                 mBuilder.setExact(MatchField.VLAN_PCP, VlanPcp.of(vpcp.priority()));
                 break;
+            case IP_DSCP:
+                IPDscpCriterion ipDscpCriterion = (IPDscpCriterion) c;
+                mBuilder.setExact(MatchField.IP_DSCP,
+                                  IpDscp.of(ipDscpCriterion.ipDscp()));
+                break;
+            case IP_ECN:
+                IPEcnCriterion ipEcnCriterion = (IPEcnCriterion) c;
+                mBuilder.setExact(MatchField.IP_ECN,
+                                  IpEcn.of(ipEcnCriterion.ipEcn()));
+                break;
             case IP_PROTO:
                 IPProtocolCriterion p = (IPProtocolCriterion) c;
                 mBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(p.protocol()));
@@ -353,11 +380,7 @@
             case ARP_SPA:
             case ARP_THA:
             case ARP_TPA:
-            case IN_PHY_PORT:
             case IPV6_EXTHDR:
-            case IP_DSCP:
-            case IP_ECN:
-            case METADATA:
             case MPLS_BOS:
             case MPLS_TC:
             case PBB_ISID:
diff --git a/web/api/src/main/java/org/onosproject/codec/impl/CriterionCodec.java b/web/api/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
index 9d714b0..3c6d4d7 100644
--- a/web/api/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
+++ b/web/api/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
@@ -43,10 +43,17 @@
         switch (criterion.type()) {
 
             case IN_PORT:
+            case IN_PHY_PORT:
                 final Criteria.PortCriterion portCriterion = (Criteria.PortCriterion) criterion;
                 result.put("port", portCriterion.port().toLong());
                 break;
 
+            case METADATA:
+                final Criteria.MetadataCriterion metadataCriterion =
+                        (Criteria.MetadataCriterion) criterion;
+                result.put("metadata", metadataCriterion.metadata());
+                break;
+
             case ETH_DST:
             case ETH_SRC:
                 final Criteria.EthCriterion ethCriterion = (Criteria.EthCriterion) criterion;
@@ -71,6 +78,18 @@
                 result.put("priority", vlanPcpCriterion.priority());
                 break;
 
+            case IP_DSCP:
+                final Criteria.IPDscpCriterion ipDscpCriterion =
+                        (Criteria.IPDscpCriterion) criterion;
+                result.put("ipDscp", ipDscpCriterion.ipDscp());
+                break;
+
+            case IP_ECN:
+                final Criteria.IPEcnCriterion ipEcnCriterion =
+                        (Criteria.IPEcnCriterion) criterion;
+                result.put("ipEcn", ipEcnCriterion.ipEcn());
+                break;
+
             case IP_PROTO:
                 final Criteria.IPProtocolCriterion iPProtocolCriterion =
                         (Criteria.IPProtocolCriterion) criterion;
diff --git a/web/api/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java b/web/api/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
index b8c430c..8032ee5 100644
--- a/web/api/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
+++ b/web/api/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
@@ -35,7 +35,8 @@
 
     // CHECKSTYLE IGNORE MethodLength FOR NEXT 300 LINES
     @Override
-    public boolean matchesSafely(JsonNode jsonCriterion, Description description) {
+    public boolean matchesSafely(JsonNode jsonCriterion,
+                                 Description description) {
         final String type = criterion.type().name();
         final String jsonType = jsonCriterion.get("type").asText();
         if (!type.equals(jsonType)) {
@@ -46,7 +47,9 @@
         switch (criterion.type()) {
 
             case IN_PORT:
-                final Criteria.PortCriterion portCriterion = (Criteria.PortCriterion) criterion;
+            case IN_PHY_PORT:
+                final Criteria.PortCriterion portCriterion =
+                        (Criteria.PortCriterion) criterion;
                 final long port = portCriterion.port().toLong();
                 final long jsonPort = jsonCriterion.get("port").asLong();
                 if (port != jsonPort) {
@@ -55,9 +58,21 @@
                 }
                 break;
 
+            case METADATA:
+                final Criteria.MetadataCriterion metadataCriterion =
+                        (Criteria.MetadataCriterion) criterion;
+                final long metadata = metadataCriterion.metadata();
+                final long jsonMetadata = jsonCriterion.get("metadata").asLong();
+                if (metadata != jsonMetadata) {
+                    description.appendText("metadata was " + Long.toString(jsonMetadata));
+                    return false;
+                }
+                break;
+
             case ETH_DST:
             case ETH_SRC:
-                final Criteria.EthCriterion ethCriterion = (Criteria.EthCriterion) criterion;
+                final Criteria.EthCriterion ethCriterion =
+                    (Criteria.EthCriterion) criterion;
                 final String mac = ethCriterion.mac().toString();
                 final String jsonMac = jsonCriterion.get("mac").textValue();
                 if (!mac.equals(jsonMac)) {
@@ -99,6 +114,28 @@
                 }
                 break;
 
+            case IP_DSCP:
+                final Criteria.IPDscpCriterion ipDscpCriterion =
+                        (Criteria.IPDscpCriterion) criterion;
+                final byte ipDscp = ipDscpCriterion.ipDscp();
+                final byte jsonIpDscp = (byte) jsonCriterion.get("ipDscp").shortValue();
+                if (ipDscp != jsonIpDscp) {
+                    description.appendText("IP DSCP was " + Byte.toString(jsonIpDscp));
+                    return false;
+                }
+                break;
+
+            case IP_ECN:
+                final Criteria.IPEcnCriterion ipEcnCriterion =
+                        (Criteria.IPEcnCriterion) criterion;
+                final byte ipEcn = ipEcnCriterion.ipEcn();
+                final byte jsonIpEcn = (byte) jsonCriterion.get("ipEcn").shortValue();
+                if (ipEcn != jsonIpEcn) {
+                    description.appendText("IP ECN was " + Byte.toString(jsonIpEcn));
+                    return false;
+                }
+                break;
+
             case IP_PROTO:
                 final Criteria.IPProtocolCriterion iPProtocolCriterion =
                         (Criteria.IPProtocolCriterion) criterion;
@@ -114,7 +151,8 @@
             case IPV4_DST:
             case IPV6_SRC:
             case IPV6_DST:
-                final Criteria.IPCriterion ipCriterion = (Criteria.IPCriterion) criterion;
+                final Criteria.IPCriterion ipCriterion =
+                    (Criteria.IPCriterion) criterion;
                 final String ip = ipCriterion.ip().toString();
                 final String jsonIp = jsonCriterion.get("ip").textValue();
                 if (!ip.equals(jsonIp)) {
@@ -217,7 +255,7 @@
             case IPV6_ND_TARGET:
                 final Criteria.IPv6NDTargetAddressCriterion
                     ipv6NDTargetAddressCriterion =
-                    (Criteria.IPv6NDTargetAddressCriterion) criterion;
+                        (Criteria.IPv6NDTargetAddressCriterion) criterion;
                 final String targetAddress =
                     ipv6NDTargetAddressCriterion.targetAddress().toString();
                 final String jsonTargetAddress =
@@ -233,7 +271,7 @@
             case IPV6_ND_TLL:
                 final Criteria.IPv6NDLinkLayerAddressCriterion
                     ipv6NDLinkLayerAddressCriterion =
-                    (Criteria.IPv6NDLinkLayerAddressCriterion) criterion;
+                        (Criteria.IPv6NDLinkLayerAddressCriterion) criterion;
                 final String llAddress =
                     ipv6NDLinkLayerAddressCriterion.mac().toString();
                 final String jsonLlAddress =