blob: 21cec5c2f6861fe41cb9898a70c0cb54f1631249 [file] [log] [blame]
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -07001package org.onlab.packet;
2
3import java.util.Arrays;
4
5/**
Jonathan Hartdec62d42014-09-22 15:59:04 -07006 * A class representing an IPv4 prefix.
7 * <p/>
8 * A prefix consists of an IP address and a subnet mask.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -07009 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070010public final class IpPrefix {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070011
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070012 // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
13
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070014 //IP Versions
15 public enum Version { INET, INET6 };
16
Ayaka Koshibe04a1a4e2014-09-11 14:31:29 -070017 //lengths of address, in bytes
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070018 public static final int INET_LEN = 4;
Ayaka Koshibe3a25aec2014-09-12 11:52:53 -070019 public static final int INET6_LEN = 16;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070020
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070021 //maximum CIDR value
22 public static final int MAX_INET_MASK = 32;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070023 //no mask (no network), e.g. a simple address
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070024 public static final int DEFAULT_MASK = 0;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070025
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070026 /**
27 * Default value indicating an unspecified address.
28 */
Yuta HIGUCHI10681f62014-09-21 17:49:46 -070029 static final byte[] ANY = new byte [] {0, 0, 0, 0};
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070030
31 protected Version version;
32
33 protected byte[] octets;
34 protected int netmask;
35
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070036 private IpPrefix(Version ver, byte[] octets, int netmask) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070037 this.version = ver;
38 this.octets = Arrays.copyOf(octets, INET_LEN);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070039 this.netmask = netmask;
40 }
41
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070042 private IpPrefix(Version ver, byte[] octets) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070043 this.version = ver;
44 this.octets = Arrays.copyOf(octets, INET_LEN);
45 this.netmask = DEFAULT_MASK;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070046 }
47
48 /**
49 * Converts a byte array into an IP address.
50 *
51 * @param address a byte array
52 * @return an IP address
53 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070054 public static IpPrefix valueOf(byte [] address) {
55 return new IpPrefix(Version.INET, address);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070056 }
57
58 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070059 * Converts a byte array into an IP address.
60 *
61 * @param address a byte array
62 * @param netmask the CIDR value subnet mask
63 * @return an IP address
64 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070065 public static IpPrefix valueOf(byte [] address, int netmask) {
66 return new IpPrefix(Version.INET, address, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070067 }
68
69 /**
70 * Helper to convert an integer into a byte array.
71 *
72 * @param address the integer to convert
73 * @return a byte array
74 */
75 private static byte [] bytes(int address) {
76 byte [] bytes = new byte [INET_LEN];
77 for (int i = 0; i < INET_LEN; i++) {
78 bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
79 }
80
81 return bytes;
82 }
83
84 /**
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070085 * Converts an integer into an IPv4 address.
86 *
87 * @param address an integer representing an IP value
88 * @return an IP address
89 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070090 public static IpPrefix valueOf(int address) {
91 return new IpPrefix(Version.INET, bytes(address));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070092 }
93
94 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070095 * Converts an integer into an IPv4 address.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070096 *
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070097 * @param address an integer representing an IP value
98 * @param netmask the CIDR value subnet mask
99 * @return an IP address
100 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700101 public static IpPrefix valueOf(int address, int netmask) {
102 return new IpPrefix(Version.INET, bytes(address), netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700103 }
104
105 /**
106 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700107 * string can also be in CIDR (slash) notation. If the netmask is omitted,
108 * it will be set to DEFAULT_MASK (0).
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700109 *
110 * @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 -0700111 * @return an IP address
112 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700113 public static IpPrefix valueOf(String address) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700114
115 final String [] parts = address.split("\\/");
116 if (parts.length > 2) {
117 throw new IllegalArgumentException("Malformed IP address string; "
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700118 + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700119 }
120
121 int mask = DEFAULT_MASK;
122 if (parts.length == 2) {
Yuta HIGUCHI7f3df232014-10-15 23:38:24 -0700123 mask = Integer.parseInt(parts[1]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700124 if (mask > MAX_INET_MASK) {
125 throw new IllegalArgumentException(
126 "Value of subnet mask cannot exceed "
alshabib8f1cf4a2014-09-17 14:44:48 -0700127 + MAX_INET_MASK);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700128 }
129 }
130
131 final String [] net = parts[0].split("\\.");
132 if (net.length != INET_LEN) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700133 throw new IllegalArgumentException("Malformed IP address string; "
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700134 + "Address must have four decimal values separated by dots (.)");
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700135 }
136 final byte [] bytes = new byte[INET_LEN];
137 for (int i = 0; i < INET_LEN; i++) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700138 bytes[i] = (byte) Short.parseShort(net[i], 10);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700139 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700140 return new IpPrefix(Version.INET, bytes, mask);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700141 }
142
143 /**
144 * Returns the IP version of this address.
145 *
146 * @return the version
147 */
148 public Version version() {
149 return this.version;
150 }
151
152 /**
153 * Returns the IP address as a byte array.
154 *
155 * @return a byte array
156 */
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700157 public byte[] toOctets() {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700158 return Arrays.copyOf(this.octets, INET_LEN);
159 }
160
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700161 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700162 * Returns the IP address prefix length.
163 *
164 * @return prefix length
165 */
166 public int prefixLength() {
167 return netmask;
168 }
169
170 /**
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700171 * Returns the integral value of this IP address.
172 *
173 * @return the IP address's value as an integer
174 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700175 public int toInt() {
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700176 int address = 0;
177 for (int i = 0; i < INET_LEN; i++) {
178 address |= octets[i] << ((INET_LEN - (i + 1)) * 8);
179 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700180 return address;
181 }
182
alshabib6eb438a2014-10-01 16:39:37 -0700183 public int toRealInt() {
184 int val = 0;
185 for (int i = 0; i < octets.length; i++) {
186 val <<= 8;
187 val |= octets[i] & 0xff;
188 }
189 return val;
190 }
191
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700192 /**
193 * Helper for computing the mask value from CIDR.
194 *
195 * @return an integer bitmask
196 */
197 private int mask() {
198 int shift = MAX_INET_MASK - this.netmask;
199 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
200 }
201
202 /**
203 * Returns the subnet mask in IpAddress form. The netmask value for
204 * the returned IpAddress is 0, as the address itself is a mask.
205 *
206 * @return the subnet mask
207 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700208 public IpPrefix netmask() {
209 return new IpPrefix(Version.INET, bytes(mask()));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700210 }
211
212 /**
213 * Returns the network portion of this address as an IpAddress.
214 * The netmask of the returned IpAddress is the current mask. If this
215 * address doesn't have a mask, this returns an all-0 IpAddress.
216 *
217 * @return the network address or null
218 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700219 public IpPrefix network() {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700220 if (netmask == DEFAULT_MASK) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700221 return new IpPrefix(version, ANY, DEFAULT_MASK);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700222 }
223
224 byte [] net = new byte [4];
225 byte [] mask = bytes(mask());
226 for (int i = 0; i < INET_LEN; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700227 net[i] = (byte) (octets[i] & mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700228 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700229 return new IpPrefix(version, net, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700230 }
231
232 /**
233 * Returns the host portion of the IPAddress, as an IPAddress.
234 * The netmask of the returned IpAddress is the current mask. If this
235 * address doesn't have a mask, this returns a copy of the current
236 * address.
237 *
238 * @return the host address
239 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700240 public IpPrefix host() {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700241 if (netmask == DEFAULT_MASK) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700242 new IpPrefix(version, octets, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700243 }
244
245 byte [] host = new byte [INET_LEN];
246 byte [] mask = bytes(mask());
247 for (int i = 0; i < INET_LEN; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700248 host[i] = (byte) (octets[i] & ~mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700249 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700250 return new IpPrefix(version, host, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700251 }
252
Jonathan Hart70da5122014-10-01 16:37:42 -0700253 /**
254 * Returns an IpAddress of the bytes contained in this prefix.
255 * FIXME this is a hack for now and only works because IpPrefix doesn't
256 * mask the input bytes on creation.
257 *
258 * @return the IpAddress
259 */
260 public IpAddress toIpAddress() {
261 return IpAddress.valueOf(octets);
262 }
263
alshabib8f1cf4a2014-09-17 14:44:48 -0700264 public boolean isMasked() {
265 return mask() != 0;
266 }
267
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700268 /**
269 * Determines whether a given address is contained within this IpAddress'
270 * network.
271 *
272 * @param other another IP address that could be contained in this network
273 * @return true if the other IP address is contained in this address'
274 * network, otherwise false
275 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700276 public boolean contains(IpPrefix other) {
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700277 if (this.netmask <= other.netmask) {
278 // Special case where they're both /32 addresses
279 if (this.netmask == MAX_INET_MASK) {
280 return Arrays.equals(octets, other.octets);
281 }
282
283 // Mask the other address with our network mask
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700284 IpPrefix otherMasked =
285 IpPrefix.valueOf(other.octets, netmask).network();
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700286
287 return network().equals(otherMasked);
288 }
289 return false;
290 }
291
Jonathan Hart70da5122014-10-01 16:37:42 -0700292 public boolean contains(IpAddress address) {
293 // Need to get the network address because prefixes aren't automatically
294 // masked on creation
295 IpPrefix meMasked = network();
296
297 IpPrefix otherMasked =
298 IpPrefix.valueOf(address.octets, netmask).network();
299
300 return Arrays.equals(meMasked.octets, otherMasked.octets);
301 }
302
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700303 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700304 public int hashCode() {
305 final int prime = 31;
306 int result = 1;
307 result = prime * result + netmask;
308 result = prime * result + Arrays.hashCode(octets);
309 result = prime * result + ((version == null) ? 0 : version.hashCode());
310 return result;
311 }
312
313 @Override
314 public boolean equals(Object obj) {
315 if (this == obj) {
316 return true;
317 }
318 if (obj == null) {
319 return false;
320 }
321 if (getClass() != obj.getClass()) {
322 return false;
323 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700324 IpPrefix other = (IpPrefix) obj;
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700325 if (netmask != other.netmask) {
326 return false;
327 }
Jonathan Hart70da5122014-10-01 16:37:42 -0700328 // TODO not quite right until we mask the input
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700329 if (!Arrays.equals(octets, other.octets)) {
330 return false;
331 }
332 if (version != other.version) {
333 return false;
334 }
335 return true;
336 }
337
338 @Override
339 /*
340 * (non-Javadoc)
341 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
342 * and "x.x.x.x/y" for masked addresses.
343 *
344 * @see java.lang.Object#toString()
345 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700346 public String toString() {
347 final StringBuilder builder = new StringBuilder();
348 for (final byte b : this.octets) {
349 if (builder.length() > 0) {
350 builder.append(".");
351 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700352 builder.append(String.format("%d", b & 0xff));
353 }
354 if (netmask != DEFAULT_MASK) {
355 builder.append("/");
356 builder.append(String.format("%d", netmask));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700357 }
358 return builder.toString();
359 }
360
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700361}