Bug 5390 - Adding Ipv6 L3ArbitraryBitMask feature support.
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / IpConversionUtil.java
index 552c49c2b485b0be27e36bf21ebf432fb48f7737..fe4ad06c9f13519d0a664a2bc3de977747583a0a 100644 (file)
@@ -1,6 +1,5 @@
 /*
- * Copyright (c) 2015 Brocade, Communications Systems, Inc
- * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2015 Cisco Systems, Inc., Brocade, Communications 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,37 +8,75 @@
 
 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
 
+import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
-import io.netty.buffer.ByteBufUtil;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
-import java.util.Iterator;
+import com.google.common.base.Strings;
 import com.google.common.collect.Iterators;
-import java.util.Arrays;
-import java.net.UnknownHostException;
-import java.net.Inet6Address;
+import com.google.common.collect.Lists;
+import com.google.common.net.InetAddresses;
+import com.google.common.primitives.UnsignedBytes;
+import java.math.BigInteger;
 import java.net.Inet4Address;
 import java.net.InetAddress;
-import com.google.common.net.InetAddresses;
-import com.google.common.base.Preconditions;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.opendaylight.ipv6.arbitrary.bitmask.fields.rev160224.Ipv6ArbitraryMask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 
 /**
  * Created by Martin Bobak <mbobak@cisco.com> on 5.3.2015.
  * v6 routines added by Anton Ivanov on 14.6.2015
+ * Arbitrary masks by sai.marapareddy@gmail.com
  */
 public final class IpConversionUtil {
 
+    private static final Logger LOG = LoggerFactory.getLogger(IpConversionUtil.class);
     public static final String PREFIX_SEPARATOR = "/";
     public static final Splitter PREFIX_SPLITTER = Splitter.on('/');
-    final private static int INADDR4SZ = 4;
-    final private static int INADDR6SZ = 16;
-    final private static int INT16SZ = 2;
+    private static final int INADDR4SZ = 4;
+    private static final int INADDR6SZ = 16;
+    private static final int INT16SZ = 2;
+    private static final int IPV4_ADDRESS_LENGTH = 32;
+    private static final int IPV6_ADDRESS_LENGTH = 128;
+    private static final String DEFAULT_ARBITRARY_BIT_MASK = "255.255.255.255";
+    private static final String DEFAULT_IPV6_ARBITRARY_BITMASK = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
+
+    /*
+     * Prefix bytearray lookup table. We concatenate the prefixes
+     * to a single byte array and perform offset lookups to ensure
+     * the table is contiguous and save some space.
+     */
+    private static final byte[] PREFIX_BYTEARRAYS;
+    static {
+        final byte[] a = new byte[(INADDR6SZ * Byte.SIZE + 1) * INADDR6SZ];
+
+        int offset = 0;
+        for (int p = 0; p <= INADDR6SZ * Byte.SIZE; ++p) {
+            int prefix = p;
+            for (int i = 0; i < INADDR6SZ; ++i) {
+                a[offset++] = (byte) nextNibble(prefix);
+                prefix -= Byte.SIZE;
+            }
+        }
+
+        PREFIX_BYTEARRAYS = a;
+    }
 
     private IpConversionUtil() {
-        throw new IllegalStateException("This class should not be instantiated.");
+        throw new UnsupportedOperationException("This class should not be instantiated.");
     }
 
     public static Iterator<String> splitToParts(final Ipv4Prefix ipv4Prefix) {
@@ -48,8 +85,7 @@ public final class IpConversionUtil {
 
     public static Iterator<String> splitToParts(final Ipv4Address ipv4Address) {
         /* Invalid (Ab)use of ip address as prefix!!! */
-        String [] tempPrefix = {ipv4Address.getValue(), "32"};
-        return Iterators.forArray(tempPrefix);
+        return Iterators.forArray(ipv4Address.getValue(), String.valueOf(IPV4_ADDRESS_LENGTH));
     }
 
     public static Iterator<String> splitToParts(final Ipv6Prefix ipv6Prefix) {
@@ -58,11 +94,9 @@ public final class IpConversionUtil {
 
     public static Iterator<String> splitToParts(final Ipv6Address ipv6Address) {
         /* Invalid (Ab)use of ip address as prefix!!! */
-        String [] tempPrefix = {ipv6Address.getValue(), "128"};
-        return Iterators.forArray(tempPrefix);
+        return Iterators.forArray(ipv6Address.getValue(), String.valueOf(IPV6_ADDRESS_LENGTH));
     }
 
-
     /* This forest of functions has a purpose:
      *
      * 1. There are multiple coding styles around the plugin, this is necessary in order to have
@@ -74,88 +108,99 @@ public final class IpConversionUtil {
      *   that happens, it will be a simple fix here without chasing it across the whole plugin.
     */
 
-    public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address){
-        return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + 32);
+    public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address){
+        return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address);
     }
 
-    public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, String mask){
-        /* 
+    public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final String mask){
+        /*
          * Ipv4Address has already validated the address part of the prefix,
          * It is mandated to comply to the same regexp as the address
          * There is absolutely no point rerunning additional checks vs this
          * Note - there is no canonical form check here!!!
          */
-        if (null != mask && !mask.equals("")) {
+        if (null != mask && !mask.isEmpty()) {
             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
         } else {
-            return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + "32");
+            return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
         }
     }
 
-    public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, int intmask){
-        return createPrefix(ipv4Address, "" + intmask); 
+    public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final int intmask){
+        return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, intmask);
+    }
+
+    public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final byte [] bytemask){
+        return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, countBits(bytemask));
+    }
+
+    public static DottedQuad createArbitraryBitMask(final byte [] bitmask)  {
+        DottedQuad dottedQuad = null;
+        if (bitmask == null ) {
+            dottedQuad = new DottedQuad(DEFAULT_ARBITRARY_BIT_MASK);
+        } else {
+            try {
+                dottedQuad = new DottedQuad(InetAddress.getByAddress(bitmask).getHostAddress());
+            } catch (UnknownHostException e) {
+                LOG.error("Failed to create the dottedQuad notation for the given mask ", e);
+            }
+        }
+        return dottedQuad;
     }
 
-    public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, byte [] bytemask){
-        return createPrefix(ipv4Address, "" + countBits(bytemask)); 
+    public static Ipv6ArbitraryMask createIpv6ArbitraryBitMask(final byte [] bitmask) {
+        Ipv6ArbitraryMask ipv6ArbitraryMask = null;
+        if (bitmask == null ) {
+            ipv6ArbitraryMask = new Ipv6ArbitraryMask(DEFAULT_IPV6_ARBITRARY_BITMASK);
+        } else {
+            try {
+                ipv6ArbitraryMask = new Ipv6ArbitraryMask(InetAddress.getByAddress(bitmask).getHostAddress());
+            } catch (UnknownHostException e) {
+                LOG.error("Failed to create the Ipv6ArbitraryMask notation for the given mask ", e);
+            }
+        }
+        return ipv6ArbitraryMask;
     }
 
-    public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address){
-        return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + 128);
+    public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address){
+        return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address);
     }
 
-    public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, String mask){
-        /* 
+    public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final String mask){
+        /*
          * Ipv6Address has already validated the address part of the prefix,
          * It is mandated to comply to the same regexp as the address
          * There is absolutely no point rerunning additional checks vs this
          * Note - there is no canonical form check here!!!
          */
-        if (null != mask && !mask.equals("")) {
-            return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
+        if (Strings.isNullOrEmpty(mask)) {
+            return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + String.valueOf(IPV6_ADDRESS_LENGTH));
         } else {
-            return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + "128");
+            return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
         }
     }
 
-    public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, int intmask){
-        return createPrefix(ipv6Address, "" + intmask); 
+    public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final int intmask){
+        return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, intmask);
     }
 
-    public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, byte [] bytemask){
-        /* 
-         * Ipv4Address has already validated the address part of the prefix,
-         * It is mandated to comply to the same regexp as the address
-         * There is absolutely no point rerunning additional checks vs this
-         * Note - there is no canonical form check here!!!
-         */
-         return createPrefix(ipv6Address, "" + countBits(bytemask)); 
+    public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final byte [] bytemask){
+        return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, countBits(bytemask));
     }
-    public static Integer extractPrefix(Ipv4Prefix ipv4Prefix) {
-        Iterator<String> addressParts = splitToParts(ipv4Prefix);
-        addressParts.next();
-        Integer retval = null;
-        if (addressParts.hasNext()) {
-            retval = Integer.parseInt(addressParts.next());
-        }
-        return retval;
+
+    public static Integer extractPrefix(final Ipv4Prefix ipv4Prefix) {
+        return IetfInetUtil.INSTANCE.splitIpv4Prefix(ipv4Prefix).getValue();
     }
 
-    public static Integer extractPrefix(Ipv6Prefix ipv6Prefix) {
-        Iterator<String> addressParts = splitToParts(ipv6Prefix);
-        addressParts.next();
-        Integer retval = null;
-        if (addressParts.hasNext()) {
-            retval = Integer.parseInt(addressParts.next());
-        }
-        return retval;
+    public static Integer extractPrefix(final Ipv6Prefix ipv6Prefix) {
+        return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
     }
 
-    public static Integer extractPrefix(Ipv4Address ipv4Prefix) {
-        return 32;
+    public static Integer extractPrefix(final Ipv4Address ipv4Prefix) {
+        return IPV4_ADDRESS_LENGTH;
     }
 
-    public static Integer extractPrefix(Ipv6Address ipv6Prefix) {
+    public static Integer extractPrefix(final Ipv6Address ipv6Prefix) {
         return 128;
     }
 
@@ -191,14 +236,18 @@ public final class IpConversionUtil {
      */
 
 
-    public static byte[] canonicalBinaryV6Address(Ipv6Address ipv6Address) {
-        /* 
+    public static byte[] canonicalBinaryV6Address(final Ipv6Address ipv6Address) {
+        /*
          * Do not modify this routine to take direct strings input!!!
          * Key checks have been removed based on the assumption that
          * the input is validated via regexps in Ipv6Prefix()
          */
 
-        String [] address =  (ipv6Address.getValue()).split("%");
+       Iterable<String> splittedV6Address = Splitter.on("%")
+                .trimResults()
+                .omitEmptyStrings()
+                .split(ipv6Address.getValue());
+        List<String> partsV6Address = Lists.newArrayList(splittedV6Address.iterator());
 
         int colonp;
         char ch;
@@ -208,7 +257,7 @@ public final class IpConversionUtil {
 
         int val;
 
-        char[] src = address[0].toCharArray();
+        char[] src = partsV6Address.get(0).toCharArray();
 
         byte[] dst = new byte[INADDR6SZ];
 
@@ -262,7 +311,7 @@ public final class IpConversionUtil {
 
                 /* removed overrun check - the regexp checks for valid data */
 
-                dst[j++] = (byte) ((val >> 8) & 0xff);
+                dst[j++] = (byte) ((val >>> 8) & 0xff);
                 dst[j++] = (byte) (val & 0xff);
                 saw_xdigit = false;
                 val = 0;
@@ -281,19 +330,16 @@ public final class IpConversionUtil {
 
                 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
 
-                InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
+                InetAddress _inet_form = InetAddresses.forString(partsV6Address.get(0).substring(curtok, src_length));
 
                 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
+                System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
+                j += INADDR4SZ;
 
-                byte[] v4addr =  _inet_form.getAddress();
-
-                for (int k = 0; k < INADDR4SZ; k++) {
-                    dst[j++] = v4addr[k];
-                }
                 saw_xdigit = false;
                 break;
             }
-            /* removed parser exit on ivalid char - no need to do it, regexp checks it */
+            /* removed parser exit on invalid char - no need to do it, regexp checks it */
         }
         if (saw_xdigit) {
             Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
@@ -317,15 +363,14 @@ public final class IpConversionUtil {
         return dst;
     }
 
-    static public String byteArrayV6AddressToString (byte [] _binary_form) throws UnknownHostException{
+    public static String byteArrayV6AddressToString (final byte [] _binary_form) throws UnknownHostException{
         /* DO NOT DIY!!! - InetAddresses will actually print correct canonical
-         * zero compressed form. 
+         * zero compressed form.
          */
         return InetAddresses.toAddrString(InetAddress.getByAddress(_binary_form));
     }
-    
 
-    static private int nextNibble(int mask) {
+    private static int nextNibble(final int mask) {
         if (mask <= 0) {
             return 0;
         }
@@ -335,16 +380,14 @@ public final class IpConversionUtil {
         return 0xff << (8 - mask);
     }
 
-     /**
+    /**
      * Convert Ipv6Prefix object to a valid Canonical v6 prefix in byte format
      *
      * @param ipv6Prefix - v6 prefix object
      * @return - byte array of size 16 + 1. Last byte contains netmask
      */
-
-
-    public static byte[] canonicalBinaryV6Prefix(Ipv6Prefix ipv6Prefix) {
-        /* 
+    public static byte[] canonicalBinaryV6Prefix(final Ipv6Prefix ipv6Prefix) {
+        /*
          * Do not modify this routine to take direct strings input!!!
          * Key checks have been removed based on the assumption that
          * the input is validated via regexps in Ipv6Prefix()
@@ -352,13 +395,16 @@ public final class IpConversionUtil {
 
         int mask = 128;
 
-        String [] address = null; 
+        Iterable<String> splittedV6Prefix = Splitter.on("/")
+                .trimResults()
+                .omitEmptyStrings()
+                .split(ipv6Prefix.getValue());
+        List<String> partsV6Prefix = Lists.newArrayList(splittedV6Prefix.iterator());
 
         boolean valid = true;
-
-        address =  (ipv6Prefix.getValue()).split("/");
+        
         try {
-            mask = Integer.parseInt(address[1]);
+            mask = Integer.parseInt(partsV6Prefix.get(1));
             if (mask > 128) {
                 valid = false;
             }
@@ -368,7 +414,7 @@ public final class IpConversionUtil {
 
         Preconditions.checkArgument(valid, "Supplied netmask in %s is invalid", ipv6Prefix.getValue());
 
-    
+
         int colonp;
         char ch;
         boolean saw_xdigit;
@@ -377,7 +423,7 @@ public final class IpConversionUtil {
 
         int val;
 
-        char[] src = address[0].toCharArray();
+        char[] src = partsV6Prefix.get(0).toCharArray();
 
         byte[] dst = new byte[INADDR6SZ + 1];
 
@@ -465,15 +511,12 @@ public final class IpConversionUtil {
 
                 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
 
-                InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
+                InetAddress _inet_form = InetAddresses.forString(partsV6Prefix.get(0).substring(curtok, src_length));
 
                 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
+                System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
+                j +=  INADDR4SZ;
 
-                byte[] v4addr =  _inet_form.getAddress();
-
-                for (int k = 0; k < INADDR4SZ; k++) {
-                    dst[j++] = v4addr[k];
-                }
                 saw_xdigit = false;
                 break;
             }
@@ -509,86 +552,224 @@ public final class IpConversionUtil {
         return dst;
     }
 
-     /**
+    /**
      * Print a v6 prefix in byte array + 1 notation
-     *
      * @param _binary_form - prefix, in byte [] form, last byte is netmask
+     * @return string of v6 prefix
+     * @throws UnknownHostException unknown host exception
      */
-
-
-    static public String byteArrayV6PrefixToString(byte [] _binary_form) throws UnknownHostException {
+    public static String byteArrayV6PrefixToString(final byte [] _binary_form) throws UnknownHostException {
         /* NO DIY!!! - InetAddresses will actually print correct canonical
          * zero compressed form
          */
-        StringBuilder sb = new java.lang.StringBuilder();
+        StringBuilder sb = new StringBuilder();
         /* Yang RFC specifies that the normalized form is RFC 5952, note - java
          * core type is not RFC compliant, guava is.
          */
         sb.append(
             InetAddresses.toAddrString(
                 InetAddress.getByAddress(
-                    Arrays.copyOfRange(_binary_form, 0, INADDR6SZ)
+                    Arrays.copyOf(_binary_form, INADDR6SZ)
                 )
             )
         );
-        sb.append("/");
+        sb.append('/');
         sb.append(_binary_form[INADDR6SZ] & 0xff);
         return sb.toString();
     }
 
+    private static int ipv6PrefixByteArrayOffset(final int mask) {
+        if (mask < 0) {
+            return 0;
+        }
 
-     /**
+        final int ret = mask * INADDR6SZ;
+        if (ret < PREFIX_BYTEARRAYS.length) {
+            return ret;
+        } else {
+            return PREFIX_BYTEARRAYS.length - INADDR6SZ;
+        }
+    }
+
+    /**
      * Canonicalize a v6 prefix while in binary form
      *
-     * @param _prefix - prefix, in byte [] form
+     * @param prefix - prefix, in byte [] form
      * @param mask - mask - number of bits
      */
+    public static void canonicalizeIpv6Prefix(final byte [] prefix, final int mask) {
+        final int offset = ipv6PrefixByteArrayOffset(mask);
 
-    static public void canonicalizeIpv6Prefix(byte [] _prefix, int mask) {
-
-        for (int i=0; i < INADDR6SZ; i++) {
-            _prefix[i] = (byte) (_prefix[i] & nextNibble(mask));
-            mask = mask - 8;
+        for (int i = 0; i < INADDR6SZ; i++) {
+            prefix[i] &= PREFIX_BYTEARRAYS[offset + i];
         }
     }
 
-    public static byte[] convertIpv6PrefixToByteArray(int prefix) {
-        byte[] mask = new byte[16];
-        for (int count = 0; count < 16; count++) {
-            mask[count] = (byte) nextNibble(prefix);
-            prefix = prefix - 8;
-        }
-        return mask;
+    public static byte[] convertIpv6PrefixToByteArray(final int prefix) {
+        final int offset = ipv6PrefixByteArrayOffset(prefix);
+
+        return Arrays.copyOfRange(PREFIX_BYTEARRAYS, offset, offset + INADDR6SZ);
     }
 
     public static Ipv6Address extractIpv6Address(final Ipv6Prefix ipv6Prefix) {
-        Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
-        return new Ipv6Address(addressParts.next());
+        return IetfInetUtil.INSTANCE.ipv6AddressFrom(ipv6Prefix);
     }
 
-    public static Integer extractIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
-        Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
+    public static Ipv4Address extractIpv4Address(final Ipv4Prefix ipv4Prefix) {
+        Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
+        return new Ipv4Address(addressParts.next());
+    }
+
+    public static DottedQuad extractIpv4AddressMask(final Ipv4Prefix ipv4Prefix) {
+        Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
         addressParts.next();
+        Integer cidrMask =0;
+        if (addressParts.hasNext()) {
+            cidrMask = Integer.parseInt(addressParts.next());
+        }
+        long maskBits = 0;
+        maskBits = 0xffffffff << IPV4_ADDRESS_LENGTH - cidrMask;
+        String mask = String.format("%d.%d.%d.%d", (maskBits & 0x0000000000ff000000L) >> 24, (maskBits & 0x0000000000ff0000) >> 16, (maskBits & 0x0000000000ff00) >> 8, maskBits & 0xff);
+        DottedQuad netMask = new DottedQuad(mask);
+        return netMask;
+    }
 
-        Integer prefix = null;
+    public static Ipv6ArbitraryMask extractIpv6AddressMask(final Ipv6Prefix ipv6Prefix) {
+        Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
+        addressParts.next();
+        int maskLength = 0;
         if (addressParts.hasNext()) {
-            prefix = Integer.parseInt(addressParts.next());
+            maskLength = Integer.parseInt(addressParts.next());
         }
-        return prefix;
+        BitSet ipmask = new BitSet(128);
+        ipmask.set(0,maskLength,true);
+        ipmask.set(maskLength+1,128,false);
+        byte[] finalmask = new byte[16];
+        System.arraycopy(ipmask.toByteArray(),0,finalmask,0,ipmask.toByteArray().length);
+        InetAddress inetAddress = null;
+        try {
+            inetAddress = InetAddress.getByAddress(finalmask);
+        } catch (UnknownHostException e) {
+            LOG.error("Failed to convert the Ipv6 subnetmask from integer to mask value ", e);
+        }
+        return new Ipv6ArbitraryMask(inetAddress.getHostAddress());
     }
 
-    private static int toInt(byte b) {
-        return b < 0 ? b + 256 : b;
+    public static Integer extractIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
+        return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
     }
 
-    public static int countBits(byte[] mask) {
+    public static int countBits(final byte[] mask) {
         int netmask = 0;
         for (byte b : mask) {
-            netmask += Integer.bitCount(toInt(b));
+            netmask += Integer.bitCount(UnsignedBytes.toInt(b));
         }
         return netmask;
     }
 
+    public static final byte[] convertArbitraryMaskToByteArray(DottedQuad mask) {
+        String maskValue;
+        if (mask != null && mask.getValue() != null) {
+           maskValue  = mask.getValue();
+        } else {
+            maskValue = DEFAULT_ARBITRARY_BIT_MASK;
+        }
+        InetAddress maskInIpFormat = null;
+        try {
+            maskInIpFormat = InetAddress.getByName(maskValue);
+        } catch (UnknownHostException e) {
+            LOG.error ("Failed to resolve the ip address of the mask ",e);
+        }
+        byte[] bytes = maskInIpFormat.getAddress();
+        return bytes;
+    }
 
+    public static boolean isArbitraryBitMask(byte[] byteMask) {
+        if (byteMask == null) {
+            return false;
+        } else {
+            ArrayList<Integer> integerMaskArrayList = new ArrayList<Integer>();
+            String maskInBits;
+            // converting byte array to bits
+            maskInBits = new BigInteger(1, byteMask).toString(2);
+            ArrayList<String> stringMaskArrayList = new ArrayList<String>(Arrays.asList(maskInBits.split("(?!^)")));
+            for (String string:stringMaskArrayList) {
+                integerMaskArrayList.add(Integer.parseInt(string));
+            }
+            return checkArbitraryBitMask(integerMaskArrayList);
+        }
+    }
+
+    private static boolean checkArbitraryBitMask(ArrayList<Integer> arrayList) {
+        // checks 0*1* case - Leading zeros in arrayList are truncated
+        if (arrayList.size()>0 && arrayList.size()<IPV4_ADDRESS_LENGTH) {
+            return true;
+        } else {
+            //checks 1*0*1 case
+            for (int i=0; i<arrayList.size()-1;i++) {
+                if (arrayList.get(i) ==0 && arrayList.get(i+1) == 1) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static final byte[] convertIpv6ArbitraryMaskToByteArray(final Ipv6ArbitraryMask mask) {
+        String maskValue;
+        if (mask.getValue() != null) {
+            maskValue  = mask.getValue();
+        } else {
+            maskValue = DEFAULT_IPV6_ARBITRARY_BITMASK;
+        }
+        InetAddress maskInIpFormat = null;
+        try {
+            maskInIpFormat = InetAddress.getByName(maskValue);
+        } catch (UnknownHostException e) {
+            LOG.error ("Failed to convert mask string to ipv6 format mask ",e);
+        }
+        return maskInIpFormat.getAddress();
+    }
 
+    public static boolean isIpv6ArbitraryBitMask(final byte[] byteMask) {
+        if (byteMask == null) {
+            return false;
+        } else {
+            ArrayList<Integer> integerMaskArrayList = new ArrayList<Integer>();
+            String maskInBits;
+            // converting byte array to bits
+            maskInBits = new BigInteger(1, byteMask).toString(2);
+            ArrayList<String> stringMaskArrayList = new ArrayList<String>(Arrays.asList(maskInBits.split("(?!^)")));
+            for (String string:stringMaskArrayList) {
+                integerMaskArrayList.add(Integer.parseInt(string));
+            }
+            return checkIpv6ArbitraryBitMask(integerMaskArrayList);
+        }
+    }
+
+    private static boolean checkIpv6ArbitraryBitMask(final ArrayList<Integer> arrayList) {
+        // checks 0*1* case - Leading zeros in arrayList are truncated
+        if (arrayList.size() > 0 && arrayList.size() < IPV6_ADDRESS_LENGTH) {
+            return true;
+        } else {
+            //checks 1*0*1 case
+            for (int i=0; i<arrayList.size()-1;i++) {
+                if (arrayList.get(i) ==0 && arrayList.get(i+1) == 1) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static String compressedIpv6Format(final String ipv6Address) {
+        String compressedIpv6Address;
+        compressedIpv6Address = ipv6Address.replaceAll("((?::0+\\b){2,}):?(?!\\S*\\b\\1:0\\b)(\\S*)", "::$2");
+        return compressedIpv6Address;
+    }
+
+    public static Ipv6ArbitraryMask compressedIpv6MaskFormat(final Ipv6ArbitraryMask ipv6Mask) {
+        String stringIpv6Mask = ipv6Mask.getValue();
+        return new Ipv6ArbitraryMask(compressedIpv6Format(stringIpv6Mask));
+    }
 }