blob: 3ab6767cca7434eb07d272615672ab6d8c4d6b0f [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 *
24 * @author Andreas Wundsam <andreas.wundsam@teleteach.de>
25 */
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
118 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -0700119 public IPv6Address and(IPv6Address other) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700120 Preconditions.checkNotNull(other, "other must not be null");
121
122 IPv6Address otherIp = other;
Aditya Vaja56b8b182014-03-11 13:13:58 -0700123 return IPv6Address.of((raw1 & otherIp.raw1), (raw2 & otherIp.raw2));
124 }
125
126 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -0700127 public IPv6Address or(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
135 public IPv6Address not() {
136 return IPv6Address.of(~raw1, ~raw2);
137 }
138
Ronald Licc9c9302014-07-07 00:58:56 -0700139 /**
140 * Returns an {@code IPv6Address} object that represents the given
141 * IP address. The argument is in network byte order: the highest
142 * order byte of the address is in {@code address[0]}.
143 * <p>
144 * The address byte array must be 16 bytes long (128 bits long).
145 * <p>
146 * Similar to {@link InetAddress#getByAddress(byte[])}.
147 *
148 * @param address the raw IP address in network byte order
149 * @return an {@code IPv6Address} object that represents the given
150 * raw IP address
151 * @throws NullPointerException if the given address was {@code null}
152 * @throws IllegalArgumentException if the given address was of an invalid
153 * byte array length
154 * @see InetAddress#getByAddress(byte[])
155 */
156 @Nonnull
157 public static IPv6Address of(@Nonnull final byte[] address) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700158 Preconditions.checkNotNull(address, "address must not be null");
159
Yotam Harcholf3f11152013-09-05 16:47:16 -0700160 if (address.length != LENGTH) {
161 throw new IllegalArgumentException(
Andreas Wundsamc85b5c52013-09-24 13:01:43 -0700162 "Invalid byte array length for IPv6 address: " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700163 }
164
165 long raw1 =
166 (address[0] & 0xFFL) << 56 | (address[1] & 0xFFL) << 48
167 | (address[2] & 0xFFL) << 40 | (address[3] & 0xFFL) << 32
168 | (address[4] & 0xFFL) << 24 | (address[5] & 0xFFL) << 16
169 | (address[6] & 0xFFL) << 8 | (address[7]);
170
171 long raw2 =
172 (address[8] & 0xFFL) << 56 | (address[9] & 0xFFL) << 48
173 | (address[10] & 0xFFL) << 40 | (address[11] & 0xFFL) << 32
174 | (address[12] & 0xFFL) << 24 | (address[13] & 0xFFL) << 16
175 | (address[14] & 0xFFL) << 8 | (address[15]);
176
Yotam Harchola289d552013-09-16 10:10:40 -0700177 return IPv6Address.of(raw1, raw2);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700178 }
179
180 private static class IPv6Builder {
181 private long raw1, raw2;
182
183 public void setUnsignedShortWord(final int i, final int value) {
184 int shift = 48 - (i % 4) * 16;
185
186 if (value < 0 || value > 0xFFFF)
187 throw new IllegalArgumentException("16 bit word must be in [0, 0xFFFF]");
188
189 if (i >= 0 && i < 4)
190 raw1 = raw1 & ~(0xFFFFL << shift) | (value & 0xFFFFL) << shift;
191 else if (i >= 4 && i < 8)
192 raw2 = raw2 & ~(0xFFFFL << shift) | (value & 0xFFFFL) << shift;
193 else
194 throw new IllegalArgumentException("16 bit word index must be in [0,7]");
195 }
196
Yotam Harchola289d552013-09-16 10:10:40 -0700197 public IPv6Address getIPv6() {
198 return IPv6Address.of(raw1, raw2);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700199 }
200 }
201
202 private final static Pattern colonPattern = Pattern.compile(":");
203
Ronald Licc9c9302014-07-07 00:58:56 -0700204 /**
205 * Returns an {@code IPv6Address} object that represents the given
206 * IP address. The argument is in the conventional string representation
207 * of IPv6 addresses.
208 * <p>
209 * Expects up to 8 groups of 16-bit hex words seperated by colons
210 * (e.g., 2001:db8:85a3:8d3:1319:8a2e:370:7348).
211 * <p>
212 * Supports zero compression (e.g., 2001:db8::7348).
213 * Does <b>not</b> currently support embedding a dotted-quad IPv4 address
214 * into the IPv6 address (e.g., 2001:db8::192.168.0.1).
Andreas Wundsam3700d162014-03-11 04:43:38 -0700215 *
Ronald Licc9c9302014-07-07 00:58:56 -0700216 * @param string the IP address in the conventional string representation
217 * of IPv6 addresses
218 * @return an {@code IPv6Address} object that represents the given
219 * IP address
220 * @throws NullPointerException if the given string was {@code null}
221 * @throws IllegalArgumentException if the given string was not a valid
222 * IPv6 address
Andreas Wundsam3700d162014-03-11 04:43:38 -0700223 */
224 @Nonnull
225 public static IPv6Address of(@Nonnull final String string) throws IllegalArgumentException {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700226 Preconditions.checkNotNull(string, "string must not be null");
227
Rich Lanebae30f92014-08-27 12:13:20 -0700228 // remove the zone id
229 int zoneDelimIndex = string.indexOf("%");
Rich Lane449664c2014-09-19 13:01:49 -0700230 String substring;
Rich Lanebae30f92014-08-27 12:13:20 -0700231 if (zoneDelimIndex != -1) {
232 substring = string.substring(0, zoneDelimIndex);
233 } else {
234 substring = string;
235 }
236
Yotam Harcholf3f11152013-09-05 16:47:16 -0700237 IPv6Builder builder = new IPv6Builder();
Rich Lanebae30f92014-08-27 12:13:20 -0700238 String[] parts = colonPattern.split(substring, -1);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700239
240 int leftWord = 0;
241 int leftIndex = 0;
242
243 boolean hitZeroCompression = false;
244
245 for (leftIndex = 0; leftIndex < parts.length; leftIndex++) {
246 String part = parts[leftIndex];
247 if (part.length() == 0) {
248 // hit empty group of zero compression
249 hitZeroCompression = true;
250 break;
251 }
252 builder.setUnsignedShortWord(leftWord++, Integer.parseInt(part, 16));
253 }
254
255 if (hitZeroCompression) {
256 if (leftIndex == 0) {
257 // if colon is at the start, two columns must be at the start,
258 // move to the second empty group
259 leftIndex = 1;
260 if (parts.length < 2 || parts[1].length() > 0)
261 throw new IllegalArgumentException("Malformed IPv6 address: " + string);
262 }
263
264 int rightWord = 7;
265 int rightIndex;
266 for (rightIndex = parts.length - 1; rightIndex > leftIndex; rightIndex--) {
267 String part = parts[rightIndex];
268 if (part.length() == 0)
269 break;
270 builder.setUnsignedShortWord(rightWord--, Integer.parseInt(part, 16));
271 }
272 if (rightIndex == parts.length - 1) {
273 // if colon is at the end, two columns must be at the end, move
274 // to the second empty group
275 if (rightIndex < 1 || parts[rightIndex - 1].length() > 0)
276 throw new IllegalArgumentException("Malformed IPv6 address: " + string);
277 rightIndex--;
278 }
279 if (leftIndex != rightIndex)
280 throw new IllegalArgumentException("Malformed IPv6 address: " + string);
281 } else {
282 if (leftIndex != 8) {
283 throw new IllegalArgumentException("Malformed IPv6 address: " + string);
284 }
285 }
286 return builder.getIPv6();
287 }
288
Ronald Licc9c9302014-07-07 00:58:56 -0700289 /**
290 * Returns an {@code IPv6Address} object that represents the given
291 * IP address. The arguments are the two 64-bit integers representing
292 * the first (higher-order) and second (lower-order) 64-bit blocks
293 * of the IP address.
Andreas Wundsam3700d162014-03-11 04:43:38 -0700294 *
Ronald Licc9c9302014-07-07 00:58:56 -0700295 * @param raw1 the first (higher-order) 64-bit block of the IP address
296 * @param raw2 the second (lower-order) 64-bit block of the IP address
297 * @return an {@code IPv6Address} object that represents the given
298 * raw IP address
Andreas Wundsam3700d162014-03-11 04:43:38 -0700299 */
Ronald Licc9c9302014-07-07 00:58:56 -0700300 @Nonnull
Yotam Harchola289d552013-09-16 10:10:40 -0700301 public static IPv6Address of(final long raw1, final long raw2) {
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -0700302 if(raw1==NONE_VAL1 && raw2 == NONE_VAL2)
303 return NONE;
Yotam Harchola289d552013-09-16 10:10:40 -0700304 return new IPv6Address(raw1, raw2);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700305 }
306
Ronald Licc9c9302014-07-07 00:58:56 -0700307 /**
308 * Returns an {@code IPv6Address} object that represents the given
309 * IP address. The argument is given as an {@code Inet6Address} object.
310 *
311 * @param address the IP address as an {@code Inet6Address} object
312 * @return an {@code IPv6Address} object that represents the
313 * given IP address
314 * @throws NullPointerException if the given {@code Inet6Address} was
315 * {@code null}
316 */
317 @Nonnull
318 public static IPv6Address of(@Nonnull final Inet6Address address) {
319 Preconditions.checkNotNull(address, "address must not be null");
320 return IPv6Address.of(address.getAddress());
321 }
322
323 /**
324 * Returns an {@code IPv6Address} object that represents the
325 * CIDR subnet mask of the given prefix length.
326 *
327 * @param cidrMaskLength the prefix length of the CIDR subnet mask
328 * (i.e. the number of leading one-bits),
329 * where {@code 0 <= cidrMaskLength <= 128}
330 * @return an {@code IPv6Address} object that represents the
331 * CIDR subnet mask of the given prefix length
332 * @throws IllegalArgumentException if the given prefix length was invalid
333 */
334 @Nonnull
335 public static IPv6Address ofCidrMaskLength(final int cidrMaskLength) {
Ronald Lifea17892014-07-03 18:36:06 -0700336 Preconditions.checkArgument(
337 cidrMaskLength >= 0 && cidrMaskLength <= 128,
338 "Invalid IPv6 CIDR mask length: %s", cidrMaskLength);
339
340 if (cidrMaskLength == 128) {
341 return IPv6Address.NO_MASK;
342 } else if (cidrMaskLength == 0) {
343 return IPv6Address.FULL_MASK;
344 } else {
Ronald Lif9377602014-07-07 18:13:29 -0700345 int shift1 = Math.min(cidrMaskLength, 64);
Ronald Li1247d0e2014-07-07 18:18:53 -0700346 long raw1 = shift1 == 0 ? 0 : -1L << (64 - shift1);
Ronald Lif9377602014-07-07 18:13:29 -0700347 int shift2 = Math.max(cidrMaskLength - 64, 0);
Ronald Li1247d0e2014-07-07 18:18:53 -0700348 long raw2 = shift2 == 0 ? 0 : -1L << (64 - shift2);
Ronald Lif9377602014-07-07 18:13:29 -0700349 return IPv6Address.of(raw1, raw2);
Ronald Lifea17892014-07-03 18:36:06 -0700350 }
351 }
352
Ronald Libbf01942014-07-07 17:00:13 -0700353 /**
354 * Returns an {@code IPv6AddressWithMask} object that represents this
355 * IP address masked by the given IP address mask.
356 *
357 * @param mask the {@code IPv6Address} object that represents the mask
358 * @return an {@code IPv6AddressWithMask} object that represents this
359 * IP address masked by the given mask
360 * @throws NullPointerException if the given mask was {@code null}
361 */
362 @Nonnull
363 @Override
364 public IPv6AddressWithMask withMask(@Nonnull final IPv6Address mask) {
365 return IPv6AddressWithMask.of(this, mask);
366 }
367
368 /**
369 * Returns an {@code IPv6AddressWithMask} object that represents this
370 * IP address masked by the CIDR subnet mask of the given prefix length.
371 *
372 * @param cidrMaskLength the prefix length of the CIDR subnet mask
373 * (i.e. the number of leading one-bits),
374 * where {@code 0 <= cidrMaskLength <= 128}
375 * @return an {@code IPv6AddressWithMask} object that
376 * represents this IP address masked by the CIDR
377 * subnet mask of the given prefix length
378 * @throws IllegalArgumentException if the given prefix length was invalid
379 * @see #ofCidrMaskLength(int)
380 */
381 @Nonnull
382 @Override
383 public IPv6AddressWithMask withMaskOfLength(final int cidrMaskLength) {
384 return this.withMask(IPv6Address.ofCidrMaskLength(cidrMaskLength));
385 }
386
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800387 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700388
389 public byte[] getBytes() {
390 if (bytesCache == null) {
391 synchronized (this) {
392 if (bytesCache == null) {
393 bytesCache =
394 new byte[] { (byte) ((raw1 >> 56) & 0xFF),
395 (byte) ((raw1 >> 48) & 0xFF),
396 (byte) ((raw1 >> 40) & 0xFF),
397 (byte) ((raw1 >> 32) & 0xFF),
398 (byte) ((raw1 >> 24) & 0xFF),
399 (byte) ((raw1 >> 16) & 0xFF),
400 (byte) ((raw1 >> 8) & 0xFF),
401 (byte) ((raw1 >> 0) & 0xFF),
402
403 (byte) ((raw2 >> 56) & 0xFF),
404 (byte) ((raw2 >> 48) & 0xFF),
405 (byte) ((raw2 >> 40) & 0xFF),
406 (byte) ((raw2 >> 32) & 0xFF),
407 (byte) ((raw2 >> 24) & 0xFF),
408 (byte) ((raw2 >> 16) & 0xFF),
409 (byte) ((raw2 >> 8) & 0xFF),
410 (byte) ((raw2 >> 0) & 0xFF) };
411 }
412 }
413 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800414 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700415 }
416
417 @Override
418 public int getLength() {
419 return LENGTH;
420 }
421
422 @Override
423 public String toString() {
424 return toString(true, false);
425 }
426
427 public int getUnsignedShortWord(final int i) {
428 if (i >= 0 && i < 4)
429 return (int) ((raw1 >>> (48 - i * 16)) & 0xFFFF);
430 else if (i >= 4 && i < 8)
431 return (int) ((raw2 >>> (48 - (i - 4) * 16)) & 0xFFFF);
432 else
433 throw new IllegalArgumentException("16 bit word index must be in [0,7]");
434 }
435
436 /** get the index of the first word where to apply IPv6 zero compression */
437 public int getZeroCompressStart() {
438 int start = Integer.MAX_VALUE;
439 int maxLength = -1;
440
441 int candidateStart = -1;
442
443 for (int i = 0; i < 8; i++) {
444 if (candidateStart >= 0) {
445 // in a zero octect
446 if (getUnsignedShortWord(i) != 0) {
447 // end of this candidate word
448 int candidateLength = i - candidateStart;
449 if (candidateLength >= maxLength) {
450 start = candidateStart;
451 maxLength = candidateLength;
452 }
453 candidateStart = -1;
454 }
455 } else {
456 // not in a zero octect
457 if (getUnsignedShortWord(i) == 0) {
458 candidateStart = i;
459 }
460 }
461 }
462
463 if (candidateStart >= 0) {
464 int candidateLength = 8 - candidateStart;
465 if (candidateLength >= maxLength) {
466 start = candidateStart;
467 maxLength = candidateLength;
468 }
469 }
470
471 return start;
472 }
473
474 public String toString(final boolean zeroCompression, final boolean leadingZeros) {
475 StringBuilder res = new StringBuilder();
476
477 int compressionStart = zeroCompression ? getZeroCompressStart() : Integer.MAX_VALUE;
478 boolean inCompression = false;
479 boolean colonNeeded = false;
480
481 for (int i = 0; i < 8; i++) {
482 int word = getUnsignedShortWord(i);
483
484 if (word == 0) {
485 if (inCompression)
486 continue;
487 else if (i == compressionStart) {
488 res.append(':').append(':');
489 inCompression = true;
490 colonNeeded = false;
491 continue;
492 }
493 } else {
494 inCompression = false;
495 }
496
497 if (colonNeeded) {
498 res.append(':');
499 colonNeeded = false;
500 }
501
502 res.append(leadingZeros ? String.format("%04x", word) : Integer.toString(word,
503 16));
504 colonNeeded = true;
505 }
506 return res.toString();
507 }
508
509 @Override
510 public int hashCode() {
511 final int prime = 31;
512 int result = 1;
513 result = prime * result + (int) (raw1 ^ (raw1 >>> 32));
514 result = prime * result + (int) (raw2 ^ (raw2 >>> 32));
515 return result;
516 }
517
518 @Override
519 public boolean equals(final Object obj) {
520 if (this == obj)
521 return true;
522 if (obj == null)
523 return false;
524 if (getClass() != obj.getClass())
525 return false;
Yotam Harchola289d552013-09-16 10:10:40 -0700526 IPv6Address other = (IPv6Address) obj;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700527 if (raw1 != other.raw1)
528 return false;
529 if (raw2 != other.raw2)
530 return false;
531 return true;
532 }
533
534 public void write16Bytes(ChannelBuffer c) {
535 c.writeLong(this.raw1);
536 c.writeLong(this.raw2);
537 }
538
Yotam Harchola289d552013-09-16 10:10:40 -0700539 public static IPv6Address read16Bytes(ChannelBuffer c) throws OFParseError {
540 return IPv6Address.of(c.readLong(), c.readLong());
Yotam Harcholf3f11152013-09-05 16:47:16 -0700541 }
542
543 @Override
Yotam Harchola289d552013-09-16 10:10:40 -0700544 public IPv6Address applyMask(IPv6Address mask) {
Aditya Vaja98c96e72014-03-11 15:19:01 -0700545 return and(mask);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700546 }
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700547
548 @Override
549 public int compareTo(IPv6Address o) {
Ronald Li9d777a52015-02-07 06:19:29 -0800550 int res = UnsignedLongs.compare(raw1, o.raw1);
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700551 if(res != 0)
552 return res;
553 else
Ronald Li9d777a52015-02-07 06:19:29 -0800554 return UnsignedLongs.compare(raw2, o.raw2);
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700555 }
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700556
557 @Override
558 public void putTo(PrimitiveSink sink) {
559 sink.putLong(raw1);
560 sink.putLong(raw2);
561 }
Byungjoon Leeba92e292014-07-18 13:13:26 +0900562
563 @Override
564 public void writeTo(ChannelBuffer bb) {
565 bb.writeLong(raw1);
566 bb.writeLong(raw2);
567 }
Yotam Harcholf3f11152013-09-05 16:47:16 -0700568}