blob: d933f8760835fc9cdb1ec60306297adae2d60a1e [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Pavlin Radoslavov9de27722014-10-23 20:31:15 -070019package org.onlab.packet;
20
21import java.net.InetAddress;
22import java.net.UnknownHostException;
23import java.nio.ByteBuffer;
24import java.util.Objects;
25
26import com.google.common.net.InetAddresses;
27import com.google.common.primitives.UnsignedLongs;
28
29import static com.google.common.base.Preconditions.checkNotNull;
30import static com.google.common.base.Preconditions.checkState;
31
32/**
33 * The class representing an IPv6 address.
34 * This class is immutable.
35 */
36public final class Ip6Address implements Comparable<Ip6Address> {
37 private final long valueHigh; // The higher (more significant) 64 bits
38 private final long valueLow; // The lower (less significant) 64 bits
39
40 /** The length of the address in bytes (octets). */
41 public static final int BYTE_LENGTH = 16;
42
43 /** The length of the address in bits. */
44 public static final int BIT_LENGTH = BYTE_LENGTH * Byte.SIZE;
45
46 /**
47 * Default constructor.
48 */
49 public Ip6Address() {
50 this.valueHigh = 0;
51 this.valueLow = 0;
52 }
53
54 /**
55 * Copy constructor.
56 *
57 * @param other the object to copy from
58 */
59 public Ip6Address(Ip6Address other) {
60 this.valueHigh = other.valueHigh;
61 this.valueLow = other.valueLow;
62 }
63
64 /**
65 * Constructor from integer values.
66 *
67 * @param valueHigh the higher (more significant) 64 bits of the address
68 * @param valueLow the lower (less significant) 64 bits of the address
69 */
70 public Ip6Address(long valueHigh, long valueLow) {
71 this.valueHigh = valueHigh;
72 this.valueLow = valueLow;
73 }
74
75 /**
76 * Constructor from a byte array with the IPv6 address stored in network
77 * byte order (i.e., the most significant byte first).
78 *
79 * @param value the value to use
80 */
81 public Ip6Address(byte[] value) {
82 this(value, 0);
83 }
84
85 /**
86 * Constructor from a byte array with the IPv6 address stored in network
87 * byte order (i.e., the most significant byte first), and a given offset
88 * from the beginning of the byte array.
89 *
90 * @param value the value to use
91 * @param offset the offset in bytes from the beginning of the byte array
92 */
93 public Ip6Address(byte[] value, int offset) {
94 checkNotNull(value);
95
96 // Verify the arguments
97 if ((offset < 0) || (offset + BYTE_LENGTH > value.length)) {
98 String msg;
99 if (value.length < BYTE_LENGTH) {
100 msg = "Invalid IPv6 address array: array length: " +
101 value.length + ". Must be at least " + BYTE_LENGTH;
102 } else {
103 msg = "Invalid IPv6 address array: array offset: " +
104 offset + ". Must be in the interval [0, " +
105 (value.length - BYTE_LENGTH) + "]";
106 }
107 throw new IllegalArgumentException(msg);
108 }
109
110 // Read the address
111 ByteBuffer bb = ByteBuffer.wrap(value);
112 bb.position(offset);
113 this.valueHigh = bb.getLong();
114 this.valueLow = bb.getLong();
115 }
116
117 /**
118 * Constructs an IPv6 address from a string representation of the address.
119 *<p>
120 * Example: "1111:2222::8888"
121 *
122 * @param value the value to use
123 */
124 public Ip6Address(String value) {
125 checkNotNull(value);
126
127 if (value.isEmpty()) {
128 final String msg = "Specified IPv6 cannot be an empty string";
129 throw new IllegalArgumentException(msg);
130 }
131 InetAddress addr = null;
132 try {
133 addr = InetAddresses.forString(value);
134 } catch (IllegalArgumentException e) {
135 final String msg = "Invalid IPv6 address string: " + value;
136 throw new IllegalArgumentException(msg);
137 }
138 byte[] bytes = addr.getAddress();
139 ByteBuffer bb = ByteBuffer.wrap(bytes);
140 this.valueHigh = bb.getLong();
141 this.valueLow = bb.getLong();
142 }
143
144 /**
145 * Gets the IPv6 address as a byte array.
146 *
147 * @return a byte array with the IPv6 address stored in network byte order
148 * (i.e., the most significant byte first).
149 */
150 public byte[] toOctets() {
151 return ByteBuffer.allocate(BYTE_LENGTH)
152 .putLong(valueHigh).putLong(valueLow).array();
153 }
154
155 /**
156 * Creates an IPv6 network mask prefix.
157 *
158 * @param prefixLen the length of the mask prefix. Must be in the interval
159 * [0, 128].
160 * @return a new IPv6 address that contains a mask prefix of the
161 * specified length
162 */
163 public static Ip6Address makeMaskPrefix(int prefixLen) {
164 long vh, vl;
165
166 // Verify the prefix length
167 if ((prefixLen < 0) || (prefixLen > Ip6Address.BIT_LENGTH)) {
168 final String msg = "Invalid IPv6 prefix length: " + prefixLen +
169 ". Must be in the interval [0, 128].";
170 throw new IllegalArgumentException(msg);
171 }
172
173 if (prefixLen == 0) {
174 //
175 // NOTE: Apparently, the result of "<< 64" shifting to the left
176 // results in all 1s instead of all 0s, hence we handle it as
177 // a special case.
178 //
179 vh = 0;
180 vl = 0;
181 } else if (prefixLen <= 64) {
182 vh = (0xffffffffffffffffL << (64 - prefixLen)) & 0xffffffffffffffffL;
183 vl = 0;
184 } else {
185 vh = -1L; // All 1s
186 vl = (0xffffffffffffffffL << (128 - prefixLen)) & 0xffffffffffffffffL;
187 }
188 return new Ip6Address(vh, vl);
189 }
190
191 /**
192 * Creates an IPv6 address by masking it with a network mask of given
193 * mask length.
194 *
195 * @param addr the address to mask
196 * @param prefixLen the length of the mask prefix. Must be in the interval
197 * [0, 128].
198 * @return a new IPv6 address that is masked with a mask prefix of the
199 * specified length
200 */
201 public static Ip6Address makeMaskedAddress(final Ip6Address addr,
202 int prefixLen) {
203 Ip6Address mask = Ip6Address.makeMaskPrefix(prefixLen);
204 long vh = addr.valueHigh & mask.valueHigh;
205 long vl = addr.valueLow & mask.valueLow;
206
207 return new Ip6Address(vh, vl);
208 }
209
210 /**
211 * Gets the value of the higher (more significant) 64 bits of the address.
212 *
213 * @return the value of the higher (more significant) 64 bits of the
214 * address
215 */
216 public long getValueHigh() {
217 return valueHigh;
218 }
219
220 /**
221 * Gets the value of the lower (less significant) 64 bits of the address.
222 *
223 * @return the value of the lower (less significant) 64 bits of the
224 * address
225 */
226 public long getValueLow() {
227 return valueLow;
228 }
229
230 /**
231 * Converts the IPv6 value to a ':' separated string.
232 *
233 * @return the IPv6 value as a ':' separated string
234 */
235 @Override
236 public String toString() {
237 ByteBuffer bb = ByteBuffer.allocate(Ip6Address.BYTE_LENGTH);
238 bb.putLong(valueHigh);
239 bb.putLong(valueLow);
240 InetAddress inetAddr = null;
241 try {
242 inetAddr = InetAddress.getByAddress(bb.array());
243 } catch (UnknownHostException e) {
244 // Should never happen
245 checkState(false, "Internal error: Ip6Address.toString()");
246 return "::";
247 }
248 return InetAddresses.toAddrString(inetAddr);
249 }
250
251 @Override
252 public boolean equals(Object o) {
253 if (!(o instanceof Ip6Address)) {
254 return false;
255 }
256 Ip6Address other = (Ip6Address) o;
257 return this.valueHigh == other.valueHigh
258 && this.valueLow == other.valueLow;
259 }
260
261 @Override
262 public int hashCode() {
263 return Objects.hash(valueHigh, valueLow);
264 }
265
266 @Override
267 public int compareTo(Ip6Address o) {
268 // Compare the high-order 64-bit value
269 if (this.valueHigh != o.valueHigh) {
270 return UnsignedLongs.compare(this.valueHigh, o.valueHigh);
271 }
272 // Compare the low-order 64-bit value
273 if (this.valueLow != o.valueLow) {
274 return UnsignedLongs.compare(this.valueLow, o.valueLow);
275 }
276 return 0;
277 }
278}