2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common;
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Splitter;
12 import com.google.common.base.Strings;
13 import com.google.common.collect.Lists;
14 import com.google.common.net.InetAddresses;
15 import com.google.common.primitives.UnsignedBytes;
16 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
17 import java.math.BigInteger;
18 import java.net.Inet4Address;
19 import java.net.InetAddress;
20 import java.net.UnknownHostException;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.BitSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import javax.annotation.Nullable;
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;
37 public final class IpConversionUtil {
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";
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.
55 private static final byte[] PREFIX_BYTEARRAYS;
58 final byte[] a = new byte[(INADDR6SZ * Byte.SIZE + 1) * INADDR6SZ];
61 for (int p = 0; p <= INADDR6SZ * Byte.SIZE; ++p) {
63 for (int i = 0; i < INADDR6SZ; ++i) {
64 a[offset++] = (byte) nextNibble(prefix);
69 PREFIX_BYTEARRAYS = a;
72 private IpConversionUtil() {
73 throw new UnsupportedOperationException("This class should not be instantiated.");
76 public static Iterator<String> splitToParts(final Ipv4Prefix ipv4Prefix) {
77 return PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
80 public static Iterator<String> splitToParts(final Ipv6Prefix ipv6Prefix) {
81 return PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
84 /* This forest of functions has a purpose:
86 * 1. There are multiple coding styles around the plugin, this is necessary in order to have
87 * one mechanism to convert them all, one mechanism to find them...
88 * 2. I hope that one day yangtools will actually deliver code fit for purpose in a packet
89 * processing application (presently it is not. When this happens, these can be optimized
90 * for "side-load" of pre-vetted data. Example. IP Address (v4 or v6) is prevetted left of the
91 * prefix. It should be loadable into Prefix without _RERUNNING_ 100ms+ of regexps. When (and if)
92 * that happens, it will be a simple fix here without chasing it across the whole plugin.
95 public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address) {
96 return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address);
99 public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final String mask) {
101 * Ipv4Address has already validated the address part of the prefix,
102 * It is mandated to comply to the same regexp as the address
103 * There is absolutely no point rerunning additional checks vs this
104 * Note - there is no canonical form check here!!!
106 if (null != mask && !mask.isEmpty()) {
107 return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
109 return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
113 public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final int intmask) {
114 return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, intmask);
117 public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final byte [] bytemask) {
118 if (bytemask == null) {
119 return createPrefix(ipv4Address);
122 return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, countBits(bytemask));
125 public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address) {
126 return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address);
129 public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final String mask) {
131 * Ipv6Address has already validated the address part of the prefix,
132 * It is mandated to comply to the same regexp as the address
133 * There is absolutely no point rerunning additional checks vs this
134 * Note - there is no canonical form check here!!!
136 if (Strings.isNullOrEmpty(mask)) {
137 return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + String.valueOf(IPV6_ADDRESS_LENGTH));
139 return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
143 public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final int intmask) {
144 return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, intmask);
147 public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final byte [] bytemask) {
148 if (bytemask == null) {
149 return createPrefix(ipv6Address);
152 return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, countBits(bytemask));
155 public static DottedQuad createArbitraryBitMask(final byte [] bitmask) {
156 DottedQuad dottedQuad = null;
157 if (bitmask == null) {
158 dottedQuad = new DottedQuad(DEFAULT_ARBITRARY_BIT_MASK);
161 dottedQuad = new DottedQuad(InetAddress.getByAddress(bitmask).getHostAddress());
162 } catch (UnknownHostException e) {
163 LOG.error("Failed to create the dottedQuad notation for the given mask ", e);
169 public static Ipv6ArbitraryMask createIpv6ArbitraryBitMask(final byte [] bitmask) {
170 Ipv6ArbitraryMask ipv6ArbitraryMask = null;
171 if (bitmask == null) {
172 ipv6ArbitraryMask = new Ipv6ArbitraryMask(DEFAULT_IPV6_ARBITRARY_BITMASK);
175 ipv6ArbitraryMask = new Ipv6ArbitraryMask(InetAddress.getByAddress(bitmask).getHostAddress());
176 } catch (UnknownHostException e) {
177 LOG.error("Failed to create the Ipv6ArbitraryMask notation for the given mask ", e);
180 return ipv6ArbitraryMask;
183 public static Integer extractPrefix(final Ipv4Prefix ipv4Prefix) {
184 return IetfInetUtil.INSTANCE.splitIpv4Prefix(ipv4Prefix).getValue();
187 public static Integer extractPrefix(final Ipv6Prefix ipv6Prefix) {
188 return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
191 public static Integer extractPrefix(final Ipv4Address ipv4Prefix) {
192 return IPV4_ADDRESS_LENGTH;
195 public static Integer extractPrefix(final Ipv6Address ipv6Prefix) {
201 * Read all of the following before you touch any v6 code or decide to
202 * optimize it by invoking a "simple" Guava call
204 * Java IPv6 is fundamentally broken and Google libraries do not fix it.
205 * 1. Java will allways implicitly rewrite v4 mapped into v6 as a v4 address
206 * and there is absolutely no way to override this behaviour
207 * 2. Guava libraries cannot parse non-canonical IPv6. They will throw an
208 * exception. Even if they did, they re-use the same broken java code
211 * This is why we have to parse v6 by ourselves.
213 * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
215 * The original BSD code is licensed under standard BSD license. While we
216 * are not obliged to provide an attribution, credit where credit is due.
217 * As far as why it is similar to Sun's sun.net.util please ask Sun why
218 * their code has the same variable names, comments and code flow.
224 * Convert Ipv6Address object to a valid Canonical v6 address in byte format.
226 * @param ipv6Address - v6 Address object
227 * @return - byte array of size 16. Last byte contains netmask
229 public static byte[] canonicalBinaryV6Address(final Ipv6Address ipv6Address) {
231 * Do not modify this routine to take direct strings input!!!
232 * Key checks have been removed based on the assumption that
233 * the input is validated via regexps in Ipv6Prefix()
236 return canonicalBinaryV6AddressFromString(ipv6Address.getValue());
240 private static byte[] canonicalBinaryV6AddressFromString(final String ipv6Address) {
241 Iterable<String> splittedV6Address = Splitter.on("%")
245 List<String> partsV6Address = Lists.newArrayList(splittedV6Address.iterator());
251 /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
253 char[] src = partsV6Address.get(0).toCharArray();
255 byte[] dst = new byte[INADDR6SZ];
261 /* Leading :: requires some special handling. */
263 /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
264 * We will derive our code from BSD. Shakespear always sounds better
265 * in original Clingon. So does Dilbert.
268 if (src[index1] == ':') {
269 Preconditions.checkArgument(src[++index1] == ':', "Invalid v6 address");
275 int srcLength = src.length;
277 while (index1 < srcLength) {
279 int chval = Character.digit(ch, 16);
281 /* Business as usual - ipv6 address digit.
282 * We can remove all checks from the original BSD code because
283 * the regexp has already verified that we are not being fed
284 * anything bigger than 0xffff between the separators.
299 /* no need to check separator position validity - regexp does that */
304 /* removed overrun check - the regexp checks for valid data */
306 dst[index2++] = (byte) (val >>> 8 & 0xff);
307 dst[index2++] = (byte) (val & 0xff);
313 /* frankenstein - v4 attached to v6, mixed notation */
315 if (ch == '.' && index2 + INADDR4SZ <= INADDR6SZ) {
317 /* this has passed the regexp so it is fairly safe to parse it
318 * straight away. As v4 addresses do not suffer from the same
319 * defficiencies as the java v6 implementation we can invoke it
320 * straight away and be done with it
323 Preconditions.checkArgument(index2 != INADDR6SZ - INADDR4SZ - 1, "Invalid v4 in v6 mapping");
325 InetAddress inetForm = InetAddresses.forString(partsV6Address.get(0).substring(curtok, srcLength));
327 Preconditions.checkArgument(inetForm instanceof Inet4Address);
328 System.arraycopy(inetForm.getAddress(), 0, dst, index2, INADDR4SZ);
334 /* removed parser exit on invalid char - no need to do it, regexp checks it */
337 Preconditions.checkArgument(index2 + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
338 dst[index2++] = (byte) (val >> 8 & 0xff);
339 dst[index2++] = (byte) (val & 0xff);
343 int to = index2 - colonp;
345 Preconditions.checkArgument(index2 != INADDR6SZ, "Overrun in v6 parsing, should not occur");
346 for (index1 = 1; index1 <= to; index1++) {
347 dst[INADDR6SZ - index1] = dst[colonp + to - index1];
348 dst[colonp + to - index1] = 0;
353 Preconditions.checkArgument(index2 == INADDR6SZ, "Overrun in v6 parsing, should not occur");
358 public static String byteArrayV6AddressToString(final byte [] binaryForm) throws UnknownHostException {
359 /* DO NOT DIY!!! - InetAddresses will actually print correct canonical
360 * zero compressed form.
362 return InetAddresses.toAddrString(InetAddress.getByAddress(binaryForm));
365 private static int nextNibble(final int mask) {
372 return 0xff << 8 - mask;
376 * Convert Ipv6Prefix object to a valid Canonical v6 prefix in byte format.
378 * @param ipv6Prefix - v6 prefix object
379 * @return - byte array of size 16 + 1. Last byte contains netmask
381 public static byte[] canonicalBinaryV6Prefix(final Ipv6Prefix ipv6Prefix) {
383 * Do not modify this routine to take direct strings input!!!
384 * Key checks have been removed based on the assumption that
385 * the input is validated via regexps in Ipv6Prefix()
388 int initialMask = 128;
390 Iterable<String> splittedV6Prefix = Splitter.on("/")
393 .split(ipv6Prefix.getValue());
394 List<String> partsV6Prefix = Lists.newArrayList(splittedV6Prefix.iterator());
396 boolean valid = true;
399 initialMask = Integer.parseInt(partsV6Prefix.get(1));
400 if (initialMask > 128) {
403 } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
407 Preconditions.checkArgument(valid, "Supplied netmask in %s is invalid", ipv6Prefix.getValue());
414 /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
416 char[] src = partsV6Prefix.get(0).toCharArray();
418 byte[] dst = new byte[INADDR6SZ + 1];
420 int mask = initialMask;
426 /* Leading :: requires some special handling. */
428 /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
429 * We will derive our code from BSD. Shakespear always sounds better
430 * in original Clingon. So does Dilbert.
433 if (src[index1] == ':') {
434 Preconditions.checkArgument(src[++index1] == ':', "Invalid v6 address");
440 int srcLength = src.length;
442 while (index1 < srcLength) {
444 int chval = Character.digit(ch, 16);
446 /* Business as usual - ipv6 address digit.
447 * We can remove all checks from the original BSD code because
448 * the regexp has already verified that we are not being fed
449 * anything bigger than 0xffff between the separators.
464 /* no need to check separator position validity - regexp does that */
469 /* removed overrun check - the regexp checks for valid data */
474 /* stop parsing if we are past the mask */
478 dst[index2] = (byte) (val >> 8 & nextNibble(mask));
483 /* stop parsing if we are past the mask */
487 dst[index2] = (byte) (val & nextNibble(mask));
495 /* frankenstein - v4 attached to v6, mixed notation */
497 if (ch == '.' && index2 + INADDR4SZ <= INADDR6SZ) {
499 /* this has passed the regexp so it is fairly safe to parse it
500 * straight away. As v4 addresses do not suffer from the same
501 * defficiencies as the java v6 implementation we can invoke it
502 * straight away and be done with it
505 Preconditions.checkArgument(index2 != INADDR6SZ - INADDR4SZ - 1, "Invalid v4 in v6 mapping");
507 InetAddress inetForm = InetAddresses.forString(partsV6Prefix.get(0).substring(curtok, srcLength));
509 Preconditions.checkArgument(inetForm instanceof Inet4Address);
510 System.arraycopy(inetForm.getAddress(), 0, dst, index2, INADDR4SZ);
516 /* removed parser exit on ivalid char - no need to do it, regexp checks it */
519 Preconditions.checkArgument(index2 + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
520 dst[index2] = (byte) (val >> 8 & nextNibble(mask));
523 dst[index2] = (byte) (val & nextNibble(mask));
528 if (index2 < INADDR6SZ && mask < 0) {
530 for (index1 = index2; index1 < INADDR6SZ; index1++) {
536 int to = index2 - colonp;
538 Preconditions.checkArgument(index2 != INADDR6SZ, "Overrun in v6 parsing, should not occur");
539 for (index1 = 1; index1 <= to; index1++) {
540 dst[INADDR6SZ - index1] = dst[colonp + to - index1];
541 dst[colonp + to - index1] = 0;
545 Preconditions.checkArgument(index2 == INADDR6SZ, "Overrun in v6 parsing, should not occur");
548 dst[INADDR6SZ] = (byte) initialMask;
553 * Print a v6 prefix in byte array + 1 notation.
555 * @param binaryForm - prefix, in byte [] form, last byte is netmask
556 * @return string of v6 prefix
557 * @throws UnknownHostException unknown host exception
559 public static String byteArrayV6PrefixToString(final byte [] binaryForm) throws UnknownHostException {
560 /* NO DIY!!! - InetAddresses will actually print correct canonical
561 * zero compressed form
563 StringBuilder sb = new StringBuilder();
564 /* Yang RFC specifies that the normalized form is RFC 5952, note - java
565 * core type is not RFC compliant, guava is.
568 InetAddresses.toAddrString(
569 InetAddress.getByAddress(
570 Arrays.copyOf(binaryForm, INADDR6SZ)
575 sb.append(binaryForm[INADDR6SZ] & 0xff);
576 return sb.toString();
580 * Check if the supplied IPv6Address has any prefix.
582 * @param ipv6Prefix Ipv6 prefix
583 * @return prefix if there is one, else null
585 public static Integer hasIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
586 final int prefix = IpConversionUtil.extractIpv6Prefix(ipv6Prefix);
587 return prefix < IPV6_ADDRESS_LENGTH ? prefix : null;
590 private static int ipv6PrefixByteArrayOffset(final int mask) {
595 final int ret = mask * INADDR6SZ;
596 if (ret < PREFIX_BYTEARRAYS.length) {
599 return PREFIX_BYTEARRAYS.length - INADDR6SZ;
604 * Canonicalize a v6 prefix while in binary form.
606 * @param prefix - prefix, in byte [] form
607 * @param mask - mask - number of bits
609 public static void canonicalizeIpv6Prefix(final byte [] prefix, final int mask) {
610 final int offset = ipv6PrefixByteArrayOffset(mask);
612 for (int i = 0; i < INADDR6SZ; i++) {
613 prefix[i] &= PREFIX_BYTEARRAYS[offset + i];
617 public static byte[] convertIpv6PrefixToByteArray(final int prefix) {
618 final int offset = ipv6PrefixByteArrayOffset(prefix);
620 return Arrays.copyOfRange(PREFIX_BYTEARRAYS, offset, offset + INADDR6SZ);
623 public static Ipv6Address extractIpv6Address(final Ipv6Prefix ipv6Prefix) {
624 return IetfInetUtil.INSTANCE.ipv6AddressFrom(ipv6Prefix);
627 public static Ipv4Address extractIpv4Address(final Ipv4Prefix ipv4Prefix) {
628 return IetfInetUtil.INSTANCE.ipv4AddressFrom(ipv4Prefix);
631 public static DottedQuad extractIpv4AddressMask(final Ipv4Prefix ipv4Prefix) {
632 Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
634 Integer cidrMask = 0;
635 if (addressParts.hasNext()) {
636 cidrMask = Integer.parseInt(addressParts.next());
639 maskBits = 0xffffffff << IPV4_ADDRESS_LENGTH - cidrMask;
640 String mask = String.format("%d.%d.%d.%d", (maskBits & 0x0000000000ff000000L) >> 24,
641 (maskBits & 0x0000000000ff0000) >> 16, (maskBits & 0x0000000000ff00) >> 8, maskBits & 0xff);
642 DottedQuad netMask = new DottedQuad(mask);
647 public static Ipv6ArbitraryMask extractIpv6AddressMask(final Ipv6Prefix ipv6Prefix) {
648 Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
651 if (addressParts.hasNext()) {
652 maskLength = Integer.parseInt(addressParts.next());
654 BitSet ipmask = new BitSet(128);
655 ipmask.set(0,maskLength,true);
656 ipmask.set(maskLength + 1,128,false);
657 byte[] finalmask = new byte[16];
658 System.arraycopy(ipmask.toByteArray(),0,finalmask,0,ipmask.toByteArray().length);
659 InetAddress inetAddress = null;
661 inetAddress = InetAddress.getByAddress(finalmask);
662 } catch (UnknownHostException e) {
663 LOG.error("Failed to convert the Ipv6 subnetmask from integer to mask value ", e);
666 return new Ipv6ArbitraryMask(inetAddress.getHostAddress());
669 public static Integer extractIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
670 return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
673 public static int countBits(final byte[] mask) {
675 for (byte b : mask) {
676 netmask += Integer.bitCount(UnsignedBytes.toInt(b));
682 @SuppressFBWarnings("PZLA_PREFER_ZERO_LENGTH_ARRAYS")
683 public static byte[] convertArbitraryMaskToByteArray(final DottedQuad mask) {
685 if (mask != null && mask.getValue() != null) {
686 maskValue = mask.getValue();
688 maskValue = DEFAULT_ARBITRARY_BIT_MASK;
690 InetAddress maskInIpFormat = null;
692 maskInIpFormat = InetAddress.getByName(maskValue);
693 } catch (UnknownHostException e) {
694 LOG.error("Failed to resolve the ip address of the mask ", e);
697 byte[] bytes = maskInIpFormat.getAddress();
701 public static boolean isArbitraryBitMask(final byte[] byteMask) {
702 if (byteMask == null) {
705 ArrayList<Integer> integerMaskArrayList = new ArrayList<>();
707 // converting byte array to bits
708 maskInBits = new BigInteger(1, byteMask).toString(2);
709 ArrayList<String> stringMaskArrayList = new ArrayList<>(Arrays.asList(maskInBits.split("(?!^)")));
710 for (String string:stringMaskArrayList) {
711 integerMaskArrayList.add(Integer.parseInt(string));
713 return checkArbitraryBitMask(integerMaskArrayList);
717 private static boolean checkArbitraryBitMask(final ArrayList<Integer> arrayList) {
718 // checks 0*1* case - Leading zeros in arrayList are truncated
719 if (arrayList.size() > 0 && arrayList.size() < IPV4_ADDRESS_LENGTH) {
723 for (int i = 0; i < arrayList.size() - 1; i++) {
724 if (arrayList.get(i) == 0 && arrayList.get(i + 1) == 1) {
733 @SuppressFBWarnings("PZLA_PREFER_ZERO_LENGTH_ARRAYS")
734 public static byte[] convertIpv6ArbitraryMaskToByteArray(final Ipv6ArbitraryMask mask) {
736 if (mask != null && mask.getValue() != null) {
737 maskValue = mask.getValue();
739 maskValue = DEFAULT_IPV6_ARBITRARY_BITMASK;
741 InetAddress maskInIpFormat = null;
743 maskInIpFormat = InetAddress.getByName(maskValue);
744 } catch (UnknownHostException e) {
745 LOG.error("Failed to convert mask string to ipv6 format mask ",e);
748 return maskInIpFormat.getAddress();
751 public static boolean isIpv6ArbitraryBitMask(final byte[] byteMask) {
752 if (byteMask == null) {
755 ArrayList<Integer> integerMaskArrayList = new ArrayList<>();
757 // converting byte array to bits
758 maskInBits = new BigInteger(1, byteMask).toString(2);
759 ArrayList<String> stringMaskArrayList = new ArrayList<>(Arrays.asList(maskInBits.split("(?!^)")));
760 for (String string:stringMaskArrayList) {
761 integerMaskArrayList.add(Integer.parseInt(string));
763 return checkIpv6ArbitraryBitMask(integerMaskArrayList);
767 private static boolean checkIpv6ArbitraryBitMask(final ArrayList<Integer> arrayList) {
768 // checks 0*1* case - Leading zeros in arrayList are truncated
769 if (arrayList.size() > 0 && arrayList.size() < IPV6_ADDRESS_LENGTH) {
773 for (int i = 0; i < arrayList.size() - 1; i++) {
774 if (arrayList.get(i) == 0 && arrayList.get(i + 1) == 1) {
782 private static String compressedIpv6FormatFromString(final String ipv6Address) {
784 return byteArrayV6AddressToString(canonicalBinaryV6AddressFromString(ipv6Address));
785 } catch (UnknownHostException e) {
786 LOG.warn("Failed to compress IPv6 address {} because it is invalid", ipv6Address);
791 public static Ipv6Address compressedIpv6AddressFormat(final Ipv6Address ipv6Address) {
792 return new Ipv6Address(compressedIpv6FormatFromString(ipv6Address.getValue()));
795 public static Ipv6ArbitraryMask compressedIpv6MaskFormat(final Ipv6ArbitraryMask ipv6Mask) {
796 return new Ipv6ArbitraryMask(compressedIpv6FormatFromString(ipv6Mask.getValue()));