blob: 1c2bc1bc559e79c417daf34a419aef33b708ca2c [file] [log] [blame]
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -07001package org.onlab.packet;
2
3import java.util.Arrays;
4
5/**
6 * A class representing an IPv4 address.
7 */
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -07008public final class IpAddress {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -07009
10 //IP Versions
11 public enum Version { INET, INET6 };
12
Ayaka Koshibe04a1a4e2014-09-11 14:31:29 -070013 //lengths of address, in bytes
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070014 public static final int INET_LEN = 4;
Ayaka Koshibe3a25aec2014-09-12 11:52:53 -070015 public static final int INET6_LEN = 16;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070016
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070017 //maximum CIDR value
18 public static final int MAX_INET_MASK = 32;
19 public static final int DEFAULT_MASK = 0;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070020
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070021 /**
22 * Default value indicating an unspecified address.
23 */
24 public static final byte [] ANY = new byte [] {0, 0, 0, 0};
25
26 protected Version version;
27
28 protected byte[] octets;
29 protected int netmask;
30
31 private IpAddress(Version ver, byte[] octets, int netmask) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070032 this.version = ver;
33 this.octets = Arrays.copyOf(octets, INET_LEN);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070034 this.netmask = netmask;
35 }
36
37 private IpAddress(Version ver, byte[] octets) {
38 this.version = ver;
39 this.octets = Arrays.copyOf(octets, INET_LEN);
40 this.netmask = DEFAULT_MASK;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070041 }
42
43 /**
44 * Converts a byte array into an IP address.
45 *
46 * @param address a byte array
47 * @return an IP address
48 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070049 public static IpAddress valueOf(byte [] address) {
50 return new IpAddress(Version.INET, address);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070051 }
52
53 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070054 * Converts a byte array into an IP address.
55 *
56 * @param address a byte array
57 * @param netmask the CIDR value subnet mask
58 * @return an IP address
59 */
60 public static IpAddress valueOf(byte [] address, int netmask) {
61 return new IpAddress(Version.INET, address, netmask);
62 }
63
64 /**
65 * Helper to convert an integer into a byte array.
66 *
67 * @param address the integer to convert
68 * @return a byte array
69 */
70 private static byte [] bytes(int address) {
71 byte [] bytes = new byte [INET_LEN];
72 for (int i = 0; i < INET_LEN; i++) {
73 bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
74 }
75
76 return bytes;
77 }
78
79 /**
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070080 * Converts an integer into an IPv4 address.
81 *
82 * @param address an integer representing an IP value
83 * @return an IP address
84 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070085 public static IpAddress valueOf(int address) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070086 return new IpAddress(Version.INET, bytes(address));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070087 }
88
89 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070090 * Converts an integer into an IPv4 address.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070091 *
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070092 * @param address an integer representing an IP value
93 * @param netmask the CIDR value subnet mask
94 * @return an IP address
95 */
96 public static IpAddress valueOf(int address, int netmask) {
97 return new IpAddress(Version.INET, bytes(address), netmask);
98 }
99
100 /**
101 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
102 * string can also be in CIDR (slash) notation.
103 *
104 * @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 -0700105 * @return an IP address
106 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700107 public static IpAddress valueOf(String address) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700108
109 final String [] parts = address.split("\\/");
110 if (parts.length > 2) {
111 throw new IllegalArgumentException("Malformed IP address string; "
112 + "Addres must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
113 }
114
115 int mask = DEFAULT_MASK;
116 if (parts.length == 2) {
117 mask = Integer.valueOf(parts[1]);
118 if (mask > MAX_INET_MASK) {
119 throw new IllegalArgumentException(
120 "Value of subnet mask cannot exceed "
alshabib8f1cf4a2014-09-17 14:44:48 -0700121 + MAX_INET_MASK);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700122 }
123 }
124
125 final String [] net = parts[0].split("\\.");
126 if (net.length != INET_LEN) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700127 throw new IllegalArgumentException("Malformed IP address string; "
128 + "Addres must have four decimal values separated by dots (.)");
129 }
130 final byte [] bytes = new byte[INET_LEN];
131 for (int i = 0; i < INET_LEN; i++) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700132 bytes[i] = (byte) Short.parseShort(net[i], 10);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700133 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700134 return new IpAddress(Version.INET, bytes, mask);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700135 }
136
137 /**
138 * Returns the IP version of this address.
139 *
140 * @return the version
141 */
142 public Version version() {
143 return this.version;
144 }
145
146 /**
147 * Returns the IP address as a byte array.
148 *
149 * @return a byte array
150 */
151 public byte [] toOctets() {
152 return Arrays.copyOf(this.octets, INET_LEN);
153 }
154
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700155 /**
156 * Returns the integral value of this IP address.
157 *
158 * @return the IP address's value as an integer
159 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700160 public int toInt() {
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700161 int address = 0;
162 for (int i = 0; i < INET_LEN; i++) {
163 address |= octets[i] << ((INET_LEN - (i + 1)) * 8);
164 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700165 return address;
166 }
167
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700168 /**
169 * Helper for computing the mask value from CIDR.
170 *
171 * @return an integer bitmask
172 */
173 private int mask() {
174 int shift = MAX_INET_MASK - this.netmask;
175 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
176 }
177
178 /**
179 * Returns the subnet mask in IpAddress form. The netmask value for
180 * the returned IpAddress is 0, as the address itself is a mask.
181 *
182 * @return the subnet mask
183 */
184 public IpAddress netmask() {
185 return new IpAddress(Version.INET, bytes(mask()));
186 }
187
188 /**
189 * Returns the network portion of this address as an IpAddress.
190 * The netmask of the returned IpAddress is the current mask. If this
191 * address doesn't have a mask, this returns an all-0 IpAddress.
192 *
193 * @return the network address or null
194 */
195 public IpAddress network() {
196 if (netmask == DEFAULT_MASK) {
197 return new IpAddress(version, ANY, DEFAULT_MASK);
198 }
199
200 byte [] net = new byte [4];
201 byte [] mask = bytes(mask());
202 for (int i = 0; i < INET_LEN; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700203 net[i] = (byte) (octets[i] & mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700204 }
205 return new IpAddress(version, net, netmask);
206 }
207
208 /**
209 * Returns the host portion of the IPAddress, as an IPAddress.
210 * The netmask of the returned IpAddress is the current mask. If this
211 * address doesn't have a mask, this returns a copy of the current
212 * address.
213 *
214 * @return the host address
215 */
216 public IpAddress host() {
217 if (netmask == DEFAULT_MASK) {
218 new IpAddress(version, octets, netmask);
219 }
220
221 byte [] host = new byte [INET_LEN];
222 byte [] mask = bytes(mask());
223 for (int i = 0; i < INET_LEN; i++) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700224 host[i] = (byte) (octets[i] & ~mask[i]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700225 }
226 return new IpAddress(version, host, netmask);
227 }
228
alshabib8f1cf4a2014-09-17 14:44:48 -0700229 public boolean isMasked() {
230 return mask() != 0;
231 }
232
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700233 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700234 public int hashCode() {
235 final int prime = 31;
236 int result = 1;
237 result = prime * result + netmask;
238 result = prime * result + Arrays.hashCode(octets);
239 result = prime * result + ((version == null) ? 0 : version.hashCode());
240 return result;
241 }
242
243 @Override
244 public boolean equals(Object obj) {
245 if (this == obj) {
246 return true;
247 }
248 if (obj == null) {
249 return false;
250 }
251 if (getClass() != obj.getClass()) {
252 return false;
253 }
254 IpAddress other = (IpAddress) obj;
255 if (netmask != other.netmask) {
256 return false;
257 }
258 if (!Arrays.equals(octets, other.octets)) {
259 return false;
260 }
261 if (version != other.version) {
262 return false;
263 }
264 return true;
265 }
266
267 @Override
268 /*
269 * (non-Javadoc)
270 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
271 * and "x.x.x.x/y" for masked addresses.
272 *
273 * @see java.lang.Object#toString()
274 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700275 public String toString() {
276 final StringBuilder builder = new StringBuilder();
277 for (final byte b : this.octets) {
278 if (builder.length() > 0) {
279 builder.append(".");
280 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700281 builder.append(String.format("%d", b & 0xff));
282 }
283 if (netmask != DEFAULT_MASK) {
284 builder.append("/");
285 builder.append(String.format("%d", netmask));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700286 }
287 return builder.toString();
288 }
289
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700290}