Merge "Remove remoterpc dead code."
[controller.git] / opendaylight / protocol_plugins / openflow / src / main / java / org / opendaylight / controller / protocol_plugin / openflow / vendorextension / v6extension / V6Match.java
index 2da6b9b00891008850075e31920d02c01888ad16..4b8966c54698b048490480aa5f758cf1d1df1e2b 100644 (file)
@@ -1,6 +1,5 @@
-
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2013-2014 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -9,49 +8,44 @@
 
 package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension;
 
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-import org.openflow.protocol.OFMatch;
-import org.openflow.util.U16;
-import org.openflow.util.U8;
-
 import java.net.Inet6Address;
-import org.opendaylight.controller.sal.utils.HexEncode;
-
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.openflow.protocol.OFMatch;
+import org.openflow.util.U16;
+import org.openflow.util.U8;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * This Class forms the vendor specific IPv6 Flow Match messages as well as
  * processes the vendor specific IPv6 Stats Reply message.
- * 
- * For message creation, it parses the user entered IPv6 match fields, creates 
- * a sub-message for each field which are later used to form the complete 
- * message.  
- * 
+ *
+ * For message creation, it parses the user entered IPv6 match fields, creates a
+ * sub-message for each field which are later used to form the complete message.
+ *
  * For message processing, it parses the incoming message and reads each field
  * of the message and stores in appropriate field of V6Match object.
- *  
+ *
  *
  */
 public class V6Match extends OFMatch implements Cloneable {
     private static final Logger logger = LoggerFactory.getLogger(V6Match.class);
     private static final long serialVersionUID = 1L;
-    protected InetAddress nwSrc;
-    protected InetAddress nwDst;
+    protected Inet6Address nwSrc;
+    protected Inet6Address nwDst;
     protected short inputPortMask;
     protected byte[] dataLayerSourceMask;
     protected byte[] dataLayerDestinationMask;
-    protected short dataLayerVirtualLanMask;
-    protected byte dataLayerVirtualLanPriorityCodePointMask;
+    protected int dataLayerVirtualLanTCIMask;
     protected short dataLayerTypeMask;
     protected byte networkTypeOfServiceMask;
     protected byte networkProtocolMask;
-    protected InetAddress networkSourceMask;
-    protected InetAddress networkDestinationMask;
     protected short transportSourceMask;
     protected short transportDestinationMask;
     protected short srcIPv6SubnetMaskbits;
@@ -60,7 +54,9 @@ public class V6Match extends OFMatch implements Cloneable {
     protected MatchFieldState inputPortState;
     protected MatchFieldState dlSourceState;
     protected MatchFieldState dlDestState;
-    protected MatchFieldState dlVlanState;
+    protected MatchFieldState dlVlanIDState;
+    protected MatchFieldState dlVlanPCPState;
+    protected MatchFieldState dlVlanTCIState;
     protected MatchFieldState ethTypeState;
     protected MatchFieldState nwTosState;
     protected MatchFieldState nwProtoState;
@@ -73,6 +69,16 @@ public class V6Match extends OFMatch implements Cloneable {
 
     private static int IPV6_EXT_MIN_HDR_LEN = 36;
 
+    /**
+     * CFI bit in VLAN TCI field.
+     */
+    private static final int  VLAN_TCI_CFI = 1 << 12;
+
+    /**
+     * Value of OFP_VLAN_NONE defined by OpenFlow 1.0.
+     */
+    private static final short  OFP_VLAN_NONE = (short) 0xffff;
+
     private enum MatchFieldState {
         MATCH_ABSENT, MATCH_FIELD_ONLY, MATCH_FIELD_WITH_MASK
     }
@@ -134,10 +140,7 @@ public class V6Match extends OFMatch implements Cloneable {
         this.dataLayerSourceMask = null;
         this.dataLayerDestinationMask = null;
         this.dataLayerTypeMask = 0;
-        this.dataLayerVirtualLanMask = 0;
-        this.dataLayerVirtualLanPriorityCodePointMask = 0;
-        this.networkDestinationMask = null;
-        this.networkSourceMask = null;
+        this.dataLayerVirtualLanTCIMask = 0;
         this.networkTypeOfServiceMask = 0;
         this.networkProtocolMask = 0;
         this.transportSourceMask = 0;
@@ -146,7 +149,9 @@ public class V6Match extends OFMatch implements Cloneable {
         this.inputPortState = MatchFieldState.MATCH_ABSENT;
         this.dlSourceState = MatchFieldState.MATCH_ABSENT;
         this.dlDestState = MatchFieldState.MATCH_ABSENT;
-        this.dlVlanState = MatchFieldState.MATCH_ABSENT;
+        this.dlVlanIDState = MatchFieldState.MATCH_ABSENT;
+        this.dlVlanPCPState = MatchFieldState.MATCH_ABSENT;
+        this.dlVlanTCIState = MatchFieldState.MATCH_ABSENT;
         this.ethTypeState = MatchFieldState.MATCH_ABSENT;
         this.nwTosState = MatchFieldState.MATCH_ABSENT;
         this.nwProtoState = MatchFieldState.MATCH_ABSENT;
@@ -164,33 +169,19 @@ public class V6Match extends OFMatch implements Cloneable {
         this.match_len = 0;
         this.pad_size = 0;
 
-        this.networkSourceMask = null;
         if (match.getNetworkSource() != 0) {
-            InetAddress address = null;
-            try {
-                address = InetAddress.getByAddress(ByteBuffer.allocate(4)
-                        .putInt(match.getNetworkSource()).array());
-            } catch (UnknownHostException e) {
-                logger.error("",e);
-            }
-            this.setNetworkSource(address, null);
+            InetAddress address = NetUtils.getInetAddress(match.getNetworkSource());
+            InetAddress mask = NetUtils.getInetNetworkMask(match.getNetworkSourceMaskLen(), false);
+            this.setNetworkSource(address, mask);
         } else {
-            this.nwSrc = null;
             this.nwSrcState = MatchFieldState.MATCH_ABSENT;
         }
 
-        this.networkDestinationMask = null;
         if (match.getNetworkDestination() != 0) {
-            InetAddress address = null;
-            try {
-                address = InetAddress.getByAddress(ByteBuffer.allocate(4)
-                        .putInt(match.getNetworkDestination()).array());
-            } catch (UnknownHostException e) {
-                logger.error("",e);
-            }
-            this.setNetworkDestination(address, null);
+            InetAddress address = NetUtils.getInetAddress(match.getNetworkDestination());
+            InetAddress mask = NetUtils.getInetNetworkMask(match.getNetworkDestinationMaskLen(), false);
+            this.setNetworkDestination(address, mask);
         } else {
-            this.nwDst = null;
             this.nwDstState = MatchFieldState.MATCH_ABSENT;
         }
 
@@ -203,17 +194,17 @@ public class V6Match extends OFMatch implements Cloneable {
         }
 
         this.dataLayerSourceMask = null;
-        if (match.getDataLayerSource() != null) {
+        if (match.getDataLayerSource() != null
+                && !NetUtils.isZeroMAC(match.getDataLayerSource())) {
             this.setDataLayerSource(match.getDataLayerSource(), null);
         } else {
-            this.dataLayerSource = null;
             this.dlSourceState = MatchFieldState.MATCH_ABSENT;
         }
         this.dataLayerDestinationMask = null;
-        if (match.getDataLayerDestination() != null) {
+        if (match.getDataLayerDestination() != null
+                && !NetUtils.isZeroMAC(match.getDataLayerDestination())) {
             this.setDataLayerDestination(match.getDataLayerDestination(), null);
         } else {
-            this.dataLayerDestination = null;
             this.dlDestState = MatchFieldState.MATCH_ABSENT;
         }
 
@@ -225,27 +216,28 @@ public class V6Match extends OFMatch implements Cloneable {
             this.ethTypeState = MatchFieldState.MATCH_ABSENT;
         }
 
-        this.dataLayerVirtualLanMask = 0;
+        this.dataLayerVirtualLanTCIMask = 0;
+        this.dlVlanTCIState = MatchFieldState.MATCH_ABSENT;
         if (match.getDataLayerVirtualLan() != 0) {
             this.setDataLayerVirtualLan(match.getDataLayerVirtualLan(),
                     (short) 0);
         } else {
             this.dataLayerVirtualLan = 0;
-            this.dlVlanState = MatchFieldState.MATCH_ABSENT;
+            this.dlVlanIDState = MatchFieldState.MATCH_ABSENT;
         }
 
-        this.dataLayerVirtualLanPriorityCodePointMask = 0;
-        if (match.getDataLayerVirtualLanPriorityCodePoint() != 0) {
-            this.setDataLayerVirtualLanPriorityCodePoint(match
-                    .getDataLayerVirtualLanPriorityCodePoint(), (byte) 0);
+        if ((match.getWildcards() & OFMatch.OFPFW_DL_VLAN_PCP) == 0) {
+            this.setDataLayerVirtualLanPriorityCodePoint(
+                    match.getDataLayerVirtualLanPriorityCodePoint(), (byte) 0);
         } else {
             this.dataLayerVirtualLanPriorityCodePoint = 0;
+            this.dlVlanPCPState = MatchFieldState.MATCH_ABSENT;
         }
 
         this.networkProtocolMask = 0;
         if (match.getNetworkProtocol() != 0) {
-            this.setNetworkProtocol(this.networkProtocol = match
-                    .getNetworkProtocol(), (byte) 0);
+            this.setNetworkProtocol(
+                    this.networkProtocol = match.getNetworkProtocol(), (byte) 0);
         } else {
             this.networkProtocol = 0;
             this.nwProtoState = MatchFieldState.MATCH_ABSENT;
@@ -253,8 +245,9 @@ public class V6Match extends OFMatch implements Cloneable {
 
         this.networkTypeOfServiceMask = 0;
         if (match.getNetworkTypeOfService() != 0) {
-            this.setNetworkTypeOfService(this.networkTypeOfService = match
-                    .getNetworkTypeOfService(), (byte) 0);
+            this.setNetworkTypeOfService(
+                    this.networkTypeOfService = match.getNetworkTypeOfService(),
+                    (byte) 0);
         } else {
             this.networkTypeOfService = match.getNetworkTypeOfService();
             this.nwTosState = MatchFieldState.MATCH_ABSENT;
@@ -348,13 +341,51 @@ public class V6Match extends OFMatch implements Cloneable {
         return (ipv6ext_etype_msg.array());
     }
 
-    private byte[] getIPv6ExtensionVlanIDMatchMsg(short VLAN) {
-        ByteBuffer ipv6ext_vlanid_msg = ByteBuffer.allocate(6);
+    private byte[] getVlanTCI(short dataLayerVirtualLanID,
+            byte dataLayerVirtualLanPriorityCodePoint) {
+        ByteBuffer vlan_tci = ByteBuffer.allocate(2);
+        int vlan_tci_int;
+        if (dataLayerVirtualLanID == OFP_VLAN_NONE) {
+            // Match only packets without VLAN tag.
+            vlan_tci_int = 0;
+        } else {
+             // the pcp fields have to move by 13
+            int pcp = dataLayerVirtualLanPriorityCodePoint << 13;
+            vlan_tci_int = pcp + VLAN_TCI_CFI + dataLayerVirtualLanID;
+        }
+        vlan_tci.put((byte) (vlan_tci_int >> 8)); // bits 8 to 15
+        vlan_tci.put((byte) vlan_tci_int); // bits 0 to 7
+        return vlan_tci.array();
+    }
+
+    private byte[] getIPv6ExtensionVlanTCIMatchMsg(short dataLayerVirtualLanID,
+            byte dataLayerVirtualLanPriorityCodePoint) {
+        ByteBuffer ipv6ext_vlan_tci_msg = ByteBuffer.allocate(6);
         int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
                 OF_Match_Types.MATCH_OF_VLAN_TCI.getValue(), 0, 2);
-        ipv6ext_vlanid_msg.putInt(nxm_header);
-        ipv6ext_vlanid_msg.putShort(VLAN);
-        return (ipv6ext_vlanid_msg.array());
+        ipv6ext_vlan_tci_msg.putInt(nxm_header);
+        ipv6ext_vlan_tci_msg.put(getVlanTCI(dataLayerVirtualLanID,
+                dataLayerVirtualLanPriorityCodePoint));
+        return (ipv6ext_vlan_tci_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionVlanTCIMatchWithMaskMsg(
+            short dataLayerVirtualLan,
+            byte dataLayerVirtualLanPriorityCodePoint,
+            int dataLayerVirtualLanTCIMask) {
+        ByteBuffer ipv6ext_vlan_tci_msg = ByteBuffer.allocate(8);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_VLAN_TCI.getValue(), 1, 4);
+        ipv6ext_vlan_tci_msg.putInt(nxm_header);
+        ipv6ext_vlan_tci_msg.put(getVlanTCI(dataLayerVirtualLan,
+                dataLayerVirtualLanPriorityCodePoint));
+        ipv6ext_vlan_tci_msg.put((byte) (dataLayerVirtualLanTCIMask >> 8)); // bits
+                                                                            // 8
+                                                                            // to
+                                                                            // 15
+        ipv6ext_vlan_tci_msg.put((byte) (dataLayerVirtualLanTCIMask)); // bits 0
+                                                                       // to 7
+        return (ipv6ext_vlan_tci_msg.array());
     }
 
     private byte[] getIPv6ExtensionSrcIPv6MatchMsg(byte[] srcIpv6) {
@@ -413,11 +444,10 @@ public class V6Match extends OFMatch implements Cloneable {
         ipv6ext_proto_msg.putInt(nxm_header);
         if (protocol == IPProtocols.ICMP.getValue()) {
             /*
-             * The front end  passes the same protocol type values for IPv4
-             * and IPv6 flows. For the Protocol types we allow in our GUI
-             * (ICMP, TCP, UDP), ICMP is the only one which is different for
-             * IPv6. It is 1 for v4 and 58 for v6 Therefore, we overwrite it
-             * here.
+             * The front end passes the same protocol type values for IPv4 and
+             * IPv6 flows. For the Protocol types we allow in our GUI (ICMP,
+             * TCP, UDP), ICMP is the only one which is different for IPv6. It
+             * is 1 for v4 and 58 for v6 Therefore, we overwrite it here.
              */
             protocol = IPProtocols.ICMPV6.getValue();
         }
@@ -471,27 +501,32 @@ public class V6Match extends OFMatch implements Cloneable {
     }
 
     /**
-     * Sets this (V6Match) object's member variables based on a comma-separated key=value pair similar to OFMatch's fromString.
-     * 
-     * @param match a key=value comma separated string.
+     * Sets this (V6Match) object's member variables based on a comma-separated
+     * key=value pair similar to OFMatch's fromString.
+     *
+     * @param match
+     *            a key=value comma separated string.
      */
     @Override
     public void fromString(String match) throws IllegalArgumentException {
         if (match.equals("") || match.equalsIgnoreCase("any")
-                || match.equalsIgnoreCase("all") || match.equals("[]"))
+                || match.equalsIgnoreCase("all") || match.equals("[]")) {
             match = "OFMatch[]";
+        }
         String[] tokens = match.split("[\\[,\\]]");
         String[] values;
         int initArg = 0;
-        if (tokens[0].equals("OFMatch"))
+        if (tokens[0].equals("OFMatch")) {
             initArg = 1;
+        }
         this.wildcards = OFPFW_ALL;
         int i;
         for (i = initArg; i < tokens.length; i++) {
             values = tokens[i].split("=");
-            if (values.length != 2)
+            if (values.length != 2) {
                 throw new IllegalArgumentException("Token " + tokens[i]
                         + " does not have form 'key=value' parsing " + match);
+            }
             values[0] = values[0].toLowerCase(); // try to make this case insens
             if (values[0].equals(STR_IN_PORT) || values[0].equals("input_port")) {
                 this.inputPort = U16.t(Integer.valueOf(values[1]));
@@ -511,56 +546,96 @@ public class V6Match extends OFMatch implements Cloneable {
                 this.wildcards &= ~OFPFW_DL_SRC;
             } else if (values[0].equals(STR_DL_TYPE)
                     || values[0].equals("eth_type")) {
-                if (values[1].startsWith("0x"))
+                if (values[1].startsWith("0x")) {
                     this.dataLayerType = U16.t(Integer.valueOf(values[1]
                             .replaceFirst("0x", ""), 16));
-                else
+                } else {
+
                     this.dataLayerType = U16.t(Integer.valueOf(values[1]));
+                }
                 ethTypeState = MatchFieldState.MATCH_FIELD_ONLY;
                 match_len += 6;
             } else if (values[0].equals(STR_DL_VLAN)) {
-                this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1]));
-                dlVlanState = MatchFieldState.MATCH_FIELD_ONLY;
-                match_len += 6;
+                short vlan = U16.t(Integer.valueOf(values[1]));
+                if (this.dlVlanPCPState != MatchFieldState.MATCH_ABSENT &&
+                    vlan == OFP_VLAN_NONE) {
+                    throw new IllegalArgumentException("DL_VLAN_PCP is set.");
+                }
+                this.dataLayerVirtualLan = vlan;
+                this.dlVlanIDState = MatchFieldState.MATCH_FIELD_ONLY;
+                // the variable dlVlanIDState is not really used as a flag
+                // for serializing and deserializing. Rather it is used as a
+                // flag
+                // to check if the vlan id is being set so that we can set the
+                // dlVlanTCIState appropriately.
+                if (this.dlVlanPCPState != MatchFieldState.MATCH_ABSENT) {
+                    this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY;
+                    match_len -= 2;
+                } else if (this.dataLayerVirtualLan == OFP_VLAN_NONE) {
+                    this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY;
+                    match_len += 6;
+                } else {
+                    this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                    this.dataLayerVirtualLanTCIMask = 0x1fff;
+                    match_len += 8;
+                }
+                this.wildcards &= ~OFPFW_DL_VLAN;
             } else if (values[0].equals(STR_DL_VLAN_PCP)) {
+                if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT &&
+                    this.dataLayerVirtualLan == OFP_VLAN_NONE) {
+                    throw new IllegalArgumentException
+                        ("OFP_VLAN_NONE is specified to DL_VLAN.");
+                }
                 this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short
                         .valueOf(values[1]));
+                this.dlVlanPCPState = MatchFieldState.MATCH_FIELD_ONLY;
+                // the variable dlVlanPCPState is not really used as a flag
+                // for serializing and deserializing. Rather it is used as a
+                // flag
+                // to check if the vlan pcp is being set so that we can set the
+                // dlVlanTCIState appropriately.
+                if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT) {
+                    this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY;
+                    match_len -= 2;
+                } else {
+                    this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                    this.dataLayerVirtualLanTCIMask = 0xf000;
+                    match_len += 8;
+                }
                 this.wildcards &= ~OFPFW_DL_VLAN_PCP;
             } else if (values[0].equals(STR_NW_DST)
                     || values[0].equals("ip_dst")) {
                 try {
+                    InetAddress address = null;
+                    InetAddress mask = null;
                     if (values[1].contains("/")) {
-                        String ipv6addr_wmask[] = values[1].split("/");
-                        this.nwDst = InetAddress.getByName(ipv6addr_wmask[0]);
-                        this.dstIPv6SubnetMaskbits = Short
-                                .valueOf(ipv6addr_wmask[1]);
-                        nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
-                        match_len += 36;
+                        String addressString[] = values[1].split("/");
+                        address = InetAddress.getByName(addressString[0]);
+                        int masklen = Integer.valueOf(addressString[1]);
+                        mask = NetUtils.getInetNetworkMask(masklen, address instanceof Inet6Address);
                     } else {
-                        this.nwDst = InetAddress.getByName(values[1]);
-                        nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
-                        match_len += 20;
+                        address = InetAddress.getByName(values[1]);
                     }
+                    this.setNetworkDestination(address, mask);
                 } catch (UnknownHostException e) {
-                    logger.error("",e);
+                    logger.error("", e);
                 }
             } else if (values[0].equals(STR_NW_SRC)
                     || values[0].equals("ip_src")) {
                 try {
+                    InetAddress address = null;
+                    InetAddress mask = null;
                     if (values[1].contains("/")) {
-                        String ipv6addr_wmask[] = values[1].split("/");
-                        this.nwSrc = InetAddress.getByName(ipv6addr_wmask[0]);
-                        this.srcIPv6SubnetMaskbits = Short
-                                .valueOf(ipv6addr_wmask[1]);
-                        nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
-                        match_len += 36;
+                        String addressString[] = values[1].split("/");
+                        address = InetAddress.getByName(addressString[0]);
+                        int masklen = Integer.valueOf(addressString[1]);
+                        mask = NetUtils.getInetNetworkMask(masklen, address instanceof Inet6Address);
                     } else {
-                        this.nwSrc = InetAddress.getByName(values[1]);
-                        nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
-                        match_len += 20;
+                        address = InetAddress.getByName(values[1]);
                     }
+                    this.setNetworkSource(address, mask);
                 } catch (UnknownHostException e) {
-                    logger.error("",e);
+                    logger.error("", e);
                 }
             } else if (values[0].equals(STR_NW_PROTO)) {
                 this.networkProtocol = U8.t(Short.valueOf(values[1]));
@@ -583,14 +658,15 @@ public class V6Match extends OFMatch implements Cloneable {
                 this.transportSource = U16.t(Integer.valueOf(values[1]));
                 tpSrcState = MatchFieldState.MATCH_FIELD_ONLY;
                 match_len += 6;
-            } else
+            } else {
                 throw new IllegalArgumentException("unknown token " + tokens[i]
                         + " parsing " + match);
+            }
         }
 
         /*
-         * In a V6 extension message action list should be preceded by a padding of 0 to
-         * 7 bytes based upon following formula.
+         * In a V6 extension message action list should be preceded by a padding
+         * of 0 to 7 bytes based upon following formula.
          */
 
         pad_size = (short) (((match_len + 7) / 8) * 8 - match_len);
@@ -620,9 +696,17 @@ public class V6Match extends OFMatch implements Cloneable {
             byte[] ipv6ext_srcmac_msg = getIPv6ExtensionSrcMacMatchMsg(this.dataLayerSource);
             data.put(ipv6ext_srcmac_msg);
         }
-        if (dlVlanState == MatchFieldState.MATCH_FIELD_ONLY) {
-            byte[] ipv6ext_vlan_id_msg = getIPv6ExtensionVlanIDMatchMsg(this.dataLayerVirtualLan);
-            data.put(ipv6ext_vlan_id_msg);
+        if (dlVlanTCIState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_vlan_tci_msg = getIPv6ExtensionVlanTCIMatchMsg(
+                    this.dataLayerVirtualLan,
+                    this.dataLayerVirtualLanPriorityCodePoint);
+            data.put(ipv6ext_vlan_tci_msg);
+        } else if (dlVlanTCIState == MatchFieldState.MATCH_FIELD_WITH_MASK) {
+            byte[] ipv6ext_vlan_tci_msg_with_mask = getIPv6ExtensionVlanTCIMatchWithMaskMsg(
+                    this.dataLayerVirtualLan,
+                    this.dataLayerVirtualLanPriorityCodePoint,
+                    this.dataLayerVirtualLanTCIMask);
+            data.put(ipv6ext_vlan_tci_msg_with_mask);
         }
         if (nwSrcState == MatchFieldState.MATCH_FIELD_ONLY) {
             byte[] ipv6ext_src_ipv6_msg = getIPv6ExtensionSrcIPv6MatchMsg(this.nwSrc
@@ -678,11 +762,12 @@ public class V6Match extends OFMatch implements Cloneable {
     }
 
     private void readInPort(ByteBuffer data, int nxmLen, boolean hasMask) {
-        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) {
             /*
              * mask is not allowed for inport port
              */
             return;
+        }
         super.setInputPort(data.getShort());
         this.inputPortState = MatchFieldState.MATCH_FIELD_ONLY;
         this.wildcards ^= (1 << 0); // Sync with 0F 1.0 Match
@@ -692,9 +777,9 @@ public class V6Match extends OFMatch implements Cloneable {
     private void readDataLinkDestination(ByteBuffer data, int nxmLen,
             boolean hasMask) {
         if (hasMask) {
-            if ((nxmLen != 2 * 6) || (data.remaining() < 2 * 6))
+            if ((nxmLen != 2 * 6) || (data.remaining() < 2 * 6)) {
                 return;
-            else {
+            else {
                 byte[] bytes = new byte[6];
                 data.get(bytes);
                 super.setDataLayerDestination(bytes);
@@ -704,9 +789,9 @@ public class V6Match extends OFMatch implements Cloneable {
                 this.match_len += 16;
             }
         } else {
-            if ((nxmLen != 6) || (data.remaining() < 6))
+            if ((nxmLen != 6) || (data.remaining() < 6)) {
                 return;
-            else {
+            else {
                 byte[] bytes = new byte[6];
                 data.get(bytes);
                 super.setDataLayerDestination(bytes);
@@ -721,8 +806,9 @@ public class V6Match extends OFMatch implements Cloneable {
         /*
          * mask is not allowed in data link source
          */
-        if ((nxmLen != 6) || (data.remaining() < 6) || (hasMask))
+        if ((nxmLen != 6) || (data.remaining() < 6) || (hasMask)) {
             return;
+        }
         byte[] bytes = new byte[6];
         data.get(bytes);
         super.setDataLayerSource(bytes);
@@ -735,49 +821,95 @@ public class V6Match extends OFMatch implements Cloneable {
         /*
          * mask is not allowed in ethertype
          */
-        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) {
             return;
+        }
         super.setDataLayerType(data.getShort());
         this.ethTypeState = MatchFieldState.MATCH_FIELD_ONLY;
         this.wildcards ^= (1 << 4); // Sync with 0F 1.0 Match
         this.match_len += 6;
     }
 
+    private short getVlanID(byte firstByte, byte secondByte) {
+        short vlan_id_mask_firstByte = 0x0f;// this is the mask for the first
+                                            // byte
+        short vlan_id_mask_secondByte = 0xff;// this is the mask for the second
+                                             // byte
+        int vlanPart1 = (firstByte & vlan_id_mask_firstByte) << 8;
+        int vlanPart2 = secondByte & vlan_id_mask_secondByte;
+        return (short) (vlanPart1 + vlanPart2);
+    }
+
+    private byte getVlanPCP(byte pcpByte) {
+        short vlan_pcp_mask = 0xe0;// this is the vlan pcp mask
+        int pcp_int = pcpByte & vlan_pcp_mask;
+        return (byte) (pcp_int >> 5);
+    }
+
     private void readVlanTci(ByteBuffer data, int nxmLen, boolean hasMask) {
-        short vlan_mask = 0xfff;
         if (hasMask) {
-            if ((nxmLen != 2 * 2) || (data.remaining() < 2 * 2))
+            if ((nxmLen != 2 * 2) || (data.remaining() < 2 * 2)) {
                 return;
+            }
             else {
-                short vlan = data.getShort();
-                vlan &= vlan_mask;
-                super.setDataLayerVirtualLan(vlan);
-                this.dataLayerVirtualLanMask = data.getShort();
-                this.dlVlanState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                byte firstByte = data.get();
+                byte secondByte = data.get();
+                this.dataLayerVirtualLanTCIMask = data.getShort() & 0xffff; // we
+                                                                            // need
+                                                                            // the
+                                                                            // last
+                                                                            // 16
+                                                                            // bits
+                // check the mask now
+                if ((this.dataLayerVirtualLanTCIMask & 0x0fff) != 0) {
+                    // if its a vlan id mask
+                    // extract the vlan id
+                    super.setDataLayerVirtualLan(getVlanID(firstByte,
+                            secondByte));
+                    this.wildcards ^= (1 << 1); // Sync with 0F 1.0 Match
+                }
+                if ((this.dataLayerVirtualLanTCIMask & 0xe000) != 0) {
+                    // else if its a vlan pcp mask
+                    // extract the vlan pcp
+                    super.setDataLayerVirtualLanPriorityCodePoint(getVlanPCP(firstByte));
+                    this.wildcards ^= (1 << 20);
+                }
+                this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK;
                 this.match_len += 8;
-                this.wildcards ^= (1 << 20);
             }
         } else {
-            if ((nxmLen != 2) || (data.remaining() < 2))
+            if ((nxmLen != 2) || (data.remaining() < 2)) {
                 return;
+            }
             else {
-                short vlan = data.getShort();
-                vlan &= vlan_mask;
-                super.setDataLayerVirtualLan(vlan);
-                this.dlVlanState = MatchFieldState.MATCH_FIELD_ONLY;
+                // get the vlan pcp
+                byte firstByte = data.get();
+                byte secondByte = data.get();
+                if (firstByte == 0 && secondByte == 0) {
+                    // Match only packets without VLAN tag.
+                    setDataLayerVirtualLan(OFP_VLAN_NONE);
+                } else if (((firstByte << 8) & VLAN_TCI_CFI) == 0) {
+                    // Ignore invalid TCI field.
+                    return;
+                } else {
+                    super.setDataLayerVirtualLanPriorityCodePoint(getVlanPCP(firstByte));
+                    super.setDataLayerVirtualLan(getVlanID(firstByte, secondByte));
+                    this.wildcards ^= (1 << 20);
+                }
+                this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY;
                 this.match_len += 6;
+                this.wildcards ^= (1 << 1); // Sync with 0F 1.0 Match
             }
         }
-
-        this.wildcards ^= (1 << 1); // Sync with 0F 1.0 Match
     }
 
     private void readIpTos(ByteBuffer data, int nxmLen, boolean hasMask) {
         /*
          * mask is not allowed in IP TOS
          */
-        if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask))
+        if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask)) {
             return;
+        }
         super.setNetworkTypeOfService(data.get());
         this.nwTosState = MatchFieldState.MATCH_FIELD_ONLY;
         this.match_len += 5;
@@ -788,8 +920,9 @@ public class V6Match extends OFMatch implements Cloneable {
         /*
          * mask is not allowed in IP protocol
          */
-        if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask))
+        if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask)) {
             return;
+        }
         super.setNetworkProtocol(data.get());
         this.nwProtoState = MatchFieldState.MATCH_FIELD_ONLY;
         this.match_len += 5;
@@ -798,87 +931,70 @@ public class V6Match extends OFMatch implements Cloneable {
 
     private void readIpv4Src(ByteBuffer data, int nxmLen, boolean hasMask) {
         if (hasMask) {
-            if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4))
+            if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4)) {
                 return;
-            else {
+            else {
                 byte[] sbytes = new byte[4];
                 data.get(sbytes);
-                try {
-                    this.nwSrc = InetAddress.getByAddress(sbytes);
-                } catch (UnknownHostException e) {
-                    return;
-                }
+                // For compatibility, let's set the IPv4 in the parent OFMatch
+                int address = NetUtils.byteArray4ToInt(sbytes);
+                super.setNetworkSource(address);
                 byte[] mbytes = new byte[4];
                 data.get(mbytes);
-                try {
-                    this.networkSourceMask = InetAddress.getByAddress(mbytes);
-                } catch (UnknownHostException e) {
-                    return;
-                }
                 this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
                 this.match_len += 12;
                 int prefixlen = getNetworkMaskPrefixLength(mbytes);
                 this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 Match
                 this.wildcards |= ((32 - prefixlen) << 8); // Sync with 0F 1.0 Match
-
             }
         } else {
-            if ((nxmLen != 4) || (data.remaining() < 4))
+            if ((nxmLen != 4) || (data.remaining() < 4)) {
                 return;
-            else {
+            else {
                 byte[] sbytes = new byte[4];
                 data.get(sbytes);
-                try {
-                    this.nwSrc = InetAddress.getByAddress(sbytes);
-                } catch (UnknownHostException e) {
-                    return;
-                }
+                // For compatibility, let's also set the IPv4 in the parent OFMatch
+                int address = NetUtils.byteArray4ToInt(sbytes);
+                super.setNetworkSource(address);
                 this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
                 this.match_len += 8;
-                this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 Match
+                this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0
+                                                         // Match
             }
         }
     }
 
     private void readIpv4Dst(ByteBuffer data, int nxmLen, boolean hasMask) {
         if (hasMask) {
-            if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4))
+            if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4)) {
                 return;
-            else {
+            else {
                 byte[] dbytes = new byte[4];
                 data.get(dbytes);
-                try {
-                    this.nwDst = InetAddress.getByAddress(dbytes);
-                } catch (UnknownHostException e) {
-                    return;
-                }
+                // For compatibility, let's also set the IPv4 in the parent OFMatch
+                int address = NetUtils.byteArray4ToInt(dbytes);
+                super.setNetworkDestination(address);
                 byte[] mbytes = new byte[4];
                 data.get(mbytes);
-                try {
-                    this.networkDestinationMask = InetAddress
-                            .getByAddress(mbytes);
-                } catch (UnknownHostException e) {
-                    return;
-                }
                 this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
                 this.match_len += 12;
                 int prefixlen = getNetworkMaskPrefixLength(mbytes);
-                this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 Match
-                this.wildcards |= ((32 - prefixlen) << 14); // Sync with 0F 1.0 Match
+                this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0
+                                                          // Match
+                this.wildcards |= ((32 - prefixlen) << 14); // Sync with 0F 1.0
+                                                            // Match
             }
         } else {
-            if ((nxmLen != 4) || (data.remaining() < 4))
+            if ((nxmLen != 4) || (data.remaining() < 4)) {
                 return;
-            else {
+            else {
                 byte[] dbytes = new byte[4];
                 data.get(dbytes);
-                try {
-                    this.nwDst = InetAddress.getByAddress(dbytes);
-                } catch (UnknownHostException e) {
-                    return;
-                }
+                int address = NetUtils.byteArray4ToInt(dbytes);
+                super.setNetworkDestination(address);
                 this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
-                this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 Match
+                this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0
+                                                          // Match
                 this.match_len += 8;
             }
         }
@@ -888,8 +1004,9 @@ public class V6Match extends OFMatch implements Cloneable {
         /*
          * mask is not allowed in TCP SRC
          */
-        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) {
             return;
+        }
         super.setTransportSource(data.getShort());
         this.tpSrcState = MatchFieldState.MATCH_FIELD_ONLY;
         this.match_len += 6;
@@ -900,8 +1017,9 @@ public class V6Match extends OFMatch implements Cloneable {
         /*
          * mask is not allowed in TCP DST
          */
-        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) {
             return;
+        }
         super.setTransportDestination(data.getShort());
         this.tpDstState = MatchFieldState.MATCH_FIELD_ONLY;
         this.match_len += 6;
@@ -912,8 +1030,9 @@ public class V6Match extends OFMatch implements Cloneable {
         /*
          * mask is not allowed in UDP SRC
          */
-        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) {
             return;
+        }
         super.setTransportSource(data.getShort());
         this.tpSrcState = MatchFieldState.MATCH_FIELD_ONLY;
         this.match_len += 6;
@@ -924,8 +1043,9 @@ public class V6Match extends OFMatch implements Cloneable {
         /*
          * mask is not allowed in UDP DST
          */
-        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) {
             return;
+        }
         super.setTransportDestination(data.getShort());
         this.tpDstState = MatchFieldState.MATCH_FIELD_ONLY;
         this.match_len += 6;
@@ -934,34 +1054,30 @@ public class V6Match extends OFMatch implements Cloneable {
 
     private void readIpv6Src(ByteBuffer data, int nxmLen, boolean hasMask) {
         if (hasMask) {
-            if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16))
+            if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16)) {
                 return;
-            else {
+            else {
                 byte[] sbytes = new byte[16];
                 data.get(sbytes);
                 try {
-                    this.nwSrc = InetAddress.getByAddress(sbytes);
+                    this.nwSrc = (Inet6Address) InetAddress.getByAddress(sbytes);
                 } catch (UnknownHostException e) {
                     return;
                 }
                 byte[] mbytes = new byte[16];
                 data.get(mbytes);
-                try {
-                    this.networkSourceMask = InetAddress.getByAddress(mbytes);
-                } catch (UnknownHostException e) {
-                    return;
-                }
+                this.srcIPv6SubnetMaskbits = (short)NetUtils.getSubnetMaskLength(mbytes);
                 this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
                 this.match_len += 36;
             }
         } else {
-            if ((nxmLen != 16) || (data.remaining() < 16))
+            if ((nxmLen != 16) || (data.remaining() < 16)) {
                 return;
-            else {
+            else {
                 byte[] sbytes = new byte[16];
                 data.get(sbytes);
                 try {
-                    this.nwSrc = InetAddress.getByAddress(sbytes);
+                    this.nwSrc = (Inet6Address) InetAddress.getByAddress(sbytes);
                 } catch (UnknownHostException e) {
                     return;
                 }
@@ -973,35 +1089,30 @@ public class V6Match extends OFMatch implements Cloneable {
 
     private void readIpv6Dst(ByteBuffer data, int nxmLen, boolean hasMask) {
         if (hasMask) {
-            if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16))
+            if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16)) {
                 return;
-            else {
+            else {
                 byte[] dbytes = new byte[16];
                 data.get(dbytes);
                 try {
-                    this.nwDst = InetAddress.getByAddress(dbytes);
+                    this.nwDst = (Inet6Address) InetAddress.getByAddress(dbytes);
                 } catch (UnknownHostException e) {
                     return;
                 }
                 byte[] mbytes = new byte[16];
                 data.get(mbytes);
-                try {
-                    this.networkDestinationMask = InetAddress
-                            .getByAddress(mbytes);
-                } catch (UnknownHostException e) {
-                    return;
-                }
+                this.dstIPv6SubnetMaskbits = (short)NetUtils.getSubnetMaskLength(mbytes);
                 this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
                 this.match_len += 36;
             }
         } else {
-            if ((nxmLen != 16) || (data.remaining() < 16))
+            if ((nxmLen != 16) || (data.remaining() < 16)) {
                 return;
-            else {
+            else {
                 byte[] dbytes = new byte[16];
                 data.get(dbytes);
                 try {
-                    this.nwDst = InetAddress.getByAddress(dbytes);
+                    this.nwDst = (Inet6Address) InetAddress.getByAddress(dbytes);
                 } catch (UnknownHostException e) {
                     return;
                 }
@@ -1013,13 +1124,34 @@ public class V6Match extends OFMatch implements Cloneable {
 
     @Override
     public String toString() {
-        return "V6Match[" + ReflectionToStringBuilder.toString(this) + "]";
+        return "V6Match [nwSrc=" + nwSrc + ", nwDst=" + nwDst
+                + ", inputPortMask=" + inputPortMask + ", dataLayerSourceMask="
+                + HexEncode.bytesToHexStringFormat(dataLayerSourceMask)
+                + ", dataLayerDestinationMask="
+                + HexEncode.bytesToHexStringFormat(dataLayerDestinationMask)
+                + ", dataLayerVirtualLanTCIMask=" + dataLayerVirtualLanTCIMask
+                + ", dataLayerTypeMask=" + dataLayerTypeMask
+                + ", networkTypeOfServiceMask=" + networkTypeOfServiceMask
+                + ", networkProtocolMask=" + networkProtocolMask
+                + ", transportSourceMask=" + transportSourceMask
+                + ", transportDestinationMask=" + transportDestinationMask
+                + ", srcIPv6SubnetMaskbits=" + srcIPv6SubnetMaskbits
+                + ", dstIPv6SubnetMaskbits=" + dstIPv6SubnetMaskbits
+                + ", inputPortState=" + inputPortState + ", dlSourceState="
+                + dlSourceState + ", dlDestState=" + dlDestState
+                + ", dlVlanTCIState=" + dlVlanTCIState + ", ethTypeState="
+                + ethTypeState + ", nwTosState=" + nwTosState
+                + ", nwProtoState=" + nwProtoState + ", nwSrcState="
+                + nwSrcState + ", nwDstState=" + nwDstState + ", tpSrcState="
+                + tpSrcState + ", tpDstState=" + tpDstState + ", match_len="
+                + match_len + ", pad_size=" + pad_size + "]";
     }
 
     /**
      * Read the data corresponding to the match field (received from the wire)
-     * Input: data: match field(s). Since match field is of variable length, the whole data that are passed in
-     * are assumed to fem0tbd.be the match fields.
+     * Input: data: match field(s). Since match field is of variable length, the
+     * whole data that are passed in are assumed to fem0tbd.be the match fields.
+     *
      * @param data
      */
     @Override
@@ -1035,8 +1167,8 @@ public class V6Match extends OFMatch implements Cloneable {
                 /*
                  * at least 4 bytes for each match header
                  */
-                logger.error("Invalid Vendor Extension Header. Size {}", data
-                        .remaining());
+                logger.error("Invalid Vendor Extension Header. Size {}",
+                        data.remaining());
                 return;
             }
             /*
@@ -1112,15 +1244,13 @@ public class V6Match extends OFMatch implements Cloneable {
         // Sync with 0F 1.0 Match
         if (super.getDataLayerType() == 0x800) {
             if (((this.wildcards >> 8) & 0x3f) == 0x3f) {
-                //ipv4 src processing
+                // ipv4 src processing
                 this.wildcards ^= (((1 << 5) - 1) << 8);
             }
             if (((this.wildcards >> 14) & 0x3f) == 0x3f) {
-                //ipv4 dest processing
+                // ipv4 dest processing
                 this.wildcards ^= (((1 << 5) - 1) << 14);
             }
-        } else {
-            this.wildcards = 0;
         }
     }
 
@@ -1130,10 +1260,10 @@ public class V6Match extends OFMatch implements Cloneable {
         V6Match ret = (V6Match) super.clone();
         try {
             if (this.nwSrc != null) {
-                ret.nwSrc = InetAddress.getByAddress(this.nwSrc.getAddress());
+                ret.nwSrc = (Inet6Address) InetAddress.getByAddress(this.nwSrc.getAddress());
             }
             if (this.nwDst != null) {
-                ret.nwDst = InetAddress.getByAddress(this.nwDst.getAddress());
+                ret.nwDst = (Inet6Address) InetAddress.getByAddress(this.nwDst.getAddress());
             }
             return ret;
         } catch (UnknownHostException e) {
@@ -1146,38 +1276,16 @@ public class V6Match extends OFMatch implements Cloneable {
      *
      * @return
      */
-
-    public InetAddress getNetworkDest() {
+    public Inet6Address getNetworkDest() {
         return this.nwDst;
     }
 
-    /**
-     * Get nw_src
-     *
-     * @return
-     */
-
-    public void setNetworkSrc(InetAddress address) {
-        nwSrc = address;
-    }
-
-    /**
-     * Set nw_dst
-     *
-     * @return
-     */
-
-    public void setNetworkDest(InetAddress address) {
-        nwDst = address;
-    }
-
     /**
      * Set nw_src
      *
      * @return
      */
-
-    public InetAddress getNetworkSrc() {
+    public Inet6Address getNetworkSrc() {
         return this.nwSrc;
     }
 
@@ -1241,24 +1349,67 @@ public class V6Match extends OFMatch implements Cloneable {
         }
     }
 
-    public short getDataLayerVirtualLanMask() {
-        return dataLayerVirtualLanMask;
-    }
-
+    /**
+     * Set a value to VLAN ID match field.
+     *
+     * @param vlan  A value to match for VLAN ID.
+     * @param mask  A bitmask for VLAN ID.
+     */
     public void setDataLayerVirtualLan(short vlan, short mask) {
+        if (vlan == OFP_VLAN_NONE
+                && this.dlVlanIDState != MatchFieldState.MATCH_ABSENT) {
+            throw new IllegalStateException
+                ("DL_VLAN_PCP is set.");
+        }
+
+        // mask is ignored as the code sets the appropriate mask
         super.dataLayerVirtualLan = vlan;
-        if (mask == 0) {
-            this.dlVlanState = MatchFieldState.MATCH_FIELD_ONLY;
-            this.match_len += 6;
+        this.dlVlanIDState = MatchFieldState.MATCH_FIELD_ONLY;
+        // the variable dlVlanIDState is not really used as a flag
+        // for serializing and deserializing. Rather it is used as a flag
+        // to check if the vlan id is being set so that we can set the
+        // dlVlanTCIState appropriately.
+        if (this.dlVlanPCPState != MatchFieldState.MATCH_ABSENT) {
+            this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY;
+            match_len -= 2;
+        } else if (this.dataLayerVirtualLan == OFP_VLAN_NONE) {
+            this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY;
+            match_len += 6;
         } else {
-            this.dataLayerVirtualLanMask = mask;
-            this.dlVlanState = MatchFieldState.MATCH_FIELD_WITH_MASK;
-            this.match_len += 8;
+            this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+            this.dataLayerVirtualLanTCIMask = 0x1fff;
+            match_len += 8;
         }
     }
 
+    /**
+     * Set a value to VLAN PCP match field.
+     *
+     * @param pcp  A value to match for VLAN PCP.
+     * @param mask  A bitmask for VLAN PCP.
+     */
     public void setDataLayerVirtualLanPriorityCodePoint(byte pcp, byte mask) {
+        if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT
+                && this.dataLayerVirtualLan == OFP_VLAN_NONE) {
+            throw new IllegalStateException
+                ("OFP_VLAN_NONE is specified to DL_VLAN.");
+        }
+
+        // mask is ignored as the code sets the appropriate mask
         super.dataLayerVirtualLanPriorityCodePoint = pcp;
+        this.dlVlanPCPState = MatchFieldState.MATCH_FIELD_ONLY;
+        // the variable dlVlanPCPState is not really used as a flag
+        // for serializing and deserializing. Rather it is used as a flag
+        // to check if the vlan pcp is being set so that we can set the
+        // dlVlanTCIState appropriately.
+        if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT) {
+            this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY;
+            match_len -= 2;
+        } else {
+            this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+            this.dataLayerVirtualLanTCIMask = 0xf000;
+            match_len += 8;
+        }
     }
 
     public void setDataLayerType(short ethType, short mask) {
@@ -1282,35 +1433,63 @@ public class V6Match extends OFMatch implements Cloneable {
         this.match_len += 5;
     }
 
-    public InetAddress getNetworkSourceMask() {
-        return networkSourceMask;
+    public Inet6Address getNetworkSourceMask() {
+        return (this.nwSrcState == MatchFieldState.MATCH_FIELD_WITH_MASK) ? (Inet6Address) NetUtils.getInetNetworkMask(
+                this.srcIPv6SubnetMaskbits, true) : null;
     }
 
     public void setNetworkSource(InetAddress address, InetAddress mask) {
-        this.nwSrc = address;
-        if (mask == null) {
-            this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
-            this.match_len += (address instanceof Inet6Address) ? 20 : 8;
+        if (address instanceof Inet6Address) {
+            this.nwSrc = (Inet6Address) address;
+            if (mask == null) {
+                this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += (address instanceof Inet6Address) ? 20 : 8;
+            } else {
+                this.srcIPv6SubnetMaskbits = (short)NetUtils.getSubnetMaskLength(mask);
+                this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += (address instanceof Inet6Address) ? 36 : 12;
+            }
         } else {
-            this.networkSourceMask = mask;
-            this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
-            this.match_len += (address instanceof Inet6Address) ? 36 : 12;
+            super.setNetworkSource(NetUtils.byteArray4ToInt(address.getAddress()));
+            this.wildcards ^= (((1 << 6) - 1) << 8);
+            if (mask == null) {
+                this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += 8;
+            } else {
+                this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += 12;
+                this.wildcards |= ((32 - NetUtils.getSubnetMaskLength(mask)) << 8);
+            }
         }
     }
 
-    public InetAddress getNetworkDestinationMask() {
-        return networkDestinationMask;
+    public Inet6Address getNetworkDestinationMask() {
+        return (this.nwDstState == MatchFieldState.MATCH_FIELD_WITH_MASK) ? (Inet6Address) NetUtils.getInetNetworkMask(
+                this.dstIPv6SubnetMaskbits, true) : null;
     }
 
     public void setNetworkDestination(InetAddress address, InetAddress mask) {
-        this.nwDst = address;
-        if (mask == null) {
-            this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
-            this.match_len += (address instanceof Inet6Address) ? 20 : 8;
+        if (address instanceof Inet6Address) {
+            this.nwDst = (Inet6Address) address;
+            if (mask == null) {
+                this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += (address instanceof Inet6Address) ? 20 : 8;
+            } else {
+                this.dstIPv6SubnetMaskbits = (short)NetUtils.getSubnetMaskLength(mask);
+                this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += (address instanceof Inet6Address) ? 36 : 12;
+            }
         } else {
-            this.networkDestinationMask = mask;
-            this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
-            this.match_len += (address instanceof Inet6Address) ? 36 : 12;
+            this.setNetworkDestination(NetUtils.byteArray4ToInt(address.getAddress()));
+            this.wildcards ^= (((1 << 6) - 1) << 14);
+            if (mask == null) {
+                this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += 8;
+            } else {
+                this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += 12;
+                this.wildcards |= ((32 - NetUtils.getSubnetMaskLength(mask)) << 14);
+            }
         }
     }
 
@@ -1348,4 +1527,146 @@ public class V6Match extends OFMatch implements Cloneable {
         }
         return nbytes;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(dataLayerDestinationMask);
+        result = prime * result + Arrays.hashCode(dataLayerSourceMask);
+        result = prime * result + dataLayerTypeMask;
+        result = prime * result + dataLayerVirtualLanTCIMask;
+        result = prime * result
+                + ((dlDestState == null) ? 0 : dlDestState.hashCode());
+        result = prime * result
+                + ((dlSourceState == null) ? 0 : dlSourceState.hashCode());
+        result = prime * result
+                + ((dlVlanTCIState == null) ? 0 : dlVlanTCIState.hashCode());
+        result = prime * result + dstIPv6SubnetMaskbits;
+        result = prime * result
+                + ((ethTypeState == null) ? 0 : ethTypeState.hashCode());
+        result = prime * result + inputPortMask;
+        result = prime * result
+                + ((inputPortState == null) ? 0 : inputPortState.hashCode());
+        result = prime * result + match_len;
+        result = prime * result + networkProtocolMask;
+        result = prime * result + networkTypeOfServiceMask;
+        result = prime * result + ((nwDst == null) ? 0 : nwDst.hashCode());
+        result = prime * result
+                + ((nwDstState == null) ? 0 : nwDstState.hashCode());
+        result = prime * result
+                + ((nwProtoState == null) ? 0 : nwProtoState.hashCode());
+        result = prime * result + ((nwSrc == null) ? 0 : nwSrc.hashCode());
+        result = prime * result
+                + ((nwSrcState == null) ? 0 : nwSrcState.hashCode());
+        result = prime * result
+                + ((nwTosState == null) ? 0 : nwTosState.hashCode());
+        result = prime * result + pad_size;
+        result = prime * result + srcIPv6SubnetMaskbits;
+        result = prime * result
+                + ((tpDstState == null) ? 0 : tpDstState.hashCode());
+        result = prime * result
+                + ((tpSrcState == null) ? 0 : tpSrcState.hashCode());
+        result = prime * result + transportDestinationMask;
+        result = prime * result + transportSourceMask;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        V6Match other = (V6Match) obj;
+        if (!Arrays.equals(dataLayerDestinationMask, other.dataLayerDestinationMask)) {
+            return false;
+        }
+        if (!Arrays.equals(dataLayerSourceMask, other.dataLayerSourceMask)) {
+            return false;
+        }
+        if (dataLayerTypeMask != other.dataLayerTypeMask) {
+            return false;
+        }
+        if (dataLayerVirtualLanTCIMask != other.dataLayerVirtualLanTCIMask) {
+            return false;
+        }
+        if (dlVlanTCIState != other.dlVlanTCIState) {
+            return false;
+        }
+        if (dlSourceState != other.dlSourceState) {
+            return false;
+        }
+        if (dstIPv6SubnetMaskbits != other.dstIPv6SubnetMaskbits) {
+            return false;
+        }
+        if (ethTypeState != other.ethTypeState) {
+            return false;
+        }
+        if (inputPortMask != other.inputPortMask) {
+            return false;
+        }
+        if (inputPortState != other.inputPortState) {
+            return false;
+        }
+        if (match_len != other.match_len) {
+            return false;
+        }
+        if (networkProtocolMask != other.networkProtocolMask) {
+            return false;
+        }
+        if (networkTypeOfServiceMask != other.networkTypeOfServiceMask) {
+            return false;
+        }
+        if (nwDst == null) {
+            if (other.nwDst != null) {
+                return false;
+            }
+        } else if (!nwDst.equals(other.nwDst)) {
+            return false;
+        }
+        if (nwDstState != other.nwDstState) {
+            return false;
+        }
+        if (nwProtoState != other.nwProtoState) {
+            return false;
+        }
+        if (nwSrc == null) {
+            if (other.nwSrc != null) {
+                return false;
+            }
+        } else if (!nwSrc.equals(other.nwSrc)) {
+            return false;
+        }
+        if (nwSrcState != other.nwSrcState) {
+            return false;
+        }
+        if (nwTosState != other.nwTosState) {
+            return false;
+        }
+        if (pad_size != other.pad_size) {
+            return false;
+        }
+        if (srcIPv6SubnetMaskbits != other.srcIPv6SubnetMaskbits) {
+            return false;
+        }
+        if (tpDstState != other.tpDstState) {
+            return false;
+        }
+        if (tpSrcState != other.tpSrcState) {
+            return false;
+        }
+        if (transportDestinationMask != other.transportDestinationMask) {
+            return false;
+        }
+        if (transportSourceMask != other.transportSourceMask) {
+            return false;
+        }
+        return true;
+    }
 }