blob: fee04ac1b64b323097a97b3f98b2b572a89fe264 [file] [log] [blame]
Yotam Harcholf3f11152013-09-05 16:47:16 -07001package org.projectfloodlight.openflow.types;
2
Ronald Licc9c9302014-07-07 00:58:56 -07003import java.net.Inet6Address;
4import java.net.InetAddress;
Andreas Wundsam5f71b412014-02-18 12:56:35 -08005import java.util.Arrays;
Yotam Harcholf3f11152013-09-05 16:47:16 -07006import java.util.regex.Pattern;
7
Andreas Wundsam3700d162014-03-11 04:43:38 -07008import javax.annotation.Nonnull;
9
Yotam Harcholf3f11152013-09-05 16:47:16 -070010import org.jboss.netty.buffer.ChannelBuffer;
Andreas Wundsam5f71b412014-02-18 12:56:35 -080011
Sovietaced9dfc1ef2014-06-27 11:13:57 -070012import com.google.common.base.Preconditions;
Andreas Wundsam22ba3af2013-10-04 16:00:30 -070013import com.google.common.hash.PrimitiveSink;
Ronald Li9d777a52015-02-07 06:19:29 -080014import com.google.common.primitives.UnsignedLongs;
Andreas Wundsam85c961f2013-09-29 21:22:12 -070015
Byungjoon Leeba92e292014-07-18 13:13:26 +090016import org.projectfloodlight.openflow.protocol.Writeable;
17import org.projectfloodlight.openflow.protocol.OFMessageReader;
18import org.projectfloodlight.openflow.exceptions.OFParseError;
19
Yotam Harcholf3f11152013-09-05 16:47:16 -070020/**
21 * IPv6 address object. Instance controlled, immutable. Internal representation:
22 * two 64 bit longs (not that you'd have to know).
23 *
kjwon157bc85402015-02-12 15:07:42 +090024 * @author Andreas Wundsam {@literal <}andreas.wundsam@teleteach.de{@literal >}
Yotam Harcholf3f11152013-09-05 16:47:16 -070025 */
Byungjoon Leeba92e292014-07-18 13:13:26 +090026public class IPv6Address extends IPAddress<IPv6Address> implements Writeable {
Yotam Harcholf3f11152013-09-05 16:47:16 -070027 static final int LENGTH = 16;
28 private final long raw1;
29 private final long raw2;
30
Gregor Maier1acb4502013-12-12 11:25:07 -080031 private static final int NOT_A_CIDR_MASK = -1;
32 private static final int CIDR_MASK_CACHE_UNSET = -2;
Gregor Maier5615b6c2013-12-11 22:29:07 -080033 // Must appear before the static IPv4Address constant assignments
34 private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
35
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070036 private final static long NONE_VAL1 = 0x0L;
37 private final static long NONE_VAL2 = 0x0L;
38 public static final IPv6Address NONE = new IPv6Address(NONE_VAL1, NONE_VAL2);
39
Gregor Maier5615b6c2013-12-11 22:29:07 -080040
Yotam Harchola289d552013-09-16 10:10:40 -070041 public static final IPv6Address NO_MASK = IPv6Address.of(0xFFFFFFFFFFFFFFFFl, 0xFFFFFFFFFFFFFFFFl);
42 public static final IPv6Address FULL_MASK = IPv6Address.of(0x0, 0x0);
Yotam Harcholf3f11152013-09-05 16:47:16 -070043
Yotam Harchola289d552013-09-16 10:10:40 -070044 private IPv6Address(final long raw1, final long raw2) {
Yotam Harcholf3f11152013-09-05 16:47:16 -070045 this.raw1 = raw1;
46 this.raw2 = raw2;
47 }
48
Byungjoon Leeba92e292014-07-18 13:13:26 +090049 public final static Reader READER = new Reader();
50
51 private static class Reader implements OFMessageReader<IPv6Address> {
52 @Override
53 public IPv6Address readFrom(ChannelBuffer bb) throws OFParseError {
54 return new IPv6Address(bb.readLong(), bb.readLong());
55 }
56 }
57
Yotam Harchol4d634682013-09-26 13:21:06 -070058 @Override
Yotam Harcholeb023dc2013-09-26 15:45:44 -070059 public IPVersion getIpVersion() {
60 return IPVersion.IPv6;
Yotam Harchol4d634682013-09-26 13:21:06 -070061 }
62
Gregor Maier7f987e62013-12-10 19:34:18 -080063
Gregor Maier5615b6c2013-12-11 22:29:07 -080064 private int computeCidrMask64(long raw) {
65 long mask = raw;
66 if (raw == 0)
67 return 0;
Gregor Maier1acb4502013-12-12 11:25:07 -080068 else if (Long.bitCount((~mask) + 1) == 1) {
Gregor Maier5615b6c2013-12-11 22:29:07 -080069 // represent a true CIDR prefix length
70 return Long.bitCount(mask);
71 }
72 else {
73 // Not a true prefix
74 return NOT_A_CIDR_MASK;
75 }
76 }
77
78 private int asCidrMaskLengthInternal() {
79 if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
Gregor Maier1acb4502013-12-12 11:25:07 -080080 // No synchronization needed. Writing cidrMaskLengthCache only once
81 if (raw1 == 0 && raw2 == 0) {
82 cidrMaskLengthCache = 0;
83 } else if (raw1 == -1L) {
84 // top half is all 1 bits
85 int tmpLength = computeCidrMask64(raw2);
86 if (tmpLength != NOT_A_CIDR_MASK)
87 tmpLength += 64;
88 cidrMaskLengthCache = tmpLength;
89 } else if (raw2 == 0) {
90 cidrMaskLengthCache = computeCidrMask64(raw1);
91 } else {
92 cidrMaskLengthCache = NOT_A_CIDR_MASK;
Gregor Maier5615b6c2013-12-11 22:29:07 -080093 }
94 }
95 return cidrMaskLengthCache;
96 }
97
98 @Override
99 public boolean isCidrMask() {
100 return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
101 }
102
Gregor Maier7f987e62013-12-10 19:34:18 -0800103 @Override
104 public int asCidrMaskLength() {
Gregor Maier5615b6c2013-12-11 22:29:07 -0800105 if (!isCidrMask()) {
106 throw new IllegalStateException("IP is not a valid CIDR prefix " +
107 "mask " + toString());
Gregor Maier7f987e62013-12-10 19:34:18 -0800108 } else {
Gregor Maier5615b6c2013-12-11 22:29:07 -0800109 return asCidrMaskLengthInternal();
Gregor Maier7f987e62013-12-10 19:34:18 -0800110 }
111 }
112
Aditya Vaja56b8b182014-03-11 13:13:58 -0700113 @Override
114 public boolean isBroadcast() {
115 return this.equals(NO_MASK);
116 }
117
nsongd7701e12015-05-13 10:34:26 -0700118 /**
nsongc19db2c2015-05-14 13:55:15 -0700119 * IPv6 multicast addresses are defined by the prefix ff00::/8
nsongd7701e12015-05-13 10:34:26 -0700120 */
121 @Override
122 public boolean isMulticast() {
123 return (raw1 >>> 56) == 0xFFL;
124 }
125
Aditya Vaja56b8b182014-03-11 13:13:58 -0700126 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -0700127 public IPv6Address and(IPv6Address other) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700128 Preconditions.checkNotNull(other, "other must not be null");
129
130 IPv6Address otherIp = other;
Aditya Vaja56b8b182014-03-11 13:13:58 -0700131 return IPv6Address.of((raw1 & otherIp.raw1), (raw2 & otherIp.raw2));
132 }
133
134 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -0700135 public IPv6Address or(IPv6Address other) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700136 Preconditions.checkNotNull(other, "other must not be null");
137
138 IPv6Address otherIp = other;
Aditya Vaja56b8b182014-03-11 13:13:58 -0700139 return IPv6Address.of((raw1 | otherIp.raw1), (raw2 | otherIp.raw2));
140 }
141
142 @Override
143 public IPv6Address not() {
144 return IPv6Address.of(~raw1, ~raw2);
145 }
146
Ronald Licc9c9302014-07-07 00:58:56 -0700147 /**
148 * Returns an {@code IPv6Address} object that represents the given
149 * IP address. The argument is in network byte order: the highest
150 * order byte of the address is in {@code address[0]}.
151 * <p>
152 * The address byte array must be 16 bytes long (128 bits long).
153 * <p>
154 * Similar to {@link InetAddress#getByAddress(byte[])}.
155 *
156 * @param address the raw IP address in network byte order
157 * @return an {@code IPv6Address} object that represents the given
158 * raw IP address
159 * @throws NullPointerException if the given address was {@code null}
160 * @throws IllegalArgumentException if the given address was of an invalid
161 * byte array length
162 * @see InetAddress#getByAddress(byte[])
163 */
164 @Nonnull
165 public static IPv6Address of(@Nonnull final byte[] address) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700166 Preconditions.checkNotNull(address, "address must not be null");
167
Yotam Harcholf3f11152013-09-05 16:47:16 -0700168 if (address.length != LENGTH) {
169 throw new IllegalArgumentException(
Andreas Wundsamc85b5c52013-09-24 13:01:43 -0700170 "Invalid byte array length for IPv6 address: " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700171 }
172
173 long raw1 =
174 (address[0] & 0xFFL) << 56 | (address[1] & 0xFFL) << 48
175 | (address[2] & 0xFFL) << 40 | (address[3] & 0xFFL) << 32
176 | (address[4] & 0xFFL) << 24 | (address[5] & 0xFFL) << 16
Ronald Lib90552c2015-05-15 16:03:32 -0700177 | (address[6] & 0xFFL) << 8 | (address[7] & 0xFFL);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700178
179 long raw2 =
180 (address[8] & 0xFFL) << 56 | (address[9] & 0xFFL) << 48
181 | (address[10] & 0xFFL) << 40 | (address[11] & 0xFFL) << 32
182 | (address[12] & 0xFFL) << 24 | (address[13] & 0xFFL) << 16
Ronald Lib90552c2015-05-15 16:03:32 -0700183 | (address[14] & 0xFFL) << 8 | (address[15] & 0xFFL);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700184
Yotam Harchola289d552013-09-16 10:10:40 -0700185 return IPv6Address.of(raw1, raw2);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700186 }
187
188 private static class IPv6Builder {
189 private long raw1, raw2;
190
191 public void setUnsignedShortWord(final int i, final int value) {
192 int shift = 48 - (i % 4) * 16;
193
194 if (value < 0 || value > 0xFFFF)
195 throw new IllegalArgumentException("16 bit word must be in [0, 0xFFFF]");
196
197 if (i >= 0 && i < 4)
198 raw1 = raw1 & ~(0xFFFFL << shift) | (value & 0xFFFFL) << shift;
199 else if (i >= 4 && i < 8)
200 raw2 = raw2 & ~(0xFFFFL << shift) | (value & 0xFFFFL) << shift;
201 else
202 throw new IllegalArgumentException("16 bit word index must be in [0,7]");
203 }
204
Yotam Harchola289d552013-09-16 10:10:40 -0700205 public IPv6Address getIPv6() {
206 return IPv6Address.of(raw1, raw2);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700207 }
208 }
209
210 private final static Pattern colonPattern = Pattern.compile(":");
211
Ronald Licc9c9302014-07-07 00:58:56 -0700212 /**
213 * Returns an {@code IPv6Address} object that represents the given
214 * IP address. The argument is in the conventional string representation
215 * of IPv6 addresses.
216 * <p>
217 * Expects up to 8 groups of 16-bit hex words seperated by colons
218 * (e.g., 2001:db8:85a3:8d3:1319:8a2e:370:7348).
219 * <p>
220 * Supports zero compression (e.g., 2001:db8::7348).
221 * Does <b>not</b> currently support embedding a dotted-quad IPv4 address
222 * into the IPv6 address (e.g., 2001:db8::192.168.0.1).
Andreas Wundsam3700d162014-03-11 04:43:38 -0700223 *
Ronald Licc9c9302014-07-07 00:58:56 -0700224 * @param string the IP address in the conventional string representation
225 * of IPv6 addresses
226 * @return an {@code IPv6Address} object that represents the given
227 * IP address
228 * @throws NullPointerException if the given string was {@code null}
229 * @throws IllegalArgumentException if the given string was not a valid
230 * IPv6 address
Andreas Wundsam3700d162014-03-11 04:43:38 -0700231 */
232 @Nonnull
233 public static IPv6Address of(@Nonnull final String string) throws IllegalArgumentException {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700234 Preconditions.checkNotNull(string, "string must not be null");
235
Rich Lanebae30f92014-08-27 12:13:20 -0700236 // remove the zone id
237 int zoneDelimIndex = string.indexOf("%");
Rich Lane449664c2014-09-19 13:01:49 -0700238 String substring;
Rich Lanebae30f92014-08-27 12:13:20 -0700239 if (zoneDelimIndex != -1) {
240 substring = string.substring(0, zoneDelimIndex);
241 } else {
242 substring = string;
243 }
244
Yotam Harcholf3f11152013-09-05 16:47:16 -0700245 IPv6Builder builder = new IPv6Builder();
Rich Lanebae30f92014-08-27 12:13:20 -0700246 String[] parts = colonPattern.split(substring, -1);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700247
248 int leftWord = 0;
249 int leftIndex = 0;
250
251 boolean hitZeroCompression = false;
252
253 for (leftIndex = 0; leftIndex < parts.length; leftIndex++) {
254 String part = parts[leftIndex];
255 if (part.length() == 0) {
256 // hit empty group of zero compression
257 hitZeroCompression = true;
258 break;
259 }
260 builder.setUnsignedShortWord(leftWord++, Integer.parseInt(part, 16));
261 }
262
263 if (hitZeroCompression) {
264 if (leftIndex == 0) {
265 // if colon is at the start, two columns must be at the start,
266 // move to the second empty group
267 leftIndex = 1;
268 if (parts.length < 2 || parts[1].length() > 0)
269 throw new IllegalArgumentException("Malformed IPv6 address: " + string);
270 }
271
272 int rightWord = 7;
273 int rightIndex;
274 for (rightIndex = parts.length - 1; rightIndex > leftIndex; rightIndex--) {
275 String part = parts[rightIndex];
276 if (part.length() == 0)
277 break;
278 builder.setUnsignedShortWord(rightWord--, Integer.parseInt(part, 16));
279 }
280 if (rightIndex == parts.length - 1) {
281 // if colon is at the end, two columns must be at the end, move
282 // to the second empty group
283 if (rightIndex < 1 || parts[rightIndex - 1].length() > 0)
284 throw new IllegalArgumentException("Malformed IPv6 address: " + string);
285 rightIndex--;
286 }
287 if (leftIndex != rightIndex)
288 throw new IllegalArgumentException("Malformed IPv6 address: " + string);
289 } else {
290 if (leftIndex != 8) {
291 throw new IllegalArgumentException("Malformed IPv6 address: " + string);
292 }
293 }
294 return builder.getIPv6();
295 }
296
Ronald Licc9c9302014-07-07 00:58:56 -0700297 /**
298 * Returns an {@code IPv6Address} object that represents the given
299 * IP address. The arguments are the two 64-bit integers representing
300 * the first (higher-order) and second (lower-order) 64-bit blocks
301 * of the IP address.
Andreas Wundsam3700d162014-03-11 04:43:38 -0700302 *
Ronald Licc9c9302014-07-07 00:58:56 -0700303 * @param raw1 the first (higher-order) 64-bit block of the IP address
304 * @param raw2 the second (lower-order) 64-bit block of the IP address
305 * @return an {@code IPv6Address} object that represents the given
306 * raw IP address
Andreas Wundsam3700d162014-03-11 04:43:38 -0700307 */
Ronald Licc9c9302014-07-07 00:58:56 -0700308 @Nonnull
Yotam Harchola289d552013-09-16 10:10:40 -0700309 public static IPv6Address of(final long raw1, final long raw2) {
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -0700310 if(raw1==NONE_VAL1 && raw2 == NONE_VAL2)
311 return NONE;
Yotam Harchola289d552013-09-16 10:10:40 -0700312 return new IPv6Address(raw1, raw2);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700313 }
314
Ronald Licc9c9302014-07-07 00:58:56 -0700315 /**
316 * Returns an {@code IPv6Address} object that represents the given
317 * IP address. The argument is given as an {@code Inet6Address} object.
318 *
319 * @param address the IP address as an {@code Inet6Address} object
320 * @return an {@code IPv6Address} object that represents the
321 * given IP address
322 * @throws NullPointerException if the given {@code Inet6Address} was
323 * {@code null}
324 */
325 @Nonnull
326 public static IPv6Address of(@Nonnull final Inet6Address address) {
327 Preconditions.checkNotNull(address, "address must not be null");
328 return IPv6Address.of(address.getAddress());
329 }
330
331 /**
332 * Returns an {@code IPv6Address} object that represents the
333 * CIDR subnet mask of the given prefix length.
334 *
335 * @param cidrMaskLength the prefix length of the CIDR subnet mask
336 * (i.e. the number of leading one-bits),
337 * where {@code 0 <= cidrMaskLength <= 128}
338 * @return an {@code IPv6Address} object that represents the
339 * CIDR subnet mask of the given prefix length
340 * @throws IllegalArgumentException if the given prefix length was invalid
341 */
342 @Nonnull
343 public static IPv6Address ofCidrMaskLength(final int cidrMaskLength) {
Ronald Lifea17892014-07-03 18:36:06 -0700344 Preconditions.checkArgument(
345 cidrMaskLength >= 0 && cidrMaskLength <= 128,
346 "Invalid IPv6 CIDR mask length: %s", cidrMaskLength);
347
348 if (cidrMaskLength == 128) {
349 return IPv6Address.NO_MASK;
350 } else if (cidrMaskLength == 0) {
351 return IPv6Address.FULL_MASK;
352 } else {
Ronald Lif9377602014-07-07 18:13:29 -0700353 int shift1 = Math.min(cidrMaskLength, 64);
Ronald Li1247d0e2014-07-07 18:18:53 -0700354 long raw1 = shift1 == 0 ? 0 : -1L << (64 - shift1);
Ronald Lif9377602014-07-07 18:13:29 -0700355 int shift2 = Math.max(cidrMaskLength - 64, 0);
Ronald Li1247d0e2014-07-07 18:18:53 -0700356 long raw2 = shift2 == 0 ? 0 : -1L << (64 - shift2);
Ronald Lif9377602014-07-07 18:13:29 -0700357 return IPv6Address.of(raw1, raw2);
Ronald Lifea17892014-07-03 18:36:06 -0700358 }
359 }
360
Ronald Libbf01942014-07-07 17:00:13 -0700361 /**
362 * Returns an {@code IPv6AddressWithMask} object that represents this
363 * IP address masked by the given IP address mask.
364 *
365 * @param mask the {@code IPv6Address} object that represents the mask
366 * @return an {@code IPv6AddressWithMask} object that represents this
367 * IP address masked by the given mask
368 * @throws NullPointerException if the given mask was {@code null}
369 */
370 @Nonnull
371 @Override
372 public IPv6AddressWithMask withMask(@Nonnull final IPv6Address mask) {
373 return IPv6AddressWithMask.of(this, mask);
374 }
375
376 /**
377 * Returns an {@code IPv6AddressWithMask} object that represents this
378 * IP address masked by the CIDR subnet mask of the given prefix length.
379 *
380 * @param cidrMaskLength the prefix length of the CIDR subnet mask
381 * (i.e. the number of leading one-bits),
382 * where {@code 0 <= cidrMaskLength <= 128}
383 * @return an {@code IPv6AddressWithMask} object that
384 * represents this IP address masked by the CIDR
385 * subnet mask of the given prefix length
386 * @throws IllegalArgumentException if the given prefix length was invalid
387 * @see #ofCidrMaskLength(int)
388 */
389 @Nonnull
390 @Override
391 public IPv6AddressWithMask withMaskOfLength(final int cidrMaskLength) {
392 return this.withMask(IPv6Address.ofCidrMaskLength(cidrMaskLength));
393 }
394
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800395 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700396
397 public byte[] getBytes() {
398 if (bytesCache == null) {
399 synchronized (this) {
400 if (bytesCache == null) {
401 bytesCache =
402 new byte[] { (byte) ((raw1 >> 56) & 0xFF),
403 (byte) ((raw1 >> 48) & 0xFF),
404 (byte) ((raw1 >> 40) & 0xFF),
405 (byte) ((raw1 >> 32) & 0xFF),
406 (byte) ((raw1 >> 24) & 0xFF),
407 (byte) ((raw1 >> 16) & 0xFF),
408 (byte) ((raw1 >> 8) & 0xFF),
409 (byte) ((raw1 >> 0) & 0xFF),
410
411 (byte) ((raw2 >> 56) & 0xFF),
412 (byte) ((raw2 >> 48) & 0xFF),
413 (byte) ((raw2 >> 40) & 0xFF),
414 (byte) ((raw2 >> 32) & 0xFF),
415 (byte) ((raw2 >> 24) & 0xFF),
416 (byte) ((raw2 >> 16) & 0xFF),
417 (byte) ((raw2 >> 8) & 0xFF),
418 (byte) ((raw2 >> 0) & 0xFF) };
419 }
420 }
421 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800422 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700423 }
424
425 @Override
426 public int getLength() {
427 return LENGTH;
428 }
429
430 @Override
431 public String toString() {
432 return toString(true, false);
433 }
434
435 public int getUnsignedShortWord(final int i) {
436 if (i >= 0 && i < 4)
437 return (int) ((raw1 >>> (48 - i * 16)) & 0xFFFF);
438 else if (i >= 4 && i < 8)
439 return (int) ((raw2 >>> (48 - (i - 4) * 16)) & 0xFFFF);
440 else
441 throw new IllegalArgumentException("16 bit word index must be in [0,7]");
442 }
443
444 /** get the index of the first word where to apply IPv6 zero compression */
445 public int getZeroCompressStart() {
446 int start = Integer.MAX_VALUE;
447 int maxLength = -1;
448
449 int candidateStart = -1;
450
451 for (int i = 0; i < 8; i++) {
452 if (candidateStart >= 0) {
453 // in a zero octect
454 if (getUnsignedShortWord(i) != 0) {
455 // end of this candidate word
456 int candidateLength = i - candidateStart;
457 if (candidateLength >= maxLength) {
458 start = candidateStart;
459 maxLength = candidateLength;
460 }
461 candidateStart = -1;
462 }
463 } else {
464 // not in a zero octect
465 if (getUnsignedShortWord(i) == 0) {
466 candidateStart = i;
467 }
468 }
469 }
470
471 if (candidateStart >= 0) {
472 int candidateLength = 8 - candidateStart;
473 if (candidateLength >= maxLength) {
474 start = candidateStart;
475 maxLength = candidateLength;
476 }
477 }
478
479 return start;
480 }
481
482 public String toString(final boolean zeroCompression, final boolean leadingZeros) {
483 StringBuilder res = new StringBuilder();
484
485 int compressionStart = zeroCompression ? getZeroCompressStart() : Integer.MAX_VALUE;
486 boolean inCompression = false;
487 boolean colonNeeded = false;
488
489 for (int i = 0; i < 8; i++) {
490 int word = getUnsignedShortWord(i);
491
492 if (word == 0) {
493 if (inCompression)
494 continue;
495 else if (i == compressionStart) {
496 res.append(':').append(':');
497 inCompression = true;
498 colonNeeded = false;
499 continue;
500 }
501 } else {
502 inCompression = false;
503 }
504
505 if (colonNeeded) {
506 res.append(':');
507 colonNeeded = false;
508 }
509
510 res.append(leadingZeros ? String.format("%04x", word) : Integer.toString(word,
511 16));
512 colonNeeded = true;
513 }
514 return res.toString();
515 }
516
517 @Override
518 public int hashCode() {
519 final int prime = 31;
520 int result = 1;
521 result = prime * result + (int) (raw1 ^ (raw1 >>> 32));
522 result = prime * result + (int) (raw2 ^ (raw2 >>> 32));
523 return result;
524 }
525
526 @Override
527 public boolean equals(final Object obj) {
528 if (this == obj)
529 return true;
530 if (obj == null)
531 return false;
532 if (getClass() != obj.getClass())
533 return false;
Yotam Harchola289d552013-09-16 10:10:40 -0700534 IPv6Address other = (IPv6Address) obj;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700535 if (raw1 != other.raw1)
536 return false;
537 if (raw2 != other.raw2)
538 return false;
539 return true;
540 }
541
542 public void write16Bytes(ChannelBuffer c) {
543 c.writeLong(this.raw1);
544 c.writeLong(this.raw2);
545 }
546
Yotam Harchola289d552013-09-16 10:10:40 -0700547 public static IPv6Address read16Bytes(ChannelBuffer c) throws OFParseError {
548 return IPv6Address.of(c.readLong(), c.readLong());
Yotam Harcholf3f11152013-09-05 16:47:16 -0700549 }
550
551 @Override
Yotam Harchola289d552013-09-16 10:10:40 -0700552 public IPv6Address applyMask(IPv6Address mask) {
Aditya Vaja98c96e72014-03-11 15:19:01 -0700553 return and(mask);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700554 }
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700555
556 @Override
557 public int compareTo(IPv6Address o) {
Ronald Li9d777a52015-02-07 06:19:29 -0800558 int res = UnsignedLongs.compare(raw1, o.raw1);
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700559 if(res != 0)
560 return res;
561 else
Ronald Li9d777a52015-02-07 06:19:29 -0800562 return UnsignedLongs.compare(raw2, o.raw2);
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700563 }
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700564
565 @Override
566 public void putTo(PrimitiveSink sink) {
567 sink.putLong(raw1);
568 sink.putLong(raw2);
569 }
Byungjoon Leeba92e292014-07-18 13:13:26 +0900570
571 @Override
572 public void writeTo(ChannelBuffer bb) {
573 bb.writeLong(raw1);
574 bb.writeLong(raw2);
575 }
Yotam Harcholf3f11152013-09-05 16:47:16 -0700576}