blob: 53e80718999122efbfd9f876fa78e4da1f13310a [file] [log] [blame]
Yotam Harcholf3f11152013-09-05 16:47:16 -07001package org.projectfloodlight.openflow.types;
2
Ronald Liffa80792014-07-04 17:50:49 -07003import java.net.Inet4Address;
Ronald Liaf8d3e72014-07-05 01:26:28 -07004import java.net.InetAddress;
Andreas Wundsam5f71b412014-02-18 12:56:35 -08005import java.util.Arrays;
6
Andreas Wundsam3700d162014-03-11 04:43:38 -07007import javax.annotation.Nonnull;
8
Yotam Harcholf3f11152013-09-05 16:47:16 -07009import org.jboss.netty.buffer.ChannelBuffer;
10
Sovietaced9dfc1ef2014-06-27 11:13:57 -070011import com.google.common.base.Preconditions;
Andreas Wundsam22ba3af2013-10-04 16:00:30 -070012import com.google.common.hash.PrimitiveSink;
Andreas Wundsam85c961f2013-09-29 21:22:12 -070013import com.google.common.primitives.UnsignedInts;
14
Byungjoon Leeba92e292014-07-18 13:13:26 +090015import org.projectfloodlight.openflow.protocol.Writeable;
16import org.projectfloodlight.openflow.protocol.OFMessageReader;
17import org.projectfloodlight.openflow.exceptions.OFParseError;
Yotam Harcholf3f11152013-09-05 16:47:16 -070018
19/**
Yotam Harchola289d552013-09-16 10:10:40 -070020 * Wrapper around an IPv4Address address
Yotam Harcholf3f11152013-09-05 16:47:16 -070021 *
kjwon157bc85402015-02-12 15:07:42 +090022 * @author Andreas Wundsam {@literal <}andreas.wundsam@bigswitch.com{@literal >}
Yotam Harcholf3f11152013-09-05 16:47:16 -070023 */
Byungjoon Leeba92e292014-07-18 13:13:26 +090024public class IPv4Address extends IPAddress<IPv4Address> implements Writeable {
Yotam Harcholf3f11152013-09-05 16:47:16 -070025 static final int LENGTH = 4;
26 private final int rawValue;
Yotam Harcholf3f11152013-09-05 16:47:16 -070027
Gregor Maier1acb4502013-12-12 11:25:07 -080028 private static final int NOT_A_CIDR_MASK = -1;
29 private static final int CIDR_MASK_CACHE_UNSET = -2;
Gregor Maier5615b6c2013-12-11 22:29:07 -080030 // Must appear before the static IPv4Address constant assignments
31 private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
32
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070033 private final static int NONE_VAL = 0x0;
34 public final static IPv4Address NONE = new IPv4Address(NONE_VAL);
35
Yotam Harchola289d552013-09-16 10:10:40 -070036 public static final IPv4Address NO_MASK = IPv4Address.of(0xFFFFFFFF);
37 public static final IPv4Address FULL_MASK = IPv4Address.of(0x00000000);
38
39 private IPv4Address(final int rawValue) {
Yotam Harcholf3f11152013-09-05 16:47:16 -070040 this.rawValue = rawValue;
41 }
42
Byungjoon Leeba92e292014-07-18 13:13:26 +090043 public final static Reader READER = new Reader();
44
45 private static class Reader implements OFMessageReader<IPv4Address> {
46 @Override
47 public IPv4Address readFrom(ChannelBuffer bb) throws OFParseError {
48 return new IPv4Address(bb.readInt());
49 }
50 }
51
Yotam Harchol4d634682013-09-26 13:21:06 -070052 @Override
Yotam Harcholeb023dc2013-09-26 15:45:44 -070053 public IPVersion getIpVersion() {
54 return IPVersion.IPv4;
Yotam Harchol4d634682013-09-26 13:21:06 -070055 }
56
Gregor Maier5615b6c2013-12-11 22:29:07 -080057 private int asCidrMaskLengthInternal() {
58 if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
59 // No lock required. We only write cidrMaskLengthCache once
60 int maskint = getInt();
61 if (maskint == 0) {
62 cidrMaskLengthCache = 0;
63 } else if (Integer.bitCount((~maskint) + 1) == 1) {
64 // IP represents a true CIDR prefix length
65 cidrMaskLengthCache = Integer.bitCount(maskint);
66 } else {
67 cidrMaskLengthCache = NOT_A_CIDR_MASK;
68 }
69 }
70 return cidrMaskLengthCache;
71 }
72
73 @Override
74 public boolean isCidrMask() {
75 return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
76 }
Gregor Maier7f987e62013-12-10 19:34:18 -080077
78 @Override
79 public int asCidrMaskLength() {
Gregor Maier5615b6c2013-12-11 22:29:07 -080080 if (!isCidrMask()) {
81 throw new IllegalStateException("IP is not a valid CIDR prefix " +
82 "mask " + toString());
Gregor Maier7f987e62013-12-10 19:34:18 -080083 } else {
Gregor Maier5615b6c2013-12-11 22:29:07 -080084 return asCidrMaskLengthInternal();
Gregor Maier7f987e62013-12-10 19:34:18 -080085 }
86 }
87
Aditya Vaja56b8b182014-03-11 13:13:58 -070088 @Override
89 public boolean isBroadcast() {
90 return this.equals(NO_MASK);
91 }
92
nsongd7701e12015-05-13 10:34:26 -070093 /**
94 * IPv4 multicast addresses are defined by the leading address bits of 1110
95 */
96 @Override
97 public boolean isMulticast() {
nsong729900b2015-05-13 10:44:48 -070098 return ((rawValue >>> 24) & 0xF0) == 0xE0;
nsongd7701e12015-05-13 10:34:26 -070099 }
100
Aditya Vaja56b8b182014-03-11 13:13:58 -0700101 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -0700102 public IPv4Address and(IPv4Address other) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700103 Preconditions.checkNotNull(other, "other must not be null");
104
105 IPv4Address otherIp = other;
Aditya Vaja56b8b182014-03-11 13:13:58 -0700106 return IPv4Address.of(rawValue & otherIp.rawValue);
107 }
108
109 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -0700110 public IPv4Address or(IPv4Address other) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700111 Preconditions.checkNotNull(other, "other must not be null");
112
113 IPv4Address otherIp = other;
Aditya Vaja56b8b182014-03-11 13:13:58 -0700114 return IPv4Address.of(rawValue | otherIp.rawValue);
115 }
116
117 @Override
118 public IPv4Address not() {
119 return IPv4Address.of(~rawValue);
120 }
121
Ronald Liaf8d3e72014-07-05 01:26:28 -0700122 /**
123 * Returns an {@code IPv4Address} object that represents the given
Ronald Li097cda52014-07-06 23:17:05 -0700124 * IP address. The argument is in network byte order: the highest
Ronald Liaf8d3e72014-07-05 01:26:28 -0700125 * order byte of the address is in {@code address[0]}.
126 * <p>
127 * The address byte array must be 4 bytes long (32 bits long).
128 * <p>
129 * Similar to {@link InetAddress#getByAddress(byte[])}.
130 *
131 * @param address the raw IP address in network byte order
132 * @return an {@code IPv4Address} object that represents the given
133 * raw IP address
134 * @throws NullPointerException if the given address was {@code null}
135 * @throws IllegalArgumentException if the given address was of an invalid
136 * byte array length
137 * @see InetAddress#getByAddress(byte[])
138 */
Ronald Liffa80792014-07-04 17:50:49 -0700139 @Nonnull
140 public static IPv4Address of(@Nonnull final byte[] address) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700141 Preconditions.checkNotNull(address, "address must not be null");
142
Yotam Harcholf3f11152013-09-05 16:47:16 -0700143 if (address.length != LENGTH) {
144 throw new IllegalArgumentException(
Ronald Li74b54bc2014-07-06 23:59:13 -0700145 "Invalid byte array length for IPv4 address: " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700146 }
147
148 int raw =
149 (address[0] & 0xFF) << 24 | (address[1] & 0xFF) << 16
150 | (address[2] & 0xFF) << 8 | (address[3] & 0xFF) << 0;
Yotam Harchola289d552013-09-16 10:10:40 -0700151 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700152 }
153
Ronald Liaf8d3e72014-07-05 01:26:28 -0700154 /**
155 * Returns an {@code IPv4Address} object that represents the given
Ronald Li097cda52014-07-06 23:17:05 -0700156 * IP address.
Andreas Wundsam3700d162014-03-11 04:43:38 -0700157 *
Ronald Liaf8d3e72014-07-05 01:26:28 -0700158 * @param raw the raw IP address represented as a 32-bit integer
159 * @return an {@code IPv4Address} object that represents the given
160 * raw IP address
Andreas Wundsam3700d162014-03-11 04:43:38 -0700161 */
Ronald Liffa80792014-07-04 17:50:49 -0700162 @Nonnull
Yotam Harchola289d552013-09-16 10:10:40 -0700163 public static IPv4Address of(final int raw) {
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -0700164 if(raw == NONE_VAL)
165 return NONE;
Yotam Harchola289d552013-09-16 10:10:40 -0700166 return new IPv4Address(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700167 }
168
Ronald Liaf8d3e72014-07-05 01:26:28 -0700169 /**
170 * Returns an {@code IPv4Address} object that represents the given
Ronald Li5b41da92014-07-06 22:59:28 -0700171 * IP address. The argument is in the canonical quad-dotted notation.
172 * For example, {@code 1.2.3.4}.
Andreas Wundsam3700d162014-03-11 04:43:38 -0700173 *
Ronald Li5b41da92014-07-06 22:59:28 -0700174 * @param string the IP address in the canonical quad-dotted notation
Ronald Liaf8d3e72014-07-05 01:26:28 -0700175 * @return an {@code IPv4Address} object that represents the given
Ronald Li5b41da92014-07-06 22:59:28 -0700176 * IP address
Ronald Li097cda52014-07-06 23:17:05 -0700177 * @throws NullPointerException if the given string was {@code null}
178 * @throws IllegalArgumentException if the given string was not a valid
Ronald Liaf8d3e72014-07-05 01:26:28 -0700179 * IPv4 address
Andreas Wundsam3700d162014-03-11 04:43:38 -0700180 */
181 @Nonnull
182 public static IPv4Address of(@Nonnull final String string) throws IllegalArgumentException {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700183 Preconditions.checkNotNull(string, "string must not be null");
184
Yotam Harcholf3f11152013-09-05 16:47:16 -0700185 int start = 0;
186 int shift = 24;
187
188 int raw = 0;
189 while (shift >= 0) {
190 int end = string.indexOf('.', start);
191 if (end == start || !((shift > 0) ^ (end < 0)))
192 throw new IllegalArgumentException("IP Address not well formed: " + string);
193
194 String substr =
195 end > 0 ? string.substring(start, end) : string.substring(start);
196 int val = Integer.parseInt(substr);
197 if (val < 0 || val > 255)
198 throw new IllegalArgumentException("IP Address not well formed: " + string);
199
200 raw |= val << shift;
201
202 shift -= 8;
203 start = end + 1;
204 }
Yotam Harchola289d552013-09-16 10:10:40 -0700205 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700206 }
207
Ronald Liaf8d3e72014-07-05 01:26:28 -0700208 /**
Ronald Li5b41da92014-07-06 22:59:28 -0700209 * Returns an {@code IPv4Address} object that represents the given
210 * IP address. The argument is given as an {@code Inet4Address} object.
Ronald Liaf8d3e72014-07-05 01:26:28 -0700211 *
Ronald Li382589f2014-07-06 23:58:08 -0700212 * @param address the IP address as an {@code Inet4Address} object
Ronald Liaf8d3e72014-07-05 01:26:28 -0700213 * @return an {@code IPv4Address} object that represents the
214 * given IP address
Ronald Li5b41da92014-07-06 22:59:28 -0700215 * @throws NullPointerException if the given {@code Inet4Address} was
216 * {@code null}
Ronald Liaf8d3e72014-07-05 01:26:28 -0700217 */
Ronald Liffa80792014-07-04 17:50:49 -0700218 @Nonnull
219 public static IPv4Address of(@Nonnull final Inet4Address address) {
220 Preconditions.checkNotNull(address, "address must not be null");
221 return IPv4Address.of(address.getAddress());
222 }
223
Ronald Liaf8d3e72014-07-05 01:26:28 -0700224 /**
225 * Returns an {@code IPv4Address} object that represents the
Ronald Lic3c4a952014-07-07 01:01:46 -0700226 * CIDR subnet mask of the given prefix length.
Ronald Liaf8d3e72014-07-05 01:26:28 -0700227 *
Ronald Lic3c4a952014-07-07 01:01:46 -0700228 * @param cidrMaskLength the prefix length of the CIDR subnet mask
229 * (i.e. the number of leading one-bits),
Ronald Liaf8d3e72014-07-05 01:26:28 -0700230 * where {@code 0 <= cidrMaskLength <= 32}
231 * @return an {@code IPv4Address} object that represents the
232 * CIDR subnet mask of the given prefix length
233 * @throws IllegalArgumentException if the given prefix length was invalid
234 */
Ronald Liffa80792014-07-04 17:50:49 -0700235 @Nonnull
Ronald Lia7484222014-07-03 17:14:12 -0700236 public static IPv4Address ofCidrMaskLength(final int cidrMaskLength) {
237 Preconditions.checkArgument(
238 cidrMaskLength >= 0 && cidrMaskLength <= 32,
239 "Invalid IPv4 CIDR mask length: %s", cidrMaskLength);
240
241 if (cidrMaskLength == 32) {
242 return IPv4Address.NO_MASK;
243 } else if (cidrMaskLength == 0) {
244 return IPv4Address.FULL_MASK;
245 } else {
246 int mask = (-1) << (32 - cidrMaskLength);
247 return IPv4Address.of(mask);
248 }
249 }
250
Ronald Liaf8d3e72014-07-05 01:26:28 -0700251 /**
252 * Returns an {@code IPv4AddressWithMask} object that represents this
Ronald Lica08d5f2014-07-05 02:43:18 -0700253 * IP address masked by the given IP address mask.
254 *
255 * @param mask the {@code IPv4Address} object that represents the mask
256 * @return an {@code IPv4AddressWithMask} object that represents this
257 * IP address masked by the given mask
258 * @throws NullPointerException if the given mask was {@code null}
259 */
260 @Nonnull
Ronald Libbf01942014-07-07 17:00:13 -0700261 @Override
Ronald Lica08d5f2014-07-05 02:43:18 -0700262 public IPv4AddressWithMask withMask(@Nonnull final IPv4Address mask) {
263 return IPv4AddressWithMask.of(this, mask);
264 }
265
266 /**
267 * Returns an {@code IPv4AddressWithMask} object that represents this
Ronald Li383d14e2014-07-07 01:09:18 -0700268 * IP address masked by the CIDR subnet mask of the given prefix length.
Ronald Liaf8d3e72014-07-05 01:26:28 -0700269 *
Ronald Li383d14e2014-07-07 01:09:18 -0700270 * @param cidrMaskLength the prefix length of the CIDR subnet mask
271 * (i.e. the number of leading one-bits),
Ronald Liaf8d3e72014-07-05 01:26:28 -0700272 * where {@code 0 <= cidrMaskLength <= 32}
273 * @return an {@code IPv4AddressWithMask} object that
274 * represents this IP address masked by the CIDR
275 * subnet mask of the given prefix length
276 * @throws IllegalArgumentException if the given prefix length was invalid
277 * @see #ofCidrMaskLength(int)
278 */
279 @Nonnull
Ronald Libbf01942014-07-07 17:00:13 -0700280 @Override
Ronald Liaf8d3e72014-07-05 01:26:28 -0700281 public IPv4AddressWithMask withMaskOfLength(final int cidrMaskLength) {
Ronald Libbf01942014-07-07 17:00:13 -0700282 return this.withMask(IPv4Address.ofCidrMaskLength(cidrMaskLength));
Ronald Liffa80792014-07-04 17:50:49 -0700283 }
284
Yotam Harcholf3f11152013-09-05 16:47:16 -0700285 public int getInt() {
286 return rawValue;
287 }
288
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800289 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700290
Ronald Liaf8d3e72014-07-05 01:26:28 -0700291 @Override
Yotam Harcholf3f11152013-09-05 16:47:16 -0700292 public byte[] getBytes() {
293 if (bytesCache == null) {
294 synchronized (this) {
295 if (bytesCache == null) {
296 bytesCache =
297 new byte[] { (byte) ((rawValue >>> 24) & 0xFF),
298 (byte) ((rawValue >>> 16) & 0xFF),
299 (byte) ((rawValue >>> 8) & 0xFF),
300 (byte) ((rawValue >>> 0) & 0xFF) };
301 }
302 }
303 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800304 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700305 }
306
307 @Override
308 public int getLength() {
309 return LENGTH;
310 }
311
312 @Override
313 public String toString() {
314 StringBuilder res = new StringBuilder();
315 res.append((rawValue >> 24) & 0xFF).append('.');
316 res.append((rawValue >> 16) & 0xFF).append('.');
317 res.append((rawValue >> 8) & 0xFF).append('.');
318 res.append((rawValue >> 0) & 0xFF);
319 return res.toString();
320 }
321
Yotam Harcholf3f11152013-09-05 16:47:16 -0700322 public void write4Bytes(ChannelBuffer c) {
323 c.writeInt(rawValue);
324 }
Yotam Harchola289d552013-09-16 10:10:40 -0700325
326 public static IPv4Address read4Bytes(ChannelBuffer c) {
327 return IPv4Address.of(c.readInt());
Yotam Harcholf3f11152013-09-05 16:47:16 -0700328 }
329
330 @Override
Yotam Harchola289d552013-09-16 10:10:40 -0700331 public IPv4Address applyMask(IPv4Address mask) {
Aditya Vaja98c96e72014-03-11 15:19:01 -0700332 return and(mask);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700333 }
334
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700335 @Override
336 public int hashCode() {
337 final int prime = 31;
338 int result = 1;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700339 result = prime * result + rawValue;
340 return result;
341 }
Yotam Harchola289d552013-09-16 10:10:40 -0700342
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700343 @Override
344 public boolean equals(Object obj) {
345 if (this == obj)
346 return true;
347 if (obj == null)
348 return false;
349 if (getClass() != obj.getClass())
350 return false;
351 IPv4Address other = (IPv4Address) obj;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700352 if (rawValue != other.rawValue)
353 return false;
354 return true;
355 }
356
357 @Override
358 public int compareTo(IPv4Address o) {
359 return UnsignedInts.compare(rawValue, o.rawValue);
360 }
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700361
362 @Override
363 public void putTo(PrimitiveSink sink) {
364 sink.putInt(rawValue);
365 }
366
Byungjoon Leeba92e292014-07-18 13:13:26 +0900367 @Override
368 public void writeTo(ChannelBuffer bb) {
369 bb.writeInt(rawValue);
370 }
Yotam Harcholf3f11152013-09-05 16:47:16 -0700371}