blob: e8641255f04b39b62eb702244ded22bbaf925715 [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
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070029 // IP Versions: IPv4 and IPv6
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070030 public enum Version { INET, INET6 };
31
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070032 // Maximum network mask length
33 public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH;
34 public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070035
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070036 //no mask (no network), e.g. a simple address
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070037 private static final int DEFAULT_MASK = 0;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070038
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070039 /**
40 * Default value indicating an unspecified address.
41 */
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070042 private static final byte[] ANY = new byte[] {0, 0, 0, 0};
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070043
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070044 private final Version version;
45 private final byte[] octets;
46 private final int netmask;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070047
48 /**
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070049 * Constructor for given IP address version, prefix address octets,
50 * and network mask length.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070051 *
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070052 * @param ver the IP address version
53 * @param octets the IP prefix address octets
54 * @param netmask the network mask length
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070055 */
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070056 private IpPrefix(Version ver, byte[] octets, int netmask) {
57 this.version = ver;
58 this.octets = Arrays.copyOf(octets, IpAddress.INET_BYTE_LENGTH);
59 this.netmask = netmask;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070060 }
61
62 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070063 * Converts a byte array into an IP address.
64 *
65 * @param address a byte array
66 * @param netmask the CIDR value subnet mask
67 * @return an IP address
68 */
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070069 public static IpPrefix valueOf(byte[] address, int netmask) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070070 return new IpPrefix(Version.INET, address, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070071 }
72
73 /**
74 * Helper to convert an integer into a byte array.
75 *
76 * @param address the integer to convert
77 * @return a byte array
78 */
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070079 private static byte[] bytes(int address) {
80 byte[] bytes = new byte [IpAddress.INET_BYTE_LENGTH];
81 for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
82 bytes[i] = (byte) ((address >> (IpAddress.INET_BYTE_LENGTH
83 - (i + 1)) * 8) & 0xff);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070084 }
85
86 return bytes;
87 }
88
89 /**
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070090 * Converts an integer into an IPv4 address.
91 *
92 * @param address an integer representing an IP value
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070093 * @param netmask the CIDR value subnet mask
94 * @return an IP address
95 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070096 public static IpPrefix valueOf(int address, int netmask) {
97 return new IpPrefix(Version.INET, bytes(address), netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070098 }
99
100 /**
101 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700102 * string can also be in CIDR (slash) notation. If the netmask is omitted,
103 * it will be set to DEFAULT_MASK (0).
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700104 *
105 * @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 -0700106 * @return an IP address
107 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700108 public static IpPrefix valueOf(String address) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700109
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700110 final String[] parts = address.split("\\/");
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700111 if (parts.length > 2) {
112 throw new IllegalArgumentException("Malformed IP address string; "
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700113 + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700114 }
115
116 int mask = DEFAULT_MASK;
117 if (parts.length == 2) {
Yuta HIGUCHI7f3df232014-10-15 23:38:24 -0700118 mask = Integer.parseInt(parts[1]);
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700119 if (mask > MAX_INET_MASK_LENGTH) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700120 throw new IllegalArgumentException(
121 "Value of subnet mask cannot exceed "
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700122 + MAX_INET_MASK_LENGTH);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700123 }
124 }
125
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700126 final String[] net = parts[0].split("\\.");
127 if (net.length != IpAddress.INET_BYTE_LENGTH) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700128 throw new IllegalArgumentException("Malformed IP address string; "
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700129 + "Address must have four decimal values separated by dots (.)");
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700130 }
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700131 final byte[] bytes = new byte[IpAddress.INET_BYTE_LENGTH];
132 for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700133 bytes[i] = (byte) Short.parseShort(net[i], 10);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700134 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700135 return new IpPrefix(Version.INET, bytes, mask);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700136 }
137
138 /**
139 * Returns the IP version of this address.
140 *
141 * @return the version
142 */
143 public Version version() {
144 return this.version;
145 }
146
147 /**
148 * Returns the IP address as a byte array.
149 *
150 * @return a byte array
151 */
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700152 public byte[] toOctets() {
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700153 return Arrays.copyOf(this.octets, IpAddress.INET_BYTE_LENGTH);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700154 }
155
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700156 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700157 * Returns the IP address prefix length.
158 *
159 * @return prefix length
160 */
161 public int prefixLength() {
162 return netmask;
163 }
164
165 /**
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700166 * Returns the integral value of this IP address.
167 *
168 * @return the IP address's value as an integer
169 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700170 public int toInt() {
alshabib6eb438a2014-10-01 16:39:37 -0700171 int val = 0;
172 for (int i = 0; i < octets.length; i++) {
173 val <<= 8;
174 val |= octets[i] & 0xff;
175 }
176 return val;
177 }
178
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700179 /**
180 * Helper for computing the mask value from CIDR.
181 *
182 * @return an integer bitmask
183 */
184 private int mask() {
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700185 int shift = MAX_INET_MASK_LENGTH - this.netmask;
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700186 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
187 }
188
189 /**
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700190 * Returns the subnet mask in IpAddress form.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700191 *
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700192 * @return the subnet mask as an IpAddress
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700193 */
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700194 public IpAddress netmask() {
195 return IpAddress.valueOf(mask());
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700196 }
197
198 /**
199 * Returns the network portion of this address as an IpAddress.
200 * The netmask of the returned IpAddress is the current mask. If this
201 * address doesn't have a mask, this returns an all-0 IpAddress.
202 *
203 * @return the network address or null
204 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700205 public IpPrefix network() {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700206 if (netmask == DEFAULT_MASK) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700207 return new IpPrefix(version, ANY, DEFAULT_MASK);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700208 }
209
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700210 byte[] net = new byte [4];
211 byte[] mask = bytes(mask());
212 for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700213 net[i] = (byte) (octets[i] & mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700214 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700215 return new IpPrefix(version, net, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700216 }
217
218 /**
219 * Returns the host portion of the IPAddress, as an IPAddress.
220 * The netmask of the returned IpAddress is the current mask. If this
221 * address doesn't have a mask, this returns a copy of the current
222 * address.
223 *
224 * @return the host address
225 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700226 public IpPrefix host() {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700227 if (netmask == DEFAULT_MASK) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700228 new IpPrefix(version, octets, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700229 }
230
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700231 byte[] host = new byte [IpAddress.INET_BYTE_LENGTH];
232 byte[] mask = bytes(mask());
233 for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700234 host[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, host, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700237 }
238
Jonathan Hart70da5122014-10-01 16:37:42 -0700239 /**
240 * Returns an IpAddress of the bytes contained in this prefix.
241 * FIXME this is a hack for now and only works because IpPrefix doesn't
242 * mask the input bytes on creation.
243 *
244 * @return the IpAddress
245 */
246 public IpAddress toIpAddress() {
247 return IpAddress.valueOf(octets);
248 }
249
alshabib8f1cf4a2014-09-17 14:44:48 -0700250 public boolean isMasked() {
251 return mask() != 0;
252 }
253
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700254 /**
255 * Determines whether a given address is contained within this IpAddress'
256 * network.
257 *
258 * @param other another IP address that could be contained in this network
259 * @return true if the other IP address is contained in this address'
260 * network, otherwise false
261 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700262 public boolean contains(IpPrefix other) {
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700263 if (this.netmask <= other.netmask) {
264 // Special case where they're both /32 addresses
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700265 if (this.netmask == MAX_INET_MASK_LENGTH) {
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700266 return Arrays.equals(octets, other.octets);
267 }
268
269 // Mask the other address with our network mask
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700270 IpPrefix otherMasked =
271 IpPrefix.valueOf(other.octets, netmask).network();
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700272
273 return network().equals(otherMasked);
274 }
275 return false;
276 }
277
Jonathan Hart70da5122014-10-01 16:37:42 -0700278 public boolean contains(IpAddress address) {
279 // Need to get the network address because prefixes aren't automatically
280 // masked on creation
281 IpPrefix meMasked = network();
282
283 IpPrefix otherMasked =
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700284 IpPrefix.valueOf(address.toOctets(), netmask).network();
Jonathan Hart70da5122014-10-01 16:37:42 -0700285
286 return Arrays.equals(meMasked.octets, otherMasked.octets);
287 }
288
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700289 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700290 public int hashCode() {
291 final int prime = 31;
292 int result = 1;
293 result = prime * result + netmask;
294 result = prime * result + Arrays.hashCode(octets);
295 result = prime * result + ((version == null) ? 0 : version.hashCode());
296 return result;
297 }
298
299 @Override
300 public boolean equals(Object obj) {
301 if (this == obj) {
302 return true;
303 }
304 if (obj == null) {
305 return false;
306 }
307 if (getClass() != obj.getClass()) {
308 return false;
309 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700310 IpPrefix other = (IpPrefix) obj;
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700311 if (netmask != other.netmask) {
312 return false;
313 }
Jonathan Hart70da5122014-10-01 16:37:42 -0700314 // TODO not quite right until we mask the input
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700315 if (!Arrays.equals(octets, other.octets)) {
316 return false;
317 }
318 if (version != other.version) {
319 return false;
320 }
321 return true;
322 }
323
324 @Override
325 /*
326 * (non-Javadoc)
327 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
328 * and "x.x.x.x/y" for masked addresses.
329 *
330 * @see java.lang.Object#toString()
331 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700332 public String toString() {
333 final StringBuilder builder = new StringBuilder();
334 for (final byte b : this.octets) {
335 if (builder.length() > 0) {
336 builder.append(".");
337 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700338 builder.append(String.format("%d", b & 0xff));
339 }
340 if (netmask != DEFAULT_MASK) {
341 builder.append("/");
342 builder.append(String.format("%d", netmask));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700343 }
344 return builder.toString();
345 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700346}