blob: 7669cc59fd979d313a9d9741b403058201504e16 [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
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070010 // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
11
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070012 //IP Versions
13 public enum Version { INET, INET6 };
14
Ayaka Koshibe04a1a4e2014-09-11 14:31:29 -070015 //lengths of address, in bytes
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070016 public static final int INET_LEN = 4;
Ayaka Koshibe3a25aec2014-09-12 11:52:53 -070017 public static final int INET6_LEN = 16;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070018
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070019 //maximum CIDR value
20 public static final int MAX_INET_MASK = 32;
21 public static final int DEFAULT_MASK = 0;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070022
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070023 /**
24 * Default value indicating an unspecified address.
25 */
26 public static final byte [] ANY = new byte [] {0, 0, 0, 0};
27
28 protected Version version;
29
30 protected byte[] octets;
31 protected int netmask;
32
33 private IpAddress(Version ver, byte[] octets, int netmask) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070034 this.version = ver;
35 this.octets = Arrays.copyOf(octets, INET_LEN);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070036 this.netmask = netmask;
37 }
38
39 private IpAddress(Version ver, byte[] octets) {
40 this.version = ver;
41 this.octets = Arrays.copyOf(octets, INET_LEN);
42 this.netmask = DEFAULT_MASK;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070043 }
44
45 /**
46 * Converts a byte array into an IP address.
47 *
48 * @param address a byte array
49 * @return an IP address
50 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070051 public static IpAddress valueOf(byte [] address) {
52 return new IpAddress(Version.INET, address);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070053 }
54
55 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070056 * Converts a byte array into an IP address.
57 *
58 * @param address a byte array
59 * @param netmask the CIDR value subnet mask
60 * @return an IP address
61 */
62 public static IpAddress valueOf(byte [] address, int netmask) {
63 return new IpAddress(Version.INET, address, netmask);
64 }
65
66 /**
67 * Helper to convert an integer into a byte array.
68 *
69 * @param address the integer to convert
70 * @return a byte array
71 */
72 private static byte [] bytes(int address) {
73 byte [] bytes = new byte [INET_LEN];
74 for (int i = 0; i < INET_LEN; i++) {
75 bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
76 }
77
78 return bytes;
79 }
80
81 /**
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070082 * Converts an integer into an IPv4 address.
83 *
84 * @param address an integer representing an IP value
85 * @return an IP address
86 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070087 public static IpAddress valueOf(int address) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070088 return new IpAddress(Version.INET, bytes(address));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070089 }
90
91 /**
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070092 * Converts an integer into an IPv4 address.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070093 *
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070094 * @param address an integer representing an IP value
95 * @param netmask the CIDR value subnet mask
96 * @return an IP address
97 */
98 public static IpAddress valueOf(int address, int netmask) {
99 return new IpAddress(Version.INET, bytes(address), netmask);
100 }
101
102 /**
103 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700104 * string can also be in CIDR (slash) notation. If the netmask is omitted,
105 * it will be set to DEFAULT_MASK (0).
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700106 *
107 * @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 -0700108 * @return an IP address
109 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700110 public static IpAddress valueOf(String address) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700111
112 final String [] parts = address.split("\\/");
113 if (parts.length > 2) {
114 throw new IllegalArgumentException("Malformed IP address string; "
115 + "Addres must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
116 }
117
118 int mask = DEFAULT_MASK;
119 if (parts.length == 2) {
120 mask = Integer.valueOf(parts[1]);
121 if (mask > MAX_INET_MASK) {
122 throw new IllegalArgumentException(
123 "Value of subnet mask cannot exceed "
124 + MAX_INET_MASK);
125 }
126 }
127
128 final String [] net = parts[0].split("\\.");
129 if (net.length != INET_LEN) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700130 throw new IllegalArgumentException("Malformed IP address string; "
131 + "Addres must have four decimal values separated by dots (.)");
132 }
133 final byte [] bytes = new byte[INET_LEN];
134 for (int i = 0; i < INET_LEN; i++) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700135 bytes[i] = (byte) Short.parseShort(net[i], 10);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700136 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700137 return new IpAddress(Version.INET, bytes, mask);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700138 }
139
140 /**
141 * Returns the IP version of this address.
142 *
143 * @return the version
144 */
145 public Version version() {
146 return this.version;
147 }
148
149 /**
150 * Returns the IP address as a byte array.
151 *
152 * @return a byte array
153 */
154 public byte [] toOctets() {
155 return Arrays.copyOf(this.octets, INET_LEN);
156 }
157
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700158 /**
159 * Returns the integral value of this IP address.
160 *
161 * @return the IP address's value as an integer
162 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700163 public int toInt() {
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700164 int address = 0;
165 for (int i = 0; i < INET_LEN; i++) {
166 address |= octets[i] << ((INET_LEN - (i + 1)) * 8);
167 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700168 return address;
169 }
170
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700171 /**
172 * Helper for computing the mask value from CIDR.
173 *
174 * @return an integer bitmask
175 */
176 private int mask() {
177 int shift = MAX_INET_MASK - this.netmask;
178 return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
179 }
180
181 /**
182 * Returns the subnet mask in IpAddress form. The netmask value for
183 * the returned IpAddress is 0, as the address itself is a mask.
184 *
185 * @return the subnet mask
186 */
187 public IpAddress netmask() {
188 return new IpAddress(Version.INET, bytes(mask()));
189 }
190
191 /**
192 * Returns the network portion of this address as an IpAddress.
193 * The netmask of the returned IpAddress is the current mask. If this
194 * address doesn't have a mask, this returns an all-0 IpAddress.
195 *
196 * @return the network address or null
197 */
198 public IpAddress network() {
199 if (netmask == DEFAULT_MASK) {
200 return new IpAddress(version, ANY, DEFAULT_MASK);
201 }
202
203 byte [] net = new byte [4];
204 byte [] mask = bytes(mask());
205 for (int i = 0; i < INET_LEN; i++) {
206 net[i] = (byte) (octets[i] & mask[i]);
207 }
208 return new IpAddress(version, net, netmask);
209 }
210
211 /**
212 * Returns the host portion of the IPAddress, as an IPAddress.
213 * The netmask of the returned IpAddress is the current mask. If this
214 * address doesn't have a mask, this returns a copy of the current
215 * address.
216 *
217 * @return the host address
218 */
219 public IpAddress host() {
220 if (netmask == DEFAULT_MASK) {
221 new IpAddress(version, octets, netmask);
222 }
223
224 byte [] host = new byte [INET_LEN];
225 byte [] mask = bytes(mask());
226 for (int i = 0; i < INET_LEN; i++) {
227 host[i] = (byte) (octets[i] & ~mask[i]);
228 }
229 return new IpAddress(version, host, netmask);
230 }
231
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700232 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700233 public int hashCode() {
234 final int prime = 31;
235 int result = 1;
236 result = prime * result + netmask;
237 result = prime * result + Arrays.hashCode(octets);
238 result = prime * result + ((version == null) ? 0 : version.hashCode());
239 return result;
240 }
241
242 @Override
243 public boolean equals(Object obj) {
244 if (this == obj) {
245 return true;
246 }
247 if (obj == null) {
248 return false;
249 }
250 if (getClass() != obj.getClass()) {
251 return false;
252 }
253 IpAddress other = (IpAddress) obj;
254 if (netmask != other.netmask) {
255 return false;
256 }
257 if (!Arrays.equals(octets, other.octets)) {
258 return false;
259 }
260 if (version != other.version) {
261 return false;
262 }
263 return true;
264 }
265
266 @Override
267 /*
268 * (non-Javadoc)
269 * format is "x.x.x.x" for non-masked (netmask 0) addresses,
270 * and "x.x.x.x/y" for masked addresses.
271 *
272 * @see java.lang.Object#toString()
273 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700274 public String toString() {
275 final StringBuilder builder = new StringBuilder();
276 for (final byte b : this.octets) {
277 if (builder.length() > 0) {
278 builder.append(".");
279 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700280 builder.append(String.format("%d", b & 0xff));
281 }
282 if (netmask != DEFAULT_MASK) {
283 builder.append("/");
284 builder.append(String.format("%d", netmask));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700285 }
286 return builder.toString();
287 }
288
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700289}