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