9a09033db747031aff64dae8db29d6b554e9086f
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / IpConversionUtil.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc., Brocade, Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
10
11 import java.math.BigInteger;
12 import java.net.Inet4Address;
13 import java.net.InetAddress;
14 import java.net.UnknownHostException;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Iterator;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IetfInetUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import com.google.common.base.Preconditions;
28 import com.google.common.base.Splitter;
29 import com.google.common.base.Strings;
30 import com.google.common.collect.Iterators;
31 import com.google.common.net.InetAddresses;
32 import com.google.common.primitives.UnsignedBytes;
33
34
35 /**
36  * Created by Martin Bobak <mbobak@cisco.com> on 5.3.2015.
37  * v6 routines added by Anton Ivanov on 14.6.2015
38  * Arbitrary masks by sai.marapareddy@gmail.com
39  */
40 public final class IpConversionUtil {
41
42     private static final Logger LOG = LoggerFactory.getLogger(IpConversionUtil.class);
43     public static final String PREFIX_SEPARATOR = "/";
44     public static final Splitter PREFIX_SPLITTER = Splitter.on('/');
45     private static final int INADDR4SZ = 4;
46     private static final int INADDR6SZ = 16;
47     private static final int INT16SZ = 2;
48     private static final int IPV4_ADDRESS_LENGTH = 32;
49     private static final int IPV6_ADDRESS_LENGTH = 128;
50     private static final String DEFAULT_ARBITRARY_BIT_MASK = "255.255.255.255";
51
52     /*
53      * Prefix bytearray lookup table. We concatenate the prefixes
54      * to a single byte array and perform offset lookups to ensure
55      * the table is contiguous and save some space.
56      */
57     private static final byte[] PREFIX_BYTEARRAYS;
58     static {
59         final byte[] a = new byte[(INADDR6SZ * Byte.SIZE + 1) * INADDR6SZ];
60
61         int offset = 0;
62         for (int p = 0; p <= INADDR6SZ * Byte.SIZE; ++p) {
63             int prefix = p;
64             for (int i = 0; i < INADDR6SZ; ++i) {
65                 a[offset++] = (byte) nextNibble(prefix);
66                 prefix -= Byte.SIZE;
67             }
68         }
69
70         PREFIX_BYTEARRAYS = a;
71     }
72
73     private IpConversionUtil() {
74         throw new UnsupportedOperationException("This class should not be instantiated.");
75     }
76
77     public static Iterator<String> splitToParts(final Ipv4Prefix ipv4Prefix) {
78         return PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
79     }
80
81     public static Iterator<String> splitToParts(final Ipv4Address ipv4Address) {
82         /* Invalid (Ab)use of ip address as prefix!!! */
83         return Iterators.forArray(ipv4Address.getValue(), String.valueOf(IPV4_ADDRESS_LENGTH));
84     }
85
86     public static Iterator<String> splitToParts(final Ipv6Prefix ipv6Prefix) {
87         return PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
88     }
89
90     public static Iterator<String> splitToParts(final Ipv6Address ipv6Address) {
91         /* Invalid (Ab)use of ip address as prefix!!! */
92         return Iterators.forArray(ipv6Address.getValue(), String.valueOf(IPV6_ADDRESS_LENGTH));
93     }
94
95     /* This forest of functions has a purpose:
96      *
97      * 1. There are multiple coding styles around the plugin, this is necessary in order to have
98      *   one mechanism to convert them all, one mechanism to find them...
99      * 2. I hope that one day yangtools will actually deliver code fit for purpose in a packet
100      *   processing application (presently it is not. When this happens, these can be optimized
101      *   for "side-load" of pre-vetted data. Example. IP Address (v4 or v6) is prevetted left of the
102      *   prefix. It should be loadable into Prefix without _RERUNNING_ 100ms+ of regexps. When (and if)
103      *   that happens, it will be a simple fix here without chasing it across the whole plugin.
104     */
105
106     public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address){
107         return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address);
108     }
109
110     public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final String mask){
111         /*
112          * Ipv4Address has already validated the address part of the prefix,
113          * It is mandated to comply to the same regexp as the address
114          * There is absolutely no point rerunning additional checks vs this
115          * Note - there is no canonical form check here!!!
116          */
117         if (null != mask && !mask.isEmpty()) {
118             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
119         } else {
120             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
121         }
122     }
123
124     public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final int intmask){
125         return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, intmask);
126     }
127
128     public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final byte [] bytemask){
129         return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, countBits(bytemask));
130     }
131
132     public static DottedQuad createArbitraryBitMask(final byte [] bytemask)  {
133         DottedQuad dottedQuad = null;
134         if (bytemask == null ) {
135             dottedQuad = new DottedQuad(DEFAULT_ARBITRARY_BIT_MASK);
136         } else {
137             try {
138                 dottedQuad = new DottedQuad(InetAddress.getByAddress(bytemask).getHostAddress());
139             } catch (UnknownHostException e) {
140                 LOG.error("Failed to create the dottedQuad notation for the given mask ", e);
141             }
142         }
143         return dottedQuad;
144     }
145
146     public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address){
147         return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address);
148     }
149
150     public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final String mask){
151         /*
152          * Ipv6Address has already validated the address part of the prefix,
153          * It is mandated to comply to the same regexp as the address
154          * There is absolutely no point rerunning additional checks vs this
155          * Note - there is no canonical form check here!!!
156          */
157         if (Strings.isNullOrEmpty(mask)) {
158             return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + String.valueOf(IPV6_ADDRESS_LENGTH));
159         } else {
160             return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
161         }
162     }
163
164     public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final int intmask){
165         return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, intmask);
166     }
167
168     public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final byte [] bytemask){
169         return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, countBits(bytemask));
170     }
171
172     public static Integer extractPrefix(final Ipv4Prefix ipv4Prefix) {
173         return IetfInetUtil.INSTANCE.splitIpv4Prefix(ipv4Prefix).getValue();
174     }
175
176     public static Integer extractPrefix(final Ipv6Prefix ipv6Prefix) {
177         return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
178     }
179
180     public static Integer extractPrefix(final Ipv4Address ipv4Prefix) {
181         return IPV4_ADDRESS_LENGTH;
182     }
183
184     public static Integer extractPrefix(final Ipv6Address ipv6Prefix) {
185         return 128;
186     }
187
188     /*
189      * BIG FAT WARNING!!!
190      * Read all of the following before you touch any v6 code or decide to
191      * optimize it by invoking a "simple" Guava call
192      *
193      * Java IPv6 is fundamentally broken and Google libraries do not fix it.
194      * 1. Java will allways implicitly rewrite v4 mapped into v6 as a v4 address
195      *      and there is absolutely no way to override this behaviour
196      * 2. Guava libraries cannot parse non-canonical IPv6. They will throw an
197      *      exception. Even if they did, they re-use the same broken java code
198      *      underneath.
199      *
200      * This is why we have to parse v6 by ourselves.
201      *
202      * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
203      *
204      * The original BSD code is licensed under standard BSD license. While we
205      * are not obliged to provide an attribution, credit where credit is due.
206      * As far as why it is similar to Sun's sun.net.util please ask Sun why
207      * their code has the same variable names, comments and code flow.
208      *
209      */
210
211
212      /**
213      * Convert Ipv6Address object to a valid Canonical v6 address in byte format
214      *
215      * @param ipv6Address - v6 Address object
216      * @return - byte array of size 16. Last byte contains netmask
217      */
218
219
220     public static byte[] canonicalBinaryV6Address(final Ipv6Address ipv6Address) {
221         /*
222          * Do not modify this routine to take direct strings input!!!
223          * Key checks have been removed based on the assumption that
224          * the input is validated via regexps in Ipv6Prefix()
225          */
226
227         String [] address =  (ipv6Address.getValue()).split("%");
228
229         int colonp;
230         char ch;
231         boolean saw_xdigit;
232
233         /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
234
235         int val;
236
237         char[] src = address[0].toCharArray();
238
239         byte[] dst = new byte[INADDR6SZ];
240
241         int src_length = src.length;
242
243         colonp = -1;
244         int i = 0, j = 0;
245
246         /* Leading :: requires some special handling. */
247
248         /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
249          * We will derive our code from BSD. Shakespear always sounds better
250          * in original Clingon. So does Dilbert.
251          */
252
253         if (src[i] == ':') {
254             Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
255         }
256
257         int curtok = i;
258         saw_xdigit = false;
259
260
261         val = 0;
262         while (i < src_length) {
263             ch = src[i++];
264             int chval = Character.digit(ch, 16);
265
266             /* Business as usual - ipv6 address digit.
267              * We can remove all checks from the original BSD code because
268              * the regexp has already verified that we are not being fed
269              * anything bigger than 0xffff between the separators.
270              */
271
272             if (chval != -1) {
273                 val <<= 4;
274                 val |= chval;
275                 saw_xdigit = true;
276                 continue;
277             }
278
279             /* v6 separator */
280
281             if (ch == ':') {
282                 curtok = i;
283                 if (!saw_xdigit) {
284                     /* no need to check separator position validity - regexp does that */
285                     colonp = j;
286                     continue;
287                 }
288
289                 /* removed overrun check - the regexp checks for valid data */
290
291                 dst[j++] = (byte) ((val >>> 8) & 0xff);
292                 dst[j++] = (byte) (val & 0xff);
293                 saw_xdigit = false;
294                 val = 0;
295                 continue;
296             }
297
298             /* frankenstein - v4 attached to v6, mixed notation */
299
300             if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
301
302                 /* this has passed the regexp so it is fairly safe to parse it
303                  * straight away. As v4 addresses do not suffer from the same
304                  * defficiencies as the java v6 implementation we can invoke it
305                  * straight away and be done with it
306                  */
307
308                 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
309
310                 InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
311
312                 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
313                 System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
314                 j += INADDR4SZ;
315
316                 saw_xdigit = false;
317                 break;
318             }
319             /* removed parser exit on invalid char - no need to do it, regexp checks it */
320         }
321         if (saw_xdigit) {
322             Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
323             dst[j++] = (byte) ((val >> 8) & 0xff);
324             dst[j++] = (byte) (val & 0xff);
325         }
326
327         if (colonp != -1) {
328             int n = j - colonp;
329
330             Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
331             for (i = 1; i <= n; i++) {
332                 dst[INADDR6SZ - i] = dst[colonp + n - i];
333                 dst[colonp + n - i] = 0;
334             }
335             j = INADDR6SZ;
336         }
337
338         Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
339
340         return dst;
341     }
342
343     public static String byteArrayV6AddressToString (final byte [] _binary_form) throws UnknownHostException{
344         /* DO NOT DIY!!! - InetAddresses will actually print correct canonical
345          * zero compressed form.
346          */
347         return InetAddresses.toAddrString(InetAddress.getByAddress(_binary_form));
348     }
349
350     private static int nextNibble(final int mask) {
351         if (mask <= 0) {
352             return 0;
353         }
354         if (mask > 8) {
355             return 0xff;
356         }
357         return 0xff << (8 - mask);
358     }
359
360     /**
361      * Convert Ipv6Prefix object to a valid Canonical v6 prefix in byte format
362      *
363      * @param ipv6Prefix - v6 prefix object
364      * @return - byte array of size 16 + 1. Last byte contains netmask
365      */
366     public static byte[] canonicalBinaryV6Prefix(final Ipv6Prefix ipv6Prefix) {
367         /*
368          * Do not modify this routine to take direct strings input!!!
369          * Key checks have been removed based on the assumption that
370          * the input is validated via regexps in Ipv6Prefix()
371          */
372
373         int mask = 128;
374
375         String [] address = null;
376
377         boolean valid = true;
378
379         address =  (ipv6Prefix.getValue()).split("/");
380         try {
381             mask = Integer.parseInt(address[1]);
382             if (mask > 128) {
383                 valid = false;
384             }
385         } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
386             valid = false;
387         }
388
389         Preconditions.checkArgument(valid, "Supplied netmask in %s is invalid", ipv6Prefix.getValue());
390
391
392         int colonp;
393         char ch;
394         boolean saw_xdigit;
395
396         /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
397
398         int val;
399
400         char[] src = address[0].toCharArray();
401
402         byte[] dst = new byte[INADDR6SZ + 1];
403
404         int m = mask;
405
406         int src_length = src.length;
407
408         colonp = -1;
409         int i = 0, j = 0;
410
411         /* Leading :: requires some special handling. */
412
413         /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
414          * We will derive our code from BSD. Shakespear always sounds better
415          * in original Clingon. So does Dilbert.
416          */
417
418         if (src[i] == ':') {
419             Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
420         }
421
422         int curtok = i;
423         saw_xdigit = false;
424
425
426         val = 0;
427         while (i < src_length) {
428             ch = src[i++];
429             int chval = Character.digit(ch, 16);
430
431             /* Business as usual - ipv6 address digit.
432              * We can remove all checks from the original BSD code because
433              * the regexp has already verified that we are not being fed
434              * anything bigger than 0xffff between the separators.
435              */
436
437             if (chval != -1) {
438                 val <<= 4;
439                 val |= chval;
440                 saw_xdigit = true;
441                 continue;
442             }
443
444             /* v6 separator */
445
446             if (ch == ':') {
447                 curtok = i;
448                 if (!saw_xdigit) {
449                     /* no need to check separator position validity - regexp does that */
450                     colonp = j;
451                     continue;
452                 }
453
454                 /* removed overrun check - the regexp checks for valid data */
455
456                 saw_xdigit = false;
457
458                 if (m < 0) {
459                     /* stop parsing if we are past the mask */
460                     break;
461                 }
462
463                 dst[j] = (byte) ((val >> 8) & nextNibble(m)); j++; m = m - 8;
464
465                 if (m < 0) {
466                     /* stop parsing if we are past the mask */
467                     break;
468                 }
469
470                 dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
471
472                 val = 0;
473                 continue;
474             }
475
476             /* frankenstein - v4 attached to v6, mixed notation */
477
478             if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
479
480                 /* this has passed the regexp so it is fairly safe to parse it
481                  * straight away. As v4 addresses do not suffer from the same
482                  * defficiencies as the java v6 implementation we can invoke it
483                  * straight away and be done with it
484                  */
485
486                 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
487
488                 InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
489
490                 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
491                 System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
492                 j +=  INADDR4SZ;
493
494                 saw_xdigit = false;
495                 break;
496             }
497             /* removed parser exit on ivalid char - no need to do it, regexp checks it */
498         }
499         if (saw_xdigit) {
500             Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
501             dst[j] = (byte) ((val >> 8) & nextNibble(m)) ; j++; m = m - 8;
502             dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
503         }
504
505         if ((j < INADDR6SZ) && (m < 0)) {
506             /* past the mask */
507             for (i = j; i < INADDR6SZ; i++) {
508                 dst[i] = 0;
509             }
510         } else {
511             /* normal parsing */
512             if (colonp != -1) {
513                 int n = j - colonp;
514
515                 Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
516                 for (i = 1; i <= n; i++) {
517                     dst[INADDR6SZ - i] = dst[colonp + n - i];
518                     dst[colonp + n - i] = 0;
519                 }
520                 j = INADDR6SZ;
521             }
522             Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
523         }
524
525         dst[INADDR6SZ] = (byte) mask;
526         return dst;
527     }
528
529     /**
530      * Print a v6 prefix in byte array + 1 notation
531      * @param _binary_form - prefix, in byte [] form, last byte is netmask
532      * @return string of v6 prefix
533      * @throws UnknownHostException unknown host exception
534      */
535     public static String byteArrayV6PrefixToString(final byte [] _binary_form) throws UnknownHostException {
536         /* NO DIY!!! - InetAddresses will actually print correct canonical
537          * zero compressed form
538          */
539         StringBuilder sb = new StringBuilder();
540         /* Yang RFC specifies that the normalized form is RFC 5952, note - java
541          * core type is not RFC compliant, guava is.
542          */
543         sb.append(
544             InetAddresses.toAddrString(
545                 InetAddress.getByAddress(
546                     Arrays.copyOf(_binary_form, INADDR6SZ)
547                 )
548             )
549         );
550         sb.append('/');
551         sb.append(_binary_form[INADDR6SZ] & 0xff);
552         return sb.toString();
553     }
554
555     private static int ipv6PrefixByteArrayOffset(final int mask) {
556         if (mask < 0) {
557             return 0;
558         }
559
560         final int ret = mask * INADDR6SZ;
561         if (ret < PREFIX_BYTEARRAYS.length) {
562             return ret;
563         } else {
564             return PREFIX_BYTEARRAYS.length - INADDR6SZ;
565         }
566     }
567
568     /**
569      * Canonicalize a v6 prefix while in binary form
570      *
571      * @param prefix - prefix, in byte [] form
572      * @param mask - mask - number of bits
573      */
574     public static void canonicalizeIpv6Prefix(final byte [] prefix, final int mask) {
575         final int offset = ipv6PrefixByteArrayOffset(mask);
576
577         for (int i = 0; i < INADDR6SZ; i++) {
578             prefix[i] &= PREFIX_BYTEARRAYS[offset + i];
579         }
580     }
581
582     public static byte[] convertIpv6PrefixToByteArray(final int prefix) {
583         final int offset = ipv6PrefixByteArrayOffset(prefix);
584
585         return Arrays.copyOfRange(PREFIX_BYTEARRAYS, offset, offset + INADDR6SZ);
586     }
587
588     public static Ipv6Address extractIpv6Address(final Ipv6Prefix ipv6Prefix) {
589         return IetfInetUtil.INSTANCE.ipv6AddressFrom(ipv6Prefix);
590     }
591
592     public static Ipv4Address extractIpv4Address(final Ipv4Prefix ipv4Prefix) {
593         Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
594         return new Ipv4Address(addressParts.next());
595     }
596
597     public static DottedQuad extractIpv4AddressMask(final Ipv4Prefix ipv4Prefix) {
598         Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
599         addressParts.next();
600         Integer cidrMask =0;
601         if (addressParts.hasNext()) {
602             cidrMask = Integer.parseInt(addressParts.next());
603         }
604         long maskBits = 0;
605         maskBits = 0xffffffff << IPV4_ADDRESS_LENGTH - cidrMask;
606         String mask = String.format("%d.%d.%d.%d", (maskBits & 0x0000000000ff000000L) >> 24, (maskBits & 0x0000000000ff0000) >> 16, (maskBits & 0x0000000000ff00) >> 8, maskBits & 0xff);
607         DottedQuad netMask = new DottedQuad(mask);
608         return netMask;
609     }
610
611     public static Integer extractIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
612         return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
613     }
614
615     public static int countBits(final byte[] mask) {
616         int netmask = 0;
617         for (byte b : mask) {
618             netmask += Integer.bitCount(UnsignedBytes.toInt(b));
619         }
620         return netmask;
621     }
622
623     public static final byte[] convertArbitraryMaskToByteArray(DottedQuad mask) {
624         String maskValue;
625         if (mask != null && mask.getValue() != null) {
626            maskValue  = mask.getValue();
627         } else {
628             maskValue = DEFAULT_ARBITRARY_BIT_MASK;
629         }
630         InetAddress maskInIpFormat = null;
631         try {
632             maskInIpFormat = InetAddress.getByName(maskValue);
633         } catch (UnknownHostException e) {
634             LOG.error ("Failed to resolve the ip address of the mask",e);
635         }
636         byte[] bytes = maskInIpFormat.getAddress();
637         return bytes;
638     }
639
640     public static boolean isArbitraryBitMask(byte[] byteMask) {
641         if (byteMask == null) {
642             return false;
643         } else {
644             ArrayList<Integer> integerMaskArrayList = new ArrayList<Integer>();
645             String maskInBits;
646             // converting byte array to bits
647             maskInBits = new BigInteger(1, byteMask).toString(2);
648             ArrayList<String> stringMaskArrayList = new ArrayList<String>(Arrays.asList(maskInBits.split("(?!^)")));
649             for (String string:stringMaskArrayList) {
650                 integerMaskArrayList.add(Integer.parseInt(string));
651             }
652             return checkArbitraryBitMask(integerMaskArrayList);
653         }
654     }
655
656     private static boolean checkArbitraryBitMask(ArrayList<Integer> arrayList) {
657         // checks 0*1* case - Leading zeros in arrayList are truncated
658         if (arrayList.size()>0 && arrayList.size()<IPV4_ADDRESS_LENGTH) {
659             return true;
660         } else {
661             //checks 1*0*1 case
662             for (int i=0; i<arrayList.size()-1;i++) {
663                 if (arrayList.get(i) ==0 && arrayList.get(i+1) == 1) {
664                     return true;
665                 }
666             }
667         }
668         return false;
669     }
670 }