blob: f466122a8d3d9ff66f781f6f71184732ecc8dae1 [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) {
123 mask = Integer.valueOf(parts[1]);
124 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
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700183 /**
184 * Helper for computing the mask value from CIDR.
185 *
186 * @return an integer bitmask
187 */
188 private int mask() {
189 int shift = MAX_INET_MASK - this.netmask;
190 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
191 }
192
193 /**
194 * Returns the subnet mask in IpAddress form. The netmask value for
195 * the returned IpAddress is 0, as the address itself is a mask.
196 *
197 * @return the subnet mask
198 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700199 public IpPrefix netmask() {
200 return new IpPrefix(Version.INET, bytes(mask()));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700201 }
202
203 /**
204 * Returns the network portion of this address as an IpAddress.
205 * The netmask of the returned IpAddress is the current mask. If this
206 * address doesn't have a mask, this returns an all-0 IpAddress.
207 *
208 * @return the network address or null
209 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700210 public IpPrefix network() {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700211 if (netmask == DEFAULT_MASK) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700212 return new IpPrefix(version, ANY, DEFAULT_MASK);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700213 }
214
215 byte [] net = new byte [4];
216 byte [] mask = bytes(mask());
217 for (int i = 0; i < INET_LEN; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700218 net[i] = (byte) (octets[i] & mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700219 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700220 return new IpPrefix(version, net, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700221 }
222
223 /**
224 * Returns the host portion of the IPAddress, as an IPAddress.
225 * The netmask of the returned IpAddress is the current mask. If this
226 * address doesn't have a mask, this returns a copy of the current
227 * address.
228 *
229 * @return the host address
230 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700231 public IpPrefix host() {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700232 if (netmask == DEFAULT_MASK) {
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700233 new IpPrefix(version, octets, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700234 }
235
236 byte [] host = new byte [INET_LEN];
237 byte [] mask = bytes(mask());
238 for (int i = 0; i < INET_LEN; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700239 host[i] = (byte) (octets[i] & ~mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700240 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700241 return new IpPrefix(version, host, netmask);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700242 }
243
alshabib8f1cf4a2014-09-17 14:44:48 -0700244 public boolean isMasked() {
245 return mask() != 0;
246 }
247
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700248 /**
249 * Determines whether a given address is contained within this IpAddress'
250 * network.
251 *
252 * @param other another IP address that could be contained in this network
253 * @return true if the other IP address is contained in this address'
254 * network, otherwise false
255 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700256 public boolean contains(IpPrefix other) {
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700257 if (this.netmask <= other.netmask) {
258 // Special case where they're both /32 addresses
259 if (this.netmask == MAX_INET_MASK) {
260 return Arrays.equals(octets, other.octets);
261 }
262
263 // Mask the other address with our network mask
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700264 IpPrefix otherMasked =
265 IpPrefix.valueOf(other.octets, netmask).network();
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700266
267 return network().equals(otherMasked);
268 }
269 return false;
270 }
271
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700272 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700273 public int hashCode() {
274 final int prime = 31;
275 int result = 1;
276 result = prime * result + netmask;
277 result = prime * result + Arrays.hashCode(octets);
278 result = prime * result + ((version == null) ? 0 : version.hashCode());
279 return result;
280 }
281
282 @Override
283 public boolean equals(Object obj) {
284 if (this == obj) {
285 return true;
286 }
287 if (obj == null) {
288 return false;
289 }
290 if (getClass() != obj.getClass()) {
291 return false;
292 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700293 IpPrefix other = (IpPrefix) obj;
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700294 if (netmask != other.netmask) {
295 return false;
296 }
297 if (!Arrays.equals(octets, other.octets)) {
298 return false;
299 }
300 if (version != other.version) {
301 return false;
302 }
303 return true;
304 }
305
306 @Override
307 /*
308 * (non-Javadoc)
309 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
310 * and "x.x.x.x/y" for masked addresses.
311 *
312 * @see java.lang.Object#toString()
313 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700314 public String toString() {
315 final StringBuilder builder = new StringBuilder();
316 for (final byte b : this.octets) {
317 if (builder.length() > 0) {
318 builder.append(".");
319 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700320 builder.append(String.format("%d", b & 0xff));
321 }
322 if (netmask != DEFAULT_MASK) {
323 builder.append("/");
324 builder.append(String.format("%d", netmask));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700325 }
326 return builder.toString();
327 }
328
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700329}