Replaced IPv6 toString with more efficient local helper.

Change-Id: Ib53d7bdf64354efcace7facad740981fce19447c
diff --git a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
index 5da34b4..5b39286 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
@@ -18,21 +18,20 @@
 import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
-import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Objects;
-
 import com.google.common.net.InetAddresses;
 import com.google.common.primitives.UnsignedBytes;
 
-import static com.google.common.base.Preconditions.checkState;
 
 /**
  * A class representing an IP address.
  * This class is immutable.
  */
 public class IpAddress implements Comparable<IpAddress> {
+    private static final int BIT_MASK = 0x000000ff;
+
     // IP Versions
     public enum Version { INET, INET6 };
 
@@ -353,20 +352,12 @@
         switch (version) {
             case INET:
                 return String.format("%d.%d.%d.%d", octets[0] & 0xff,
-                                                    octets[1] & 0xff,
-                                                    octets[2] & 0xff,
-                                                    octets[3] & 0xff);
+                        octets[1] & 0xff,
+                        octets[2] & 0xff,
+                        octets[3] & 0xff);
             case INET6:
             default:
-                InetAddress inetAddr = null;
-                try {
-                    inetAddr = InetAddress.getByAddress(octets);
-                } catch (UnknownHostException e) {
-                    // Should never happen
-                    checkState(false, "Internal error: Ip6Address.toString()");
-                    return "[Invalid IP Address]";
-                }
-                return InetAddresses.toAddrString(inetAddr);
+                return ipv6ToStringHelper();
         }
     }
 
@@ -494,4 +485,66 @@
         }
         return net;
     }
+
+    /**
+     * Creates a string based on the IPv6 recommendations for canonical representations found here:
+     * https://tools.ietf.org/html/rfc5952#section-1.
+     * @return A properly formatted IPv6 canonical representation.
+     */
+    private String ipv6ToStringHelper() {
+        //Populate a buffer with the string of the full address with leading zeros stripped
+        StringBuffer buff = new StringBuffer();
+        buff.append(String.format("%x:%x:%x:%x:%x:%x:%x:%x",
+                (((octets[0] & BIT_MASK) << 8) | (octets[1] & BIT_MASK)),
+                (((octets[2] & BIT_MASK) << 8) | (octets[3] & BIT_MASK)),
+                (((octets[4] & BIT_MASK) << 8) | (octets[5] & BIT_MASK)),
+                (((octets[6] & BIT_MASK) << 8) | (octets[7] & BIT_MASK)),
+                (((octets[8] & BIT_MASK) << 8) | (octets[9] & BIT_MASK)),
+                (((octets[10] & BIT_MASK) << 8) | (octets[11] & BIT_MASK)),
+                (((octets[12] & BIT_MASK) << 8) | (octets[13] & BIT_MASK)),
+                (((octets[14] & BIT_MASK) << 8) | (octets[15] & BIT_MASK))));
+        //Initialize variables for tracking longest zero subsequence, tiebreaking by first occurence
+        int longestSeqStart, longestSeqLen, currSeqStart, currSeqLen;
+        longestSeqStart = 0;
+        longestSeqLen = 0;
+        currSeqStart = 0;
+        currSeqLen = 0;
+
+        for (int index = 0; index < buff.length(); index++) {
+            if (buff.charAt(index) == ':') {
+                if (currSeqLen != 0 && buff.charAt(index + 1) == '0') {
+                    currSeqLen += 1;
+                }
+            } else if (buff.charAt(index) == '0' && ((index == 0) || (buff.charAt(index - 1) == ':'))) {
+                if (currSeqLen == 0) {
+                    currSeqStart = index;
+                }
+                currSeqLen += 1;
+            } else {
+                 if (currSeqLen > longestSeqLen) {
+                     longestSeqStart = currSeqStart;
+                     longestSeqLen = currSeqLen;
+                }
+                currSeqLen = 0;
+            }
+        }
+
+        if (currSeqLen > longestSeqLen) {
+            longestSeqLen = currSeqLen;
+            longestSeqStart = currSeqStart;
+        }
+        if (longestSeqLen > 1) {
+            if (buff.length() == (longestSeqStart + longestSeqLen)) {
+                buff.append(':');
+            }
+
+            buff.delete(longestSeqStart, longestSeqStart + longestSeqLen);
+
+            if (longestSeqStart == 0) {
+                buff.insert(0, ':');
+            }
+        }
+
+    return buff.toString();
+    }
 }
diff --git a/utils/misc/src/test/java/org/onlab/packet/IpAddressTest.java b/utils/misc/src/test/java/org/onlab/packet/IpAddressTest.java
index 7a18ec5..003982a 100644
--- a/utils/misc/src/test/java/org/onlab/packet/IpAddressTest.java
+++ b/utils/misc/src/test/java/org/onlab/packet/IpAddressTest.java
@@ -896,5 +896,40 @@
             IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
         assertThat(ipAddress.toString(),
                    is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
+
+        ipAddress =
+                IpAddress.valueOf("::1111:2222");
+        assertThat(ipAddress.toString(),
+                is("::1111:2222"));
+
+        ipAddress =
+                IpAddress.valueOf("1:0:0:1:0:0:2:3");
+        assertThat(ipAddress.toString(),
+                is("1::1:0:0:2:3"));
+
+        ipAddress =
+                IpAddress.valueOf("::0123:0004");
+        assertThat(ipAddress.toString(),
+                is("::123:4"));
+
+        ipAddress =
+                IpAddress.valueOf("0:0:1:1:0:0:1:1");
+        assertThat(ipAddress.toString(),
+                is("::1:1:0:0:1:1"));
+
+        ipAddress =
+                IpAddress.valueOf("1:1a2b::");
+        assertThat(ipAddress.toString(),
+                is("1:1a2b::"));
+
+        ipAddress =
+                IpAddress.valueOf("0:0:00:00:0000:00:00:000");
+        assertThat(ipAddress.toString(),
+                is("::"));
+
+        ipAddress =
+                IpAddress.valueOf("0:0:0:1:0:0:0:0");
+        assertThat(ipAddress.toString(),
+                is("0:0:0:1::"));
     }
 }