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