2 * Copyright (c) 2015 Cisco Systems, Inc., Brocade, Communications 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
9 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
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;
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;
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
44 public final class IpConversionUtil {
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";
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.
62 private static final byte[] PREFIX_BYTEARRAYS;
64 final byte[] a = new byte[(INADDR6SZ * Byte.SIZE + 1) * INADDR6SZ];
67 for (int p = 0; p <= INADDR6SZ * Byte.SIZE; ++p) {
69 for (int i = 0; i < INADDR6SZ; ++i) {
70 a[offset++] = (byte) nextNibble(prefix);
75 PREFIX_BYTEARRAYS = a;
78 private IpConversionUtil() {
79 throw new UnsupportedOperationException("This class should not be instantiated.");
82 public static Iterator<String> splitToParts(final Ipv4Prefix ipv4Prefix) {
83 return PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
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));
91 public static Iterator<String> splitToParts(final Ipv6Prefix ipv6Prefix) {
92 return PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
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));
100 /* This forest of functions has a purpose:
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.
111 public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address){
112 return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address);
115 public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final String mask){
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!!!
122 if (null != mask && !mask.isEmpty()) {
123 return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
125 return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
129 public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final int intmask){
130 return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, intmask);
133 public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final byte [] bytemask){
134 return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, countBits(bytemask));
137 public static DottedQuad createArbitraryBitMask(final byte [] bitmask) {
138 DottedQuad dottedQuad = null;
139 if (bitmask == null ) {
140 dottedQuad = new DottedQuad(DEFAULT_ARBITRARY_BIT_MASK);
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);
151 public static Ipv6ArbitraryMask createIpv6ArbitraryBitMask(final byte [] bitmask) {
152 Ipv6ArbitraryMask ipv6ArbitraryMask = null;
153 if (bitmask == null ) {
154 ipv6ArbitraryMask = new Ipv6ArbitraryMask(DEFAULT_IPV6_ARBITRARY_BITMASK);
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);
162 return ipv6ArbitraryMask;
165 public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address){
166 return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address);
169 public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final String mask){
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!!!
176 if (Strings.isNullOrEmpty(mask)) {
177 return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + String.valueOf(IPV6_ADDRESS_LENGTH));
179 return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
183 public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final int intmask){
184 return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, intmask);
187 public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final byte [] bytemask){
188 return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, countBits(bytemask));
191 public static Integer extractPrefix(final Ipv4Prefix ipv4Prefix) {
192 return IetfInetUtil.INSTANCE.splitIpv4Prefix(ipv4Prefix).getValue();
195 public static Integer extractPrefix(final Ipv6Prefix ipv6Prefix) {
196 return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
199 public static Integer extractPrefix(final Ipv4Address ipv4Prefix) {
200 return IPV4_ADDRESS_LENGTH;
203 public static Integer extractPrefix(final Ipv6Address ipv6Prefix) {
209 * Read all of the following before you touch any v6 code or decide to
210 * optimize it by invoking a "simple" Guava call
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
219 * This is why we have to parse v6 by ourselves.
221 * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
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.
232 * Convert Ipv6Address object to a valid Canonical v6 address in byte format
234 * @param ipv6Address - v6 Address object
235 * @return - byte array of size 16. Last byte contains netmask
239 public static byte[] canonicalBinaryV6Address(final Ipv6Address ipv6Address) {
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()
246 Iterable<String> splittedV6Address = Splitter.on("%")
249 .split(ipv6Address.getValue());
250 List<String> partsV6Address = Lists.newArrayList(splittedV6Address.iterator());
256 /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
260 char[] src = partsV6Address.get(0).toCharArray();
262 byte[] dst = new byte[INADDR6SZ];
264 int src_length = src.length;
269 /* Leading :: requires some special handling. */
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.
277 Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
285 while (i < src_length) {
287 int chval = Character.digit(ch, 16);
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.
307 /* no need to check separator position validity - regexp does that */
312 /* removed overrun check - the regexp checks for valid data */
314 dst[j++] = (byte) ((val >>> 8) & 0xff);
315 dst[j++] = (byte) (val & 0xff);
321 /* frankenstein - v4 attached to v6, mixed notation */
323 if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
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
331 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
333 InetAddress _inet_form = InetAddresses.forString(partsV6Address.get(0).substring(curtok, src_length));
335 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
336 System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
342 /* removed parser exit on invalid char - no need to do it, regexp checks it */
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);
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;
361 Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
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.
370 return InetAddresses.toAddrString(InetAddress.getByAddress(_binary_form));
373 private static int nextNibble(final int mask) {
380 return 0xff << (8 - mask);
384 * Convert Ipv6Prefix object to a valid Canonical v6 prefix in byte format
386 * @param ipv6Prefix - v6 prefix object
387 * @return - byte array of size 16 + 1. Last byte contains netmask
389 public static byte[] canonicalBinaryV6Prefix(final Ipv6Prefix ipv6Prefix) {
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()
398 Iterable<String> splittedV6Prefix = Splitter.on("/")
401 .split(ipv6Prefix.getValue());
402 List<String> partsV6Prefix = Lists.newArrayList(splittedV6Prefix.iterator());
404 boolean valid = true;
407 mask = Integer.parseInt(partsV6Prefix.get(1));
411 } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
415 Preconditions.checkArgument(valid, "Supplied netmask in %s is invalid", ipv6Prefix.getValue());
422 /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
426 char[] src = partsV6Prefix.get(0).toCharArray();
428 byte[] dst = new byte[INADDR6SZ + 1];
432 int src_length = src.length;
437 /* Leading :: requires some special handling. */
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.
445 Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
453 while (i < src_length) {
455 int chval = Character.digit(ch, 16);
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.
475 /* no need to check separator position validity - regexp does that */
480 /* removed overrun check - the regexp checks for valid data */
485 /* stop parsing if we are past the mask */
489 dst[j] = (byte) ((val >> 8) & nextNibble(m)); j++; m = m - 8;
492 /* stop parsing if we are past the mask */
496 dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
502 /* frankenstein - v4 attached to v6, mixed notation */
504 if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
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
512 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
514 InetAddress _inet_form = InetAddresses.forString(partsV6Prefix.get(0).substring(curtok, src_length));
516 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
517 System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
523 /* removed parser exit on ivalid char - no need to do it, regexp checks it */
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;
531 if ((j < INADDR6SZ) && (m < 0)) {
533 for (i = j; i < INADDR6SZ; i++) {
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;
548 Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
551 dst[INADDR6SZ] = (byte) mask;
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
561 public static String byteArrayV6PrefixToString(final byte [] _binary_form) throws UnknownHostException {
562 /* NO DIY!!! - InetAddresses will actually print correct canonical
563 * zero compressed form
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.
570 InetAddresses.toAddrString(
571 InetAddress.getByAddress(
572 Arrays.copyOf(_binary_form, INADDR6SZ)
577 sb.append(_binary_form[INADDR6SZ] & 0xff);
578 return sb.toString();
581 private static int ipv6PrefixByteArrayOffset(final int mask) {
586 final int ret = mask * INADDR6SZ;
587 if (ret < PREFIX_BYTEARRAYS.length) {
590 return PREFIX_BYTEARRAYS.length - INADDR6SZ;
595 * Canonicalize a v6 prefix while in binary form
597 * @param prefix - prefix, in byte [] form
598 * @param mask - mask - number of bits
600 public static void canonicalizeIpv6Prefix(final byte [] prefix, final int mask) {
601 final int offset = ipv6PrefixByteArrayOffset(mask);
603 for (int i = 0; i < INADDR6SZ; i++) {
604 prefix[i] &= PREFIX_BYTEARRAYS[offset + i];
608 public static byte[] convertIpv6PrefixToByteArray(final int prefix) {
609 final int offset = ipv6PrefixByteArrayOffset(prefix);
611 return Arrays.copyOfRange(PREFIX_BYTEARRAYS, offset, offset + INADDR6SZ);
614 public static Ipv6Address extractIpv6Address(final Ipv6Prefix ipv6Prefix) {
615 return IetfInetUtil.INSTANCE.ipv6AddressFrom(ipv6Prefix);
618 public static Ipv4Address extractIpv4Address(final Ipv4Prefix ipv4Prefix) {
619 Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
620 return new Ipv4Address(addressParts.next());
623 public static DottedQuad extractIpv4AddressMask(final Ipv4Prefix ipv4Prefix) {
624 Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
627 if (addressParts.hasNext()) {
628 cidrMask = Integer.parseInt(addressParts.next());
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);
637 public static Ipv6ArbitraryMask extractIpv6AddressMask(final Ipv6Prefix ipv6Prefix) {
638 Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
641 if (addressParts.hasNext()) {
642 maskLength = Integer.parseInt(addressParts.next());
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;
651 inetAddress = InetAddress.getByAddress(finalmask);
652 } catch (UnknownHostException e) {
653 LOG.error("Failed to convert the Ipv6 subnetmask from integer to mask value ", e);
655 return new Ipv6ArbitraryMask(inetAddress.getHostAddress());
658 public static Integer extractIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
659 return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
662 public static int countBits(final byte[] mask) {
664 for (byte b : mask) {
665 netmask += Integer.bitCount(UnsignedBytes.toInt(b));
670 public static final byte[] convertArbitraryMaskToByteArray(DottedQuad mask) {
672 if (mask != null && mask.getValue() != null) {
673 maskValue = mask.getValue();
675 maskValue = DEFAULT_ARBITRARY_BIT_MASK;
677 InetAddress maskInIpFormat = null;
679 maskInIpFormat = InetAddress.getByName(maskValue);
680 } catch (UnknownHostException e) {
681 LOG.error ("Failed to resolve the ip address of the mask ",e);
683 byte[] bytes = maskInIpFormat.getAddress();
687 public static boolean isArbitraryBitMask(byte[] byteMask) {
688 if (byteMask == null) {
691 ArrayList<Integer> integerMaskArrayList = new ArrayList<Integer>();
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));
699 return checkArbitraryBitMask(integerMaskArrayList);
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) {
709 for (int i=0; i<arrayList.size()-1;i++) {
710 if (arrayList.get(i) ==0 && arrayList.get(i+1) == 1) {
718 public static final byte[] convertIpv6ArbitraryMaskToByteArray(final Ipv6ArbitraryMask mask) {
720 if (mask.getValue() != null) {
721 maskValue = mask.getValue();
723 maskValue = DEFAULT_IPV6_ARBITRARY_BITMASK;
725 InetAddress maskInIpFormat = null;
727 maskInIpFormat = InetAddress.getByName(maskValue);
728 } catch (UnknownHostException e) {
729 LOG.error ("Failed to convert mask string to ipv6 format mask ",e);
731 return maskInIpFormat.getAddress();
734 public static boolean isIpv6ArbitraryBitMask(final byte[] byteMask) {
735 if (byteMask == null) {
738 ArrayList<Integer> integerMaskArrayList = new ArrayList<Integer>();
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));
746 return checkIpv6ArbitraryBitMask(integerMaskArrayList);
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) {
756 for (int i=0; i<arrayList.size()-1;i++) {
757 if (arrayList.get(i) ==0 && arrayList.get(i+1) == 1) {
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;
771 public static Ipv6ArbitraryMask compressedIpv6MaskFormat(final Ipv6ArbitraryMask ipv6Mask) {
772 String stringIpv6Mask = ipv6Mask.getValue();
773 return new Ipv6ArbitraryMask(compressedIpv6Format(stringIpv6Mask));