Fix IPv6 + subnet flow installation 25/625/1
authorAlessandro Boch <aboch@cisco.com>
Mon, 22 Jul 2013 21:29:03 +0000 (14:29 -0700)
committerAlessandro Boch <aboch@cisco.com>
Tue, 23 Jul 2013 02:50:59 +0000 (19:50 -0700)
    ISSUE: Flows matching on IPv6 packets are not installed when a mask is specified
    CHANGE:
    - Set the proper field in V6Match for subnets
    - Cleanup V6Match to make use of parent OFMatch fields for IPv4 matches
    - Fix subnet methods in NetUtils
    - Fix MatchType and MatchField to consider the network prefix address when
      checking equality and building hashcode for a Match on NW_SRC and NW_DST

Signed-off-by: Alessandro Boch <aboch@cisco.com>
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java
opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/utils/NetUtilsTest.java

index 8d3a1be..756a689 100644 (file)
@@ -51,6 +51,7 @@ import org.openflow.protocol.OFPacketOut;
 import org.openflow.protocol.OFPort;
 import org.openflow.protocol.OFVendor;
 import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionDataLayer;
 import org.openflow.protocol.action.OFActionDataLayerDestination;
 import org.openflow.protocol.action.OFActionDataLayerSource;
 import org.openflow.protocol.action.OFActionNetworkLayerAddress;
@@ -196,35 +197,23 @@ public class FlowConverter {
                 }
             }
             if (match.isPresent(MatchType.NW_SRC)) {
-                InetAddress address = (InetAddress) match.getField(
-                        MatchType.NW_SRC).getValue();
-                InetAddress mask = (InetAddress) match.getField(
-                        MatchType.NW_SRC).getMask();
+                InetAddress address = (InetAddress) match.getField(MatchType.NW_SRC).getValue();
+                InetAddress mask = (InetAddress) match.getField(MatchType.NW_SRC).getMask();
                 if (!isIPv6) {
-                    ofMatch.setNetworkSource(NetUtils.byteArray4ToInt(address
-                            .getAddress()));
-                    int maskLength = NetUtils
-                            .getSubnetMaskLength((mask == null) ? null : mask
-                                    .getAddress());
-                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_SRC_MASK)
-                            | (maskLength << OFMatch.OFPFW_NW_SRC_SHIFT);
+                    ofMatch.setNetworkSource(NetUtils.byteArray4ToInt(address.getAddress()));
+                    int maskLength = (mask == null) ? 32 : NetUtils.getSubnetMaskLength(mask);
+                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_SRC_MASK) | ((32 - maskLength) << OFMatch.OFPFW_NW_SRC_SHIFT);
                 } else {
                     ((V6Match) ofMatch).setNetworkSource(address, mask);
                 }
             }
             if (match.isPresent(MatchType.NW_DST)) {
-                InetAddress address = (InetAddress) match.getField(
-                        MatchType.NW_DST).getValue();
-                InetAddress mask = (InetAddress) match.getField(
-                        MatchType.NW_DST).getMask();
+                InetAddress address = (InetAddress) match.getField(MatchType.NW_DST).getValue();
+                InetAddress mask = (InetAddress) match.getField(MatchType.NW_DST).getMask();
                 if (!isIPv6) {
-                    ofMatch.setNetworkDestination(NetUtils
-                            .byteArray4ToInt(address.getAddress()));
-                    int maskLength = NetUtils
-                            .getSubnetMaskLength((mask == null) ? null : mask
-                                    .getAddress());
-                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_DST_MASK)
-                            | (maskLength << OFMatch.OFPFW_NW_DST_SHIFT);
+                    ofMatch.setNetworkDestination(NetUtils.byteArray4ToInt(address.getAddress()));
+                    int maskLength = (mask == null) ? 32 : NetUtils.getSubnetMaskLength(mask);
+                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_DST_MASK) | ((32 - maskLength) << OFMatch.OFPFW_NW_DST_SHIFT);
                 } else {
                     ((V6Match) ofMatch).setNetworkDestination(address, mask);
                 }
@@ -354,7 +343,7 @@ public class FlowConverter {
                     OFActionDataLayerSource ofAction = new OFActionDataLayerSource();
                     ofAction.setDataLayerAddress(a.getDlAddress());
                     actionsList.add(ofAction);
-                    actionsLength += OFActionDataLayerSource.MINIMUM_LENGTH;
+                    actionsLength += OFActionDataLayer.MINIMUM_LENGTH;
                     continue;
                 }
                 if (action.getType() == ActionType.SET_DL_DST) {
@@ -362,7 +351,7 @@ public class FlowConverter {
                     OFActionDataLayerDestination ofAction = new OFActionDataLayerDestination();
                     ofAction.setDataLayerAddress(a.getDlAddress());
                     actionsList.add(ofAction);
-                    actionsLength += OFActionDataLayerDestination.MINIMUM_LENGTH;
+                    actionsLength += OFActionDataLayer.MINIMUM_LENGTH;
                     continue;
                 }
                 if (action.getType() == ActionType.SET_NW_SRC) {
@@ -502,7 +491,7 @@ public class FlowConverter {
             if (ofMatch != null) {
                 if (!isIPv6) {
                     // Compute OF1.0 Match
-                    if (ofMatch.getInputPort() != 0) {
+                    if (ofMatch.getInputPort() != 0 && ofMatch.getInputPort() != OFPort.OFPP_LOCAL.getValue()) {
                         salMatch.setField(new MatchField(MatchType.IN_PORT,
                                 NodeConnectorCreator.createNodeConnector(
                                         ofMatch.getInputPort(), node)));
@@ -569,7 +558,7 @@ public class FlowConverter {
                 } else {
                     // Compute OF1.0 + IPv6 extensions Match
                     V6Match v6Match = (V6Match) ofMatch;
-                    if (v6Match.getInputPort() != 0) {
+                    if (v6Match.getInputPort() != 0 && v6Match.getInputPort() != OFPort.OFPP_LOCAL.getValue()) {
                         // Mask on input port is not defined
                         salMatch.setField(new MatchField(MatchType.IN_PORT,
                                 NodeConnectorCreator.createOFNodeConnector(
@@ -601,15 +590,30 @@ public class FlowConverter {
                         salMatch.setField(MatchType.DL_VLAN_PR, v6Match
                                 .getDataLayerVirtualLanPriorityCodePoint());
                     }
+                    // V6Match may carry IPv4 address
                     if (v6Match.getNetworkSrc() != null) {
                         salMatch.setField(MatchType.NW_SRC,
                                 v6Match.getNetworkSrc(),
                                 v6Match.getNetworkSourceMask());
+                    } else if (v6Match.getNetworkSource() != 0) {
+                        salMatch.setField(MatchType.NW_SRC, NetUtils
+                                .getInetAddress(v6Match.getNetworkSource()),
+                                NetUtils.getInetNetworkMask(
+                                        v6Match.getNetworkSourceMaskLen(),
+                                        false));
                     }
+                    // V6Match may carry IPv4 address
                     if (v6Match.getNetworkDest() != null) {
                         salMatch.setField(MatchType.NW_DST,
                                 v6Match.getNetworkDest(),
                                 v6Match.getNetworkDestinationMask());
+                    } else if (v6Match.getNetworkDestination() != 0) {
+                        salMatch.setField(MatchType.NW_DST,
+                                NetUtils.getInetAddress(v6Match
+                                        .getNetworkDestination()),
+                                NetUtils.getInetNetworkMask(
+                                        v6Match.getNetworkDestinationMaskLen(),
+                                        false));
                     }
                     if (v6Match.getNetworkTypeOfService() != 0) {
                         int dscp = NetUtils.getUnsignedByte(v6Match
index c7439ed..6c26af2 100644 (file)
@@ -39,8 +39,8 @@ import org.slf4j.LoggerFactory;
 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;
@@ -49,8 +49,6 @@ public class V6Match extends OFMatch implements Cloneable {
     protected short dataLayerTypeMask;
     protected byte networkTypeOfServiceMask;
     protected byte networkProtocolMask;
-    protected InetAddress networkSourceMask;
-    protected InetAddress networkDestinationMask;
     protected short transportSourceMask;
     protected short transportDestinationMask;
     protected short srcIPv6SubnetMaskbits;
@@ -135,8 +133,6 @@ public class V6Match extends OFMatch implements Cloneable {
         this.dataLayerTypeMask = 0;
         this.dataLayerVirtualLanMask = 0;
         this.dataLayerVirtualLanPriorityCodePointMask = 0;
-        this.networkDestinationMask = null;
-        this.networkSourceMask = null;
         this.networkTypeOfServiceMask = 0;
         this.networkProtocolMask = 0;
         this.transportSourceMask = 0;
@@ -163,33 +159,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.setNetworkDestination(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;
         }
 
@@ -475,20 +457,23 @@ public class V6Match extends OFMatch implements Cloneable {
     @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]));
@@ -508,11 +493,12 @@ 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)) {
@@ -526,36 +512,34 @@ public class V6Match extends OFMatch implements Cloneable {
             } 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);
                 }
             } 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);
                 }
@@ -580,9 +564,10 @@ 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);
+            }
         }
 
         /*
@@ -675,11 +660,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
@@ -689,9 +675,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);
@@ -701,9 +687,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);
@@ -718,8 +704,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);
@@ -732,8 +719,9 @@ 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
@@ -743,9 +731,9 @@ public class V6Match extends OFMatch implements Cloneable {
     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 {
+            else {
                 short vlan = data.getShort();
                 vlan &= vlan_mask;
                 super.setDataLayerVirtualLan(vlan);
@@ -755,9 +743,9 @@ public class V6Match extends OFMatch implements Cloneable {
                 this.wildcards ^= (1 << 20);
             }
         } else {
-            if ((nxmLen != 2) || (data.remaining() < 2))
+            if ((nxmLen != 2) || (data.remaining() < 2)) {
                 return;
-            else {
+            else {
                 short vlan = data.getShort();
                 vlan &= vlan_mask;
                 super.setDataLayerVirtualLan(vlan);
@@ -773,8 +761,9 @@ public class V6Match extends OFMatch implements Cloneable {
         /*
          * 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;
@@ -785,8 +774,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;
@@ -795,41 +785,31 @@ 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
@@ -839,24 +819,16 @@ public class V6Match extends OFMatch implements Cloneable {
 
     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);
@@ -864,16 +836,13 @@ public class V6Match extends OFMatch implements Cloneable {
                 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.match_len += 8;
@@ -885,8 +854,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;
@@ -897,8 +867,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;
@@ -909,8 +880,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;
@@ -921,8 +893,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;
@@ -931,34 +904,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;
                 }
@@ -970,35 +939,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;
                 }
@@ -1021,8 +985,6 @@ public class V6Match extends OFMatch implements Cloneable {
                 + ", dataLayerTypeMask=" + dataLayerTypeMask
                 + ", networkTypeOfServiceMask=" + networkTypeOfServiceMask
                 + ", networkProtocolMask=" + networkProtocolMask
-                + ", networkSourceMask=" + networkSourceMask
-                + ", networkDestinationMask=" + networkDestinationMask
                 + ", transportSourceMask=" + transportSourceMask
                 + ", transportDestinationMask=" + transportDestinationMask
                 + ", srcIPv6SubnetMaskbits=" + srcIPv6SubnetMaskbits
@@ -1151,10 +1113,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) {
@@ -1168,37 +1130,17 @@ 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;
     }
 
@@ -1303,35 +1245,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);
+            }
         }
     }
 
@@ -1387,9 +1357,7 @@ public class V6Match extends OFMatch implements Cloneable {
         result = prime * result + inputPortMask;
         result = prime * result + ((inputPortState == null) ? 0 : inputPortState.hashCode());
         result = prime * result + match_len;
-        result = prime * result + ((networkDestinationMask == null) ? 0 : networkDestinationMask.hashCode());
         result = prime * result + networkProtocolMask;
-        result = prime * result + ((networkSourceMask == null) ? 0 : networkSourceMask.hashCode());
         result = prime * result + networkTypeOfServiceMask;
         result = prime * result + ((nwDst == null) ? 0 : nwDst.hashCode());
         result = prime * result + ((nwDstState == null) ? 0 : nwDstState.hashCode());
@@ -1408,83 +1376,105 @@ public class V6Match extends OFMatch implements Cloneable {
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj)
+        if (this == obj) {
             return true;
-        if (!super.equals(obj))
+        }
+        if (!super.equals(obj)) {
             return false;
-        if (getClass() != obj.getClass())
+        }
+        if (getClass() != obj.getClass()) {
             return false;
+        }
         V6Match other = (V6Match) obj;
-        if (!Arrays.equals(dataLayerDestinationMask, other.dataLayerDestinationMask))
+        if (!Arrays.equals(dataLayerDestinationMask, other.dataLayerDestinationMask)) {
             return false;
-        if (!Arrays.equals(dataLayerSourceMask, other.dataLayerSourceMask))
-            return false;
-        if (dataLayerTypeMask != other.dataLayerTypeMask)
-            return false;
-        if (dataLayerVirtualLanMask != other.dataLayerVirtualLanMask)
+        }
+        if (!Arrays.equals(dataLayerSourceMask, other.dataLayerSourceMask)) {
             return false;
-        if (dataLayerVirtualLanPriorityCodePointMask != other.dataLayerVirtualLanPriorityCodePointMask)
+        }
+        if (dataLayerTypeMask != other.dataLayerTypeMask) {
             return false;
-        if (dlDestState != other.dlDestState)
+        }
+        if (dataLayerVirtualLanMask != other.dataLayerVirtualLanMask) {
             return false;
-        if (dlSourceState != other.dlSourceState)
+        }
+        if (dataLayerVirtualLanPriorityCodePointMask != other.dataLayerVirtualLanPriorityCodePointMask) {
             return false;
-        if (dlVlanState != other.dlVlanState)
+        }
+        if (dlDestState != other.dlDestState) {
             return false;
-        if (dstIPv6SubnetMaskbits != other.dstIPv6SubnetMaskbits)
+        }
+        if (dlSourceState != other.dlSourceState) {
             return false;
-        if (ethTypeState != other.ethTypeState)
+        }
+        if (dlVlanState != other.dlVlanState) {
             return false;
-        if (inputPortMask != other.inputPortMask)
+        }
+        if (dstIPv6SubnetMaskbits != other.dstIPv6SubnetMaskbits) {
             return false;
-        if (inputPortState != other.inputPortState)
+        }
+        if (ethTypeState != other.ethTypeState) {
             return false;
-        if (match_len != other.match_len)
+        }
+        if (inputPortMask != other.inputPortMask) {
             return false;
-        if (networkDestinationMask == null) {
-            if (other.networkDestinationMask != null)
-                return false;
-        } else if (!networkDestinationMask.equals(other.networkDestinationMask))
+        }
+        if (inputPortState != other.inputPortState) {
             return false;
-        if (networkProtocolMask != other.networkProtocolMask)
+        }
+        if (match_len != other.match_len) {
             return false;
-        if (networkSourceMask == null) {
-            if (other.networkSourceMask != null)
-                return false;
-        } else if (!networkSourceMask.equals(other.networkSourceMask))
+        }
+        if (networkProtocolMask != other.networkProtocolMask) {
             return false;
-        if (networkTypeOfServiceMask != other.networkTypeOfServiceMask)
+        }
+        if (networkTypeOfServiceMask != other.networkTypeOfServiceMask) {
             return false;
+        }
         if (nwDst == null) {
-            if (other.nwDst != null)
+            if (other.nwDst != null) {
                 return false;
-        } else if (!nwDst.equals(other.nwDst))
+            }
+        } else if (!nwDst.equals(other.nwDst)) {
             return false;
-        if (nwDstState != other.nwDstState)
+        }
+        if (nwDstState != other.nwDstState) {
             return false;
-        if (nwProtoState != other.nwProtoState)
+        }
+        if (nwProtoState != other.nwProtoState) {
             return false;
+        }
         if (nwSrc == null) {
-            if (other.nwSrc != null)
+            if (other.nwSrc != null) {
                 return false;
-        } else if (!nwSrc.equals(other.nwSrc))
+            }
+        } else if (!nwSrc.equals(other.nwSrc)) {
             return false;
-        if (nwSrcState != other.nwSrcState)
+        }
+        if (nwSrcState != other.nwSrcState) {
             return false;
-        if (nwTosState != other.nwTosState)
+        }
+        if (nwTosState != other.nwTosState) {
             return false;
-        if (pad_size != other.pad_size)
+        }
+        if (pad_size != other.pad_size) {
             return false;
-        if (srcIPv6SubnetMaskbits != other.srcIPv6SubnetMaskbits)
+        }
+        if (srcIPv6SubnetMaskbits != other.srcIPv6SubnetMaskbits) {
             return false;
-        if (tpDstState != other.tpDstState)
+        }
+        if (tpDstState != other.tpDstState) {
             return false;
-        if (tpSrcState != other.tpSrcState)
+        }
+        if (tpSrcState != other.tpSrcState) {
             return false;
-        if (transportDestinationMask != other.transportDestinationMask)
+        }
+        if (transportDestinationMask != other.transportDestinationMask) {
             return false;
-        if (transportSourceMask != other.transportSourceMask)
+        }
+        if (transportSourceMask != other.transportSourceMask) {
             return false;
+        }
         return true;
     }
 }
index 75f6a83..6afaf5f 100644 (file)
@@ -89,9 +89,10 @@ public class V6ExtensionTest {
                 match3.getDataLayerSource()));
         Assert.assertTrue(Arrays.equals(match.getDataLayerDestination(),
                 match3.getDataLayerDestination()));
-        Assert.assertTrue(match.getNetworkSrc().equals(match3.getNetworkSrc()));
-        Assert.assertTrue(match.getNetworkDest()
-                .equals(match3.getNetworkDest()));
+        Assert.assertNull(match.getNetworkSrc());
+        Assert.assertNull(match3.getNetworkSrc());
+        Assert.assertNull(match.getNetworkDest());
+        Assert.assertNull(match3.getNetworkDest());
         Assert.assertTrue(match.getDataLayerVirtualLan() == match3
                 .getDataLayerVirtualLan());
         Assert.assertTrue(match.getDataLayerVirtualLanPriorityCodePoint() == match3
index 4f3cbbd..3b8a295 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.controller.sal.match;
 
 import java.io.Serializable;
-
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
@@ -208,6 +207,6 @@ public class MatchField implements Cloneable, Serializable {
         if (type != other.type) {
             return false;
         }
-        return (type.equalValues(this.value, other.value) && type.equalMasks(this.mask, other.mask));
+        return type.equals(this.value, other.value, this.mask, other.mask);
     }
 }
index bb5e007..85e5056 100644 (file)
@@ -8,7 +8,7 @@
 
 package org.opendaylight.controller.sal.match;
 
-import java.net.Inet6Address;
+import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.util.Arrays;
 
@@ -242,8 +242,12 @@ public enum MatchType {
             break;
         case NW_SRC:
         case NW_DST:
-            result = prime * result + ((v == null)? 0 : v.hashCode());
-            result = prime * result + ((m == null)? NetUtils.gethighestIP(v instanceof Inet6Address).hashCode() : m.hashCode());
+            // Hash code has to take into account only prefix address
+            InetAddress ip = (InetAddress) v;
+            int maskLen = (m == null) ? ((ip instanceof Inet4Address) ? 32 : 128) : NetUtils
+                    .getSubnetMaskLength((InetAddress) m);
+            InetAddress prefix = NetUtils.getSubnetPrefix(ip, maskLen);
+            result = prime * result + ((v == null)? 0 : prefix.hashCode());
             break;
         default:
             result = prime * result + ((v == null)? 0 : v.hashCode());
@@ -278,14 +282,10 @@ public enum MatchType {
              * For network address mask, network node may return full mask for
              * flows the controller generated with a null mask object
              */
-            byte maskBytes[] = null;
-            if (a == null) {
-                maskBytes = ((InetAddress) b).getAddress();
-            } else if (b == null) {
-                maskBytes = ((InetAddress) a).getAddress();
-            }
-            if (maskBytes != null) {
-                return (NetUtils.getSubnetMaskLength(maskBytes) == 0);
+            if (a == null || b == null) {
+                InetAddress mask = (a == null) ? (InetAddress) b : (InetAddress) a;
+                int maxLength = (mask instanceof Inet4Address) ? 32 : 128;
+                return (NetUtils.getSubnetMaskLength(mask) == maxLength);
             }
         default:
             if (a == null) {
@@ -294,4 +294,23 @@ public enum MatchType {
             return a.equals(b);
         }
     }
+
+    public boolean equals(Object value1, Object value2, Object mask1, Object mask2) {
+        switch (this) {
+        case NW_SRC:
+        case NW_DST:
+            // Equality to be checked against prefix addresses
+            InetAddress thisIP = (InetAddress) value1;
+            int thisMaskLen = (mask1 == null) ? ((thisIP instanceof Inet4Address) ? 32 : 128) : NetUtils
+                    .getSubnetMaskLength((InetAddress) mask1);
+            InetAddress otherIP = (InetAddress) value2;
+            int otherMaskLen = (mask2 == null) ? ((otherIP instanceof Inet4Address) ? 32 : 128) : NetUtils
+                    .getSubnetMaskLength((InetAddress) mask2);
+
+            return NetUtils.getSubnetPrefix(thisIP, thisMaskLen)
+                    .equals(NetUtils.getSubnetPrefix(otherIP, otherMaskLen));
+        default:
+            return (this.equalValues(value1, value2) && this.equalMasks(mask1, mask2));
+        }
+    }
 }
index 4b42cb7..6a3a42f 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.controller.sal.utils;
 
+import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -41,7 +42,7 @@ public abstract class NetUtils {
     /**
      * Constant holding the broadcast MAC address
      */
-    public static byte[] BroadcastMACAddr = {-1, -1, -1, -1, -1, -1};
+    private static final byte[] BroadcastMACAddr = {-1, -1, -1, -1, -1, -1};
 
     /**
      * Converts a 4 bytes array into an integer number
@@ -144,46 +145,44 @@ public abstract class NetUtils {
     }
 
     /**
-     * Returns the number of contiguous bits belonging to the subnet, that have
-     * to be masked out Example: A prefix network byte mask of ff.ff.ff.00 will
-     * give a subnet mask length of 8, while ff.00.00.00 will return a subnet
-     * mask length of 24. If the passed prefixMask object is null, 0 is returned
+     * Returns the prefix size in bits of the specified subnet mask. Example:
+     * For the subnet mask ff.ff.ff.e0 it returns 25 while for ff.00.00.00 it
+     * returns 8. If the passed subnetMask array is null, 0 is returned.
      *
-     * @param prefixMask
-     *            the prefix mask as byte array
-     * @return the length of the prefix network mask
+     * @param subnetMask
+     *            the subnet mask as byte array
+     * @return the prefix length as number of bits
      */
-    public static int getSubnetMaskLength(byte[] prefixMask) {
+    public static int getSubnetMaskLength(byte[] subnetMask) {
         int maskLength = 0;
-        if (prefixMask != null) {
-            // Create bit mask
-            int intMask = 0;
-            int numBytes = prefixMask.length;
-            for (int i = 0; i < numBytes; i++) {
-                intMask |= (prefixMask[i] & 0xff) << (8 * (numBytes - 1 - i));
+        if (subnetMask != null && (subnetMask.length == 4 || subnetMask.length == 16)) {
+            int index = 0;
+            while (index < subnetMask.length && subnetMask[index] == (byte) 0xFF) {
+                maskLength += NetUtils.NumBitsInAByte;
+                index++;
             }
-
-            int bit = 1;
-            while (((intMask & bit) == 0) && (maskLength <= (numBytes * 8))) {
-                maskLength += 1;
-                bit = bit << 1;
+            if (index != subnetMask.length) {
+                int bits = NetUtils.NumBitsInAByte - 1;
+                while (bits >= 0 && (subnetMask[index] & 1 << bits)  != 0) {
+                    bits--;
+                    maskLength++;
+                }
             }
         }
         return maskLength;
     }
 
     /**
-     * Returns the number of contiguous bits belonging to the subnet, that have
-     * to be masked out Example: A prefix network byte mask of ff.ff.ff.00 will
-     * give a subnet mask length of 8, while ff.00.00.00 will return a subnet
-     * mask length of 24 If the passed prefixMask object is null, 0 is returned
+     * Returns the prefix size in bits of the specified subnet mask. Example:
+     * For the subnet mask 255.255.255.128 it returns 25 while for 255.0.0.0 it
+     * returns 8. If the passed subnetMask object is null, 0 is returned
      *
-     * @param prefixMask
-     *            the prefix mask as InetAddress
-     * @return the length of the prefix network mask
+     * @param subnetMask
+     *            the subnet mask as InetAddress
+     * @return the prefix length as number of bits
      */
-    public static int getSubnetMaskLength(InetAddress prefixMask) {
-        return (prefixMask == null) ? 0 : NetUtils.getSubnetMaskLength(prefixMask.getAddress());
+    public static int getSubnetMaskLength(InetAddress subnetMask) {
+        return subnetMask == null ? 0 : NetUtils.getSubnetMaskLength(subnetMask.getAddress());
     }
 
     /**
@@ -247,20 +246,18 @@ public abstract class NetUtils {
             return false;
         }
 
-        int testMaskLen = (testMask != null) ? NetUtils.getSubnetMaskLength(testMask.getAddress()) : 0;
-        int filterMaskLen = (filterMask != null) ? NetUtils.getSubnetMaskLength(filterMask.getAddress()) : 0;
-
-        int testPrefixLen = (testAddress instanceof Inet6Address) ? (128 - testMaskLen) : (32 - testMaskLen);
-        int filterPrefixLen = (filterAddress instanceof Inet6Address) ? (128 - filterMaskLen) : (32 - filterMaskLen);
+        int testMaskLen = (testMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+                .getSubnetMaskLength(testMask);
+        int filterMaskLen = NetUtils.getSubnetMaskLength(filterMask);
 
         // Mask length check. Test mask has to be more specific than filter one
-        if (testPrefixLen < filterPrefixLen) {
+        if (testMaskLen < filterMaskLen) {
             return true;
         }
 
         // Subnet Prefix on filter mask length must be the same
-        InetAddress prefix1 = getSubnetPrefix(testAddress, filterPrefixLen);
-        InetAddress prefix2 = getSubnetPrefix(filterAddress, filterPrefixLen);
+        InetAddress prefix1 = getSubnetPrefix(testAddress, filterMaskLen);
+        InetAddress prefix2 = getSubnetPrefix(filterAddress, filterMaskLen);
         return (!prefix1.equals(prefix2));
     }
 
index 599f974..0c7e5bb 100644 (file)
@@ -200,16 +200,46 @@ public class NetUtilsTest {
     public void testGetSubnetLen() {
 
         byte address[] = { (byte) 128, (byte) 0, (byte) 0, 0 };
-        Assert.assertTrue(NetUtils.getSubnetMaskLength(address) == 31);
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address) == 1);
 
         byte address1[] = { (byte) 255, 0, 0, 0 };
-        Assert.assertTrue(NetUtils.getSubnetMaskLength(address1) == 24);
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address1) == 8);
 
         byte address2[] = { (byte) 255, (byte) 255, (byte) 248, 0 };
-        Assert.assertTrue(NetUtils.getSubnetMaskLength(address2) == 11);
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address2) == 21);
 
         byte address4[] = { (byte) 255, (byte) 255, (byte) 255, (byte) 254 };
-        Assert.assertTrue(NetUtils.getSubnetMaskLength(address4) == 1);
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address4) == 31);
+
+        byte address5[] = { (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255,
+                (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255,
+                (byte) 255 };
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address5) == 128);
+
+        byte address6[] = { (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255,
+                (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255,
+                (byte) 254 };
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address6) == 127);
+
+        byte address7[] = { (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255,
+                (byte) 255, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 };
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address7) == 64);
+
+        byte address8[] = { (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255,
+                (byte) 254, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 };
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address8) == 63);
+
+        byte address9[] = { (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 128,
+                (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 };
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address9) == 49);
+
+        byte address10[] = { (byte) 128, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+                (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 };
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address10) == 1);
+
+        byte address11[] = { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+                (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 };
+        Assert.assertTrue(NetUtils.getSubnetMaskLength(address11) == 0);
     }
 
     @Test