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