blob: e454a04ade5f5576387be1b23817c251ed3d9ccb [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
Jonathan Hartdec62d42014-09-22 15:59:04 -070016package org.onlab.packet;
17
18import java.util.Arrays;
19
Jonathan Hartab63aac2014-10-16 08:52:55 -070020
21
Jonathan Hartdec62d42014-09-22 15:59:04 -070022/**
23 * A class representing an IPv4 address.
24 * <p/>
25 * TODO this class is a clone of IpPrefix and still needs to be modified to
26 * look more like an IpAddress.
27 */
Jonathan Hartab63aac2014-10-16 08:52:55 -070028public final class IpAddress implements Comparable<IpAddress> {
Jonathan Hartdec62d42014-09-22 15:59:04 -070029
30 // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
31
32 //IP Versions
33 public enum Version { INET, INET6 };
34
35 //lengths of address, in bytes
36 public static final int INET_LEN = 4;
37 public static final int INET6_LEN = 16;
38
39 //maximum CIDR value
40 public static final int MAX_INET_MASK = 32;
41 //no mask (no network), e.g. a simple address
42 public static final int DEFAULT_MASK = 0;
43
44 /**
45 * Default value indicating an unspecified address.
46 */
47 static final byte[] ANY = new byte [] {0, 0, 0, 0};
48
49 protected Version version;
50
51 protected byte[] octets;
52 protected int netmask;
53
54 private IpAddress(Version ver, byte[] octets, int netmask) {
55 this.version = ver;
56 this.octets = Arrays.copyOf(octets, INET_LEN);
57 this.netmask = netmask;
58 }
59
60 private IpAddress(Version ver, byte[] octets) {
61 this.version = ver;
62 this.octets = Arrays.copyOf(octets, INET_LEN);
63 this.netmask = DEFAULT_MASK;
64 }
65
66 /**
67 * Converts a byte array into an IP address.
68 *
69 * @param address a byte array
70 * @return an IP address
71 */
72 public static IpAddress valueOf(byte [] address) {
73 return new IpAddress(Version.INET, address);
74 }
75
76 /**
77 * Converts a byte array into an IP address.
78 *
79 * @param address a byte array
80 * @param netmask the CIDR value subnet mask
81 * @return an IP address
82 */
83 public static IpAddress valueOf(byte [] address, int netmask) {
84 return new IpAddress(Version.INET, address, netmask);
85 }
86
87 /**
88 * Helper to convert an integer into a byte array.
89 *
90 * @param address the integer to convert
91 * @return a byte array
92 */
93 private static byte [] bytes(int address) {
94 byte [] bytes = new byte [INET_LEN];
95 for (int i = 0; i < INET_LEN; i++) {
96 bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
97 }
98
99 return bytes;
100 }
101
102 /**
103 * Converts an integer into an IPv4 address.
104 *
105 * @param address an integer representing an IP value
106 * @return an IP address
107 */
108 public static IpAddress valueOf(int address) {
109 return new IpAddress(Version.INET, bytes(address));
110 }
111
112 /**
113 * Converts an integer into an IPv4 address.
114 *
115 * @param address an integer representing an IP value
116 * @param netmask the CIDR value subnet mask
117 * @return an IP address
118 */
119 public static IpAddress valueOf(int address, int netmask) {
120 return new IpAddress(Version.INET, bytes(address), netmask);
121 }
122
123 /**
124 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
125 * string can also be in CIDR (slash) notation. If the netmask is omitted,
126 * it will be set to DEFAULT_MASK (0).
127 *
128 * @param address a IP address in string form, e.g. "10.0.0.1", "10.0.0.1/24"
129 * @return an IP address
130 */
131 public static IpAddress valueOf(String address) {
132
133 final String [] parts = address.split("\\/");
134 if (parts.length > 2) {
135 throw new IllegalArgumentException("Malformed IP address string; "
136 + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
137 }
138
139 int mask = DEFAULT_MASK;
140 if (parts.length == 2) {
Yuta HIGUCHI7f3df232014-10-15 23:38:24 -0700141 mask = Integer.parseInt(parts[1]);
Jonathan Hartdec62d42014-09-22 15:59:04 -0700142 if (mask > MAX_INET_MASK) {
143 throw new IllegalArgumentException(
144 "Value of subnet mask cannot exceed "
145 + MAX_INET_MASK);
146 }
147 }
148
149 final String [] net = parts[0].split("\\.");
150 if (net.length != INET_LEN) {
151 throw new IllegalArgumentException("Malformed IP address string; "
152 + "Address must have four decimal values separated by dots (.)");
153 }
154 final byte [] bytes = new byte[INET_LEN];
155 for (int i = 0; i < INET_LEN; i++) {
156 bytes[i] = (byte) Short.parseShort(net[i], 10);
157 }
158 return new IpAddress(Version.INET, bytes, mask);
159 }
160
161 /**
162 * Returns the IP version of this address.
163 *
164 * @return the version
165 */
166 public Version version() {
167 return this.version;
168 }
169
170 /**
171 * Returns the IP address as a byte array.
172 *
173 * @return a byte array
174 */
175 public byte[] toOctets() {
176 return Arrays.copyOf(this.octets, INET_LEN);
177 }
178
179 /**
180 * Returns the IP address prefix length.
181 *
182 * @return prefix length
183 */
184 public int prefixLength() {
185 return netmask;
186 }
187
188 /**
189 * Returns the integral value of this IP address.
190 *
191 * @return the IP address's value as an integer
192 */
193 public int toInt() {
Jonathan Hartdc711bd2014-10-15 11:24:23 -0700194 int val = 0;
195 for (int i = 0; i < octets.length; i++) {
196 val <<= 8;
197 val |= octets[i] & 0xff;
198 }
199 return val;
200 }
201
Jonathan Hartdec62d42014-09-22 15:59:04 -0700202 /**
Jonathan Hart335ef462014-10-16 08:20:46 -0700203 * Converts the IP address to a /32 IP prefix.
204 *
205 * @return the new IP prefix
206 */
207 public IpPrefix toPrefix() {
208 return IpPrefix.valueOf(octets, MAX_INET_MASK);
209 }
210
211 /**
Jonathan Hartdec62d42014-09-22 15:59:04 -0700212 * Helper for computing the mask value from CIDR.
213 *
214 * @return an integer bitmask
215 */
216 private int mask() {
217 int shift = MAX_INET_MASK - this.netmask;
218 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
219 }
220
221 /**
222 * Returns the subnet mask in IpAddress form. The netmask value for
223 * the returned IpAddress is 0, as the address itself is a mask.
224 *
225 * @return the subnet mask
226 */
227 public IpAddress netmask() {
228 return new IpAddress(Version.INET, bytes(mask()));
229 }
230
231 /**
232 * Returns the network portion of this address as an IpAddress.
233 * The netmask of the returned IpAddress is the current mask. If this
234 * address doesn't have a mask, this returns an all-0 IpAddress.
235 *
236 * @return the network address or null
237 */
238 public IpAddress network() {
239 if (netmask == DEFAULT_MASK) {
240 return new IpAddress(version, ANY, DEFAULT_MASK);
241 }
242
243 byte [] net = new byte [4];
244 byte [] mask = bytes(mask());
245 for (int i = 0; i < INET_LEN; i++) {
246 net[i] = (byte) (octets[i] & mask[i]);
247 }
248 return new IpAddress(version, net, netmask);
249 }
250
251 /**
252 * Returns the host portion of the IPAddress, as an IPAddress.
253 * The netmask of the returned IpAddress is the current mask. If this
254 * address doesn't have a mask, this returns a copy of the current
255 * address.
256 *
257 * @return the host address
258 */
259 public IpAddress host() {
260 if (netmask == DEFAULT_MASK) {
261 new IpAddress(version, octets, netmask);
262 }
263
264 byte [] host = new byte [INET_LEN];
265 byte [] mask = bytes(mask());
266 for (int i = 0; i < INET_LEN; i++) {
267 host[i] = (byte) (octets[i] & ~mask[i]);
268 }
269 return new IpAddress(version, host, netmask);
270 }
271
272 public boolean isMasked() {
273 return mask() != 0;
274 }
275
276 /**
277 * Determines whether a given address is contained within this IpAddress'
278 * network.
279 *
280 * @param other another IP address that could be contained in this network
281 * @return true if the other IP address is contained in this address'
282 * network, otherwise false
283 */
284 public boolean contains(IpAddress other) {
285 if (this.netmask <= other.netmask) {
286 // Special case where they're both /32 addresses
287 if (this.netmask == MAX_INET_MASK) {
288 return Arrays.equals(octets, other.octets);
289 }
290
291 // Mask the other address with our network mask
292 IpAddress otherMasked =
293 IpAddress.valueOf(other.octets, netmask).network();
294
295 return network().equals(otherMasked);
296 }
297 return false;
298 }
299
300 @Override
Jonathan Hartab63aac2014-10-16 08:52:55 -0700301 public int compareTo(IpAddress o) {
Jonathan Hartbcae7bd2014-10-16 10:24:41 -0700302 Long lv = ((long) this.toInt()) & 0xffffffffL;
303 Long rv = ((long) o.toInt()) & 0xffffffffL;
Jonathan Hartab63aac2014-10-16 08:52:55 -0700304 return lv.compareTo(rv);
305 }
306
307 @Override
Jonathan Hartdec62d42014-09-22 15:59:04 -0700308 public int hashCode() {
309 final int prime = 31;
310 int result = 1;
311 result = prime * result + netmask;
312 result = prime * result + Arrays.hashCode(octets);
313 result = prime * result + ((version == null) ? 0 : version.hashCode());
314 return result;
315 }
316
317 @Override
318 public boolean equals(Object obj) {
319 if (this == obj) {
320 return true;
321 }
322 if (obj == null) {
323 return false;
324 }
325 if (getClass() != obj.getClass()) {
326 return false;
327 }
328 IpAddress other = (IpAddress) obj;
329 if (netmask != other.netmask) {
330 return false;
331 }
332 if (!Arrays.equals(octets, other.octets)) {
333 return false;
334 }
335 if (version != other.version) {
336 return false;
337 }
338 return true;
339 }
340
341 @Override
342 /*
343 * (non-Javadoc)
344 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
345 * and "x.x.x.x/y" for masked addresses.
346 *
347 * @see java.lang.Object#toString()
348 */
349 public String toString() {
350 final StringBuilder builder = new StringBuilder();
351 for (final byte b : this.octets) {
352 if (builder.length() > 0) {
353 builder.append(".");
354 }
355 builder.append(String.format("%d", b & 0xff));
356 }
357 if (netmask != DEFAULT_MASK) {
358 builder.append("/");
359 builder.append(String.format("%d", netmask));
360 }
361 return builder.toString();
362 }
363
364}