blob: 1a9156857936b0ba2a21306e79d8d0cd726c4ab5 [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 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070016package org.onlab.packet;
17
18import java.util.Arrays;
19
20/**
Jonathan Hartdec62d42014-09-22 15:59:04 -070021 * A class representing an IPv4 prefix.
22 * <p/>
23 * A prefix consists of an IP address and a subnet mask.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070024 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070025public final class IpPrefix {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070026
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070027 // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
28
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070029 //IP Versions
30 public enum Version { INET, INET6 };
31
Ayaka Koshibe04a1a4e2014-09-11 14:31:29 -070032 //lengths of address, in bytes
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070033 public static final int INET_LEN = 4;
Ayaka Koshibe3a25aec2014-09-12 11:52:53 -070034 public static final int INET6_LEN = 16;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070035
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070036 //maximum CIDR value
37 public static final int MAX_INET_MASK = 32;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070038 //no mask (no network), e.g. a simple address
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070039 public static final int DEFAULT_MASK = 0;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070040
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070041 /**
42 * Default value indicating an unspecified address.
43 */
Yuta HIGUCHI10681f62014-09-21 17:49:46 -070044 static final byte[] ANY = new byte [] {0, 0, 0, 0};
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070045
46 protected Version version;
47
48 protected byte[] octets;
49 protected int netmask;
50
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070051 private IpPrefix(Version ver, byte[] octets, int netmask) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070052 this.version = ver;
53 this.octets = Arrays.copyOf(octets, INET_LEN);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070054 this.netmask = netmask;
55 }
56
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070057 private IpPrefix(Version ver, byte[] octets) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070058 this.version = ver;
59 this.octets = Arrays.copyOf(octets, INET_LEN);
60 this.netmask = DEFAULT_MASK;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070061 }
62
63 /**
64 * Converts a byte array into an IP address.
65 *
66 * @param address a byte array
67 * @return an IP address
68 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070069 public static IpPrefix valueOf(byte [] address) {
70 return new IpPrefix(Version.INET, address);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070071 }
72
73 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070074 * Converts a byte array into an IP address.
75 *
76 * @param address a byte array
77 * @param netmask the CIDR value subnet mask
78 * @return an IP address
79 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070080 public static IpPrefix valueOf(byte [] address, int netmask) {
81 return new IpPrefix(Version.INET, address, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070082 }
83
84 /**
85 * Helper to convert an integer into a byte array.
86 *
87 * @param address the integer to convert
88 * @return a byte array
89 */
90 private static byte [] bytes(int address) {
91 byte [] bytes = new byte [INET_LEN];
92 for (int i = 0; i < INET_LEN; i++) {
93 bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
94 }
95
96 return bytes;
97 }
98
99 /**
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700100 * Converts an integer into an IPv4 address.
101 *
102 * @param address an integer representing an IP value
103 * @return an IP address
104 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700105 public static IpPrefix valueOf(int address) {
106 return new IpPrefix(Version.INET, bytes(address));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700107 }
108
109 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700110 * Converts an integer into an IPv4 address.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700111 *
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700112 * @param address an integer representing an IP value
113 * @param netmask the CIDR value subnet mask
114 * @return an IP address
115 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700116 public static IpPrefix valueOf(int address, int netmask) {
117 return new IpPrefix(Version.INET, bytes(address), netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700118 }
119
120 /**
121 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700122 * string can also be in CIDR (slash) notation. If the netmask is omitted,
123 * it will be set to DEFAULT_MASK (0).
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700124 *
125 * @param address a IP address in string form, e.g. "10.0.0.1", "10.0.0.1/24"
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700126 * @return an IP address
127 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700128 public static IpPrefix valueOf(String address) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700129
130 final String [] parts = address.split("\\/");
131 if (parts.length > 2) {
132 throw new IllegalArgumentException("Malformed IP address string; "
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700133 + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700134 }
135
136 int mask = DEFAULT_MASK;
137 if (parts.length == 2) {
Yuta HIGUCHI7f3df232014-10-15 23:38:24 -0700138 mask = Integer.parseInt(parts[1]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700139 if (mask > MAX_INET_MASK) {
140 throw new IllegalArgumentException(
141 "Value of subnet mask cannot exceed "
alshabib8f1cf4a2014-09-17 14:44:48 -0700142 + MAX_INET_MASK);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700143 }
144 }
145
146 final String [] net = parts[0].split("\\.");
147 if (net.length != INET_LEN) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700148 throw new IllegalArgumentException("Malformed IP address string; "
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700149 + "Address must have four decimal values separated by dots (.)");
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700150 }
151 final byte [] bytes = new byte[INET_LEN];
152 for (int i = 0; i < INET_LEN; i++) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700153 bytes[i] = (byte) Short.parseShort(net[i], 10);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700154 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700155 return new IpPrefix(Version.INET, bytes, mask);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700156 }
157
158 /**
159 * Returns the IP version of this address.
160 *
161 * @return the version
162 */
163 public Version version() {
164 return this.version;
165 }
166
167 /**
168 * Returns the IP address as a byte array.
169 *
170 * @return a byte array
171 */
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700172 public byte[] toOctets() {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700173 return Arrays.copyOf(this.octets, INET_LEN);
174 }
175
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700176 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700177 * Returns the IP address prefix length.
178 *
179 * @return prefix length
180 */
181 public int prefixLength() {
182 return netmask;
183 }
184
185 /**
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700186 * Returns the integral value of this IP address.
187 *
188 * @return the IP address's value as an integer
189 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700190 public int toInt() {
alshabib6eb438a2014-10-01 16:39:37 -0700191 int val = 0;
192 for (int i = 0; i < octets.length; i++) {
193 val <<= 8;
194 val |= octets[i] & 0xff;
195 }
196 return val;
197 }
198
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700199 /**
200 * Helper for computing the mask value from CIDR.
201 *
202 * @return an integer bitmask
203 */
204 private int mask() {
205 int shift = MAX_INET_MASK - this.netmask;
206 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
207 }
208
209 /**
210 * Returns the subnet mask in IpAddress form. The netmask value for
211 * the returned IpAddress is 0, as the address itself is a mask.
212 *
213 * @return the subnet mask
214 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700215 public IpPrefix netmask() {
216 return new IpPrefix(Version.INET, bytes(mask()));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700217 }
218
219 /**
220 * Returns the network portion of this address as an IpAddress.
221 * The netmask of the returned IpAddress is the current mask. If this
222 * address doesn't have a mask, this returns an all-0 IpAddress.
223 *
224 * @return the network address or null
225 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700226 public IpPrefix network() {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700227 if (netmask == DEFAULT_MASK) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700228 return new IpPrefix(version, ANY, DEFAULT_MASK);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700229 }
230
231 byte [] net = new byte [4];
232 byte [] mask = bytes(mask());
233 for (int i = 0; i < INET_LEN; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700234 net[i] = (byte) (octets[i] & mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700235 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700236 return new IpPrefix(version, net, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700237 }
238
239 /**
240 * Returns the host portion of the IPAddress, as an IPAddress.
241 * The netmask of the returned IpAddress is the current mask. If this
242 * address doesn't have a mask, this returns a copy of the current
243 * address.
244 *
245 * @return the host address
246 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700247 public IpPrefix host() {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700248 if (netmask == DEFAULT_MASK) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700249 new IpPrefix(version, octets, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700250 }
251
252 byte [] host = new byte [INET_LEN];
253 byte [] mask = bytes(mask());
254 for (int i = 0; i < INET_LEN; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700255 host[i] = (byte) (octets[i] & ~mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700256 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700257 return new IpPrefix(version, host, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700258 }
259
Jonathan Hart70da5122014-10-01 16:37:42 -0700260 /**
261 * Returns an IpAddress of the bytes contained in this prefix.
262 * FIXME this is a hack for now and only works because IpPrefix doesn't
263 * mask the input bytes on creation.
264 *
265 * @return the IpAddress
266 */
267 public IpAddress toIpAddress() {
268 return IpAddress.valueOf(octets);
269 }
270
alshabib8f1cf4a2014-09-17 14:44:48 -0700271 public boolean isMasked() {
272 return mask() != 0;
273 }
274
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700275 /**
276 * Determines whether a given address is contained within this IpAddress'
277 * network.
278 *
279 * @param other another IP address that could be contained in this network
280 * @return true if the other IP address is contained in this address'
281 * network, otherwise false
282 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700283 public boolean contains(IpPrefix other) {
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700284 if (this.netmask <= other.netmask) {
285 // Special case where they're both /32 addresses
286 if (this.netmask == MAX_INET_MASK) {
287 return Arrays.equals(octets, other.octets);
288 }
289
290 // Mask the other address with our network mask
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700291 IpPrefix otherMasked =
292 IpPrefix.valueOf(other.octets, netmask).network();
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700293
294 return network().equals(otherMasked);
295 }
296 return false;
297 }
298
Jonathan Hart70da5122014-10-01 16:37:42 -0700299 public boolean contains(IpAddress address) {
300 // Need to get the network address because prefixes aren't automatically
301 // masked on creation
302 IpPrefix meMasked = network();
303
304 IpPrefix otherMasked =
305 IpPrefix.valueOf(address.octets, netmask).network();
306
307 return Arrays.equals(meMasked.octets, otherMasked.octets);
308 }
309
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700310 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700311 public int hashCode() {
312 final int prime = 31;
313 int result = 1;
314 result = prime * result + netmask;
315 result = prime * result + Arrays.hashCode(octets);
316 result = prime * result + ((version == null) ? 0 : version.hashCode());
317 return result;
318 }
319
320 @Override
321 public boolean equals(Object obj) {
322 if (this == obj) {
323 return true;
324 }
325 if (obj == null) {
326 return false;
327 }
328 if (getClass() != obj.getClass()) {
329 return false;
330 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700331 IpPrefix other = (IpPrefix) obj;
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700332 if (netmask != other.netmask) {
333 return false;
334 }
Jonathan Hart70da5122014-10-01 16:37:42 -0700335 // TODO not quite right until we mask the input
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700336 if (!Arrays.equals(octets, other.octets)) {
337 return false;
338 }
339 if (version != other.version) {
340 return false;
341 }
342 return true;
343 }
344
345 @Override
346 /*
347 * (non-Javadoc)
348 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
349 * and "x.x.x.x/y" for masked addresses.
350 *
351 * @see java.lang.Object#toString()
352 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700353 public String toString() {
354 final StringBuilder builder = new StringBuilder();
355 for (final byte b : this.octets) {
356 if (builder.length() > 0) {
357 builder.append(".");
358 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700359 builder.append(String.format("%d", b & 0xff));
360 }
361 if (netmask != DEFAULT_MASK) {
362 builder.append("/");
363 builder.append(String.format("%d", netmask));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700364 }
365 return builder.toString();
366 }
367
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700368}