Fixed a bug and added a function for operating on MAC addresses.
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / utils / NetUtils.java
index 8e76c3fc60d81e35b552bd8bb54edf73d997bf6e..a3f21cff3eb50ad3d062b1c381a79abf35b81f2e 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;
@@ -28,6 +29,21 @@ public abstract class NetUtils {
      */
     public static final int NumBitsInAByte = 8;
 
+    /**
+     * Constant holding the number of bytes in MAC Address
+     */
+    public static final int MACAddrLengthInBytes = 6;
+
+    /**
+     * Constant holding the number of words in MAC Address
+     */
+    public static final int MACAddrLengthInWords = 3;
+
+    /**
+     * Constant holding the broadcast MAC address
+     */
+    private static final byte[] BroadcastMACAddr = {-1, -1, -1, -1, -1, -1};
+
     /**
      * Converts a 4 bytes array into an integer number
      *
@@ -43,20 +59,46 @@ public abstract class NetUtils {
     }
 
     /**
-     * Converts a long to 6 bytes array for mac addresses
-     * @param addr
-     * @return
+     * Converts a 6 bytes array into a long number MAC addresses.
+     *
+     * @param ba
+     *            The 6 bytes long byte array.
+     * @return The long number.
+     *         Zero is returned if {@code ba} is {@code null} or
+     *         the length of it is not six.
      */
+    public static long byteArray6ToLong(byte[] ba) {
+        if (ba == null || ba.length != MACAddrLengthInBytes) {
+            return 0L;
+        }
+        long num = 0L;
+        int i = 0;
+        do {
+            num <<= NumBitsInAByte;
+            num |= 0xff & ba[i];
+            i++;
+        } while (i < MACAddrLengthInBytes);
+        return num;
+    }
 
+    /**
+     * Converts a long number to a 6 bytes array for MAC addresses.
+     *
+     * @param addr
+     *            The long number.
+     * @return The byte array.
+     */
     public static byte[] longToByteArray6(long addr){
-        byte[] mac = new byte[6];
-        for(int i = 0; i < 6; i++){
-            mac[i] = (byte) (addr >> (i*8));
-        }
+        byte[] mac = new byte[MACAddrLengthInBytes];
+        int i = MACAddrLengthInBytes - 1;
+        do {
+            mac[i] = (byte) addr;
+            addr >>>= NumBitsInAByte;
+            i--;
+        } while (i >= 0);
         return mac;
     }
 
-
     /**
      * Converts an integer number into a 4 bytes array
      *
@@ -129,46 +171,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());
     }
 
     /**
@@ -232,20 +272,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));
     }
 
@@ -265,6 +303,43 @@ public abstract class NetUtils {
         return true;
     }
 
+    /**
+     * Returns true if the MAC address is the broadcast MAC address and false
+     * otherwise.
+     *
+     * @param MACAddress
+     * @return
+     */
+    public static boolean isBroadcastMACAddr(byte[] MACAddress) {
+        if (MACAddress.length == MACAddrLengthInBytes) {
+            for (int i = 0; i < 6; i++) {
+                if (MACAddress[i] != BroadcastMACAddr[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns true if the MAC address is a multicast MAC address and false
+     * otherwise. Note that this explicitly returns false for the broadcast MAC
+     * address.
+     *
+     * @param MACAddress
+     * @return
+     */
+    public static boolean isMulticastMACAddr(byte[] MACAddress) {
+        if (MACAddress.length == MACAddrLengthInBytes && !isBroadcastMACAddr(MACAddress)) {
+            if (MACAddress[0] % 2 == 1) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Returns true if the passed InetAddress contains all zero
      *