blob: 153062943a92421278a0b7e2d6d3e8f54e40046a [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
93 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -070094 public IPv4Address and(IPv4Address other) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -070095 Preconditions.checkNotNull(other, "other must not be null");
96
97 IPv4Address otherIp = other;
Aditya Vaja56b8b182014-03-11 13:13:58 -070098 return IPv4Address.of(rawValue & otherIp.rawValue);
99 }
100
101 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -0700102 public IPv4Address or(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
110 public IPv4Address not() {
111 return IPv4Address.of(~rawValue);
112 }
113
Ronald Liaf8d3e72014-07-05 01:26:28 -0700114 /**
115 * Returns an {@code IPv4Address} object that represents the given
Ronald Li097cda52014-07-06 23:17:05 -0700116 * IP address. The argument is in network byte order: the highest
Ronald Liaf8d3e72014-07-05 01:26:28 -0700117 * order byte of the address is in {@code address[0]}.
118 * <p>
119 * The address byte array must be 4 bytes long (32 bits long).
120 * <p>
121 * Similar to {@link InetAddress#getByAddress(byte[])}.
122 *
123 * @param address the raw IP address in network byte order
124 * @return an {@code IPv4Address} object that represents the given
125 * raw IP address
126 * @throws NullPointerException if the given address was {@code null}
127 * @throws IllegalArgumentException if the given address was of an invalid
128 * byte array length
129 * @see InetAddress#getByAddress(byte[])
130 */
Ronald Liffa80792014-07-04 17:50:49 -0700131 @Nonnull
132 public static IPv4Address of(@Nonnull final byte[] address) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700133 Preconditions.checkNotNull(address, "address must not be null");
134
Yotam Harcholf3f11152013-09-05 16:47:16 -0700135 if (address.length != LENGTH) {
136 throw new IllegalArgumentException(
Ronald Li74b54bc2014-07-06 23:59:13 -0700137 "Invalid byte array length for IPv4 address: " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700138 }
139
140 int raw =
141 (address[0] & 0xFF) << 24 | (address[1] & 0xFF) << 16
142 | (address[2] & 0xFF) << 8 | (address[3] & 0xFF) << 0;
Yotam Harchola289d552013-09-16 10:10:40 -0700143 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700144 }
145
Ronald Liaf8d3e72014-07-05 01:26:28 -0700146 /**
147 * Returns an {@code IPv4Address} object that represents the given
Ronald Li097cda52014-07-06 23:17:05 -0700148 * IP address.
Andreas Wundsam3700d162014-03-11 04:43:38 -0700149 *
Ronald Liaf8d3e72014-07-05 01:26:28 -0700150 * @param raw the raw IP address represented as a 32-bit integer
151 * @return an {@code IPv4Address} object that represents the given
152 * raw IP address
Andreas Wundsam3700d162014-03-11 04:43:38 -0700153 */
Ronald Liffa80792014-07-04 17:50:49 -0700154 @Nonnull
Yotam Harchola289d552013-09-16 10:10:40 -0700155 public static IPv4Address of(final int raw) {
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -0700156 if(raw == NONE_VAL)
157 return NONE;
Yotam Harchola289d552013-09-16 10:10:40 -0700158 return new IPv4Address(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700159 }
160
Ronald Liaf8d3e72014-07-05 01:26:28 -0700161 /**
162 * Returns an {@code IPv4Address} object that represents the given
Ronald Li5b41da92014-07-06 22:59:28 -0700163 * IP address. The argument is in the canonical quad-dotted notation.
164 * For example, {@code 1.2.3.4}.
Andreas Wundsam3700d162014-03-11 04:43:38 -0700165 *
Ronald Li5b41da92014-07-06 22:59:28 -0700166 * @param string the IP address in the canonical quad-dotted notation
Ronald Liaf8d3e72014-07-05 01:26:28 -0700167 * @return an {@code IPv4Address} object that represents the given
Ronald Li5b41da92014-07-06 22:59:28 -0700168 * IP address
Ronald Li097cda52014-07-06 23:17:05 -0700169 * @throws NullPointerException if the given string was {@code null}
170 * @throws IllegalArgumentException if the given string was not a valid
Ronald Liaf8d3e72014-07-05 01:26:28 -0700171 * IPv4 address
Andreas Wundsam3700d162014-03-11 04:43:38 -0700172 */
173 @Nonnull
174 public static IPv4Address of(@Nonnull final String string) throws IllegalArgumentException {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700175 Preconditions.checkNotNull(string, "string must not be null");
176
Yotam Harcholf3f11152013-09-05 16:47:16 -0700177 int start = 0;
178 int shift = 24;
179
180 int raw = 0;
181 while (shift >= 0) {
182 int end = string.indexOf('.', start);
183 if (end == start || !((shift > 0) ^ (end < 0)))
184 throw new IllegalArgumentException("IP Address not well formed: " + string);
185
186 String substr =
187 end > 0 ? string.substring(start, end) : string.substring(start);
188 int val = Integer.parseInt(substr);
189 if (val < 0 || val > 255)
190 throw new IllegalArgumentException("IP Address not well formed: " + string);
191
192 raw |= val << shift;
193
194 shift -= 8;
195 start = end + 1;
196 }
Yotam Harchola289d552013-09-16 10:10:40 -0700197 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700198 }
199
Ronald Liaf8d3e72014-07-05 01:26:28 -0700200 /**
Ronald Li5b41da92014-07-06 22:59:28 -0700201 * Returns an {@code IPv4Address} object that represents the given
202 * IP address. The argument is given as an {@code Inet4Address} object.
Ronald Liaf8d3e72014-07-05 01:26:28 -0700203 *
Ronald Li382589f2014-07-06 23:58:08 -0700204 * @param address the IP address as an {@code Inet4Address} object
Ronald Liaf8d3e72014-07-05 01:26:28 -0700205 * @return an {@code IPv4Address} object that represents the
206 * given IP address
Ronald Li5b41da92014-07-06 22:59:28 -0700207 * @throws NullPointerException if the given {@code Inet4Address} was
208 * {@code null}
Ronald Liaf8d3e72014-07-05 01:26:28 -0700209 */
Ronald Liffa80792014-07-04 17:50:49 -0700210 @Nonnull
211 public static IPv4Address of(@Nonnull final Inet4Address address) {
212 Preconditions.checkNotNull(address, "address must not be null");
213 return IPv4Address.of(address.getAddress());
214 }
215
Ronald Liaf8d3e72014-07-05 01:26:28 -0700216 /**
217 * Returns an {@code IPv4Address} object that represents the
Ronald Lic3c4a952014-07-07 01:01:46 -0700218 * CIDR subnet mask of the given prefix length.
Ronald Liaf8d3e72014-07-05 01:26:28 -0700219 *
Ronald Lic3c4a952014-07-07 01:01:46 -0700220 * @param cidrMaskLength the prefix length of the CIDR subnet mask
221 * (i.e. the number of leading one-bits),
Ronald Liaf8d3e72014-07-05 01:26:28 -0700222 * where {@code 0 <= cidrMaskLength <= 32}
223 * @return an {@code IPv4Address} object that represents the
224 * CIDR subnet mask of the given prefix length
225 * @throws IllegalArgumentException if the given prefix length was invalid
226 */
Ronald Liffa80792014-07-04 17:50:49 -0700227 @Nonnull
Ronald Lia7484222014-07-03 17:14:12 -0700228 public static IPv4Address ofCidrMaskLength(final int cidrMaskLength) {
229 Preconditions.checkArgument(
230 cidrMaskLength >= 0 && cidrMaskLength <= 32,
231 "Invalid IPv4 CIDR mask length: %s", cidrMaskLength);
232
233 if (cidrMaskLength == 32) {
234 return IPv4Address.NO_MASK;
235 } else if (cidrMaskLength == 0) {
236 return IPv4Address.FULL_MASK;
237 } else {
238 int mask = (-1) << (32 - cidrMaskLength);
239 return IPv4Address.of(mask);
240 }
241 }
242
Ronald Liaf8d3e72014-07-05 01:26:28 -0700243 /**
244 * Returns an {@code IPv4AddressWithMask} object that represents this
Ronald Lica08d5f2014-07-05 02:43:18 -0700245 * IP address masked by the given IP address mask.
246 *
247 * @param mask the {@code IPv4Address} object that represents the mask
248 * @return an {@code IPv4AddressWithMask} object that represents this
249 * IP address masked by the given mask
250 * @throws NullPointerException if the given mask was {@code null}
251 */
252 @Nonnull
Ronald Libbf01942014-07-07 17:00:13 -0700253 @Override
Ronald Lica08d5f2014-07-05 02:43:18 -0700254 public IPv4AddressWithMask withMask(@Nonnull final IPv4Address mask) {
255 return IPv4AddressWithMask.of(this, mask);
256 }
257
258 /**
259 * Returns an {@code IPv4AddressWithMask} object that represents this
Ronald Li383d14e2014-07-07 01:09:18 -0700260 * IP address masked by the CIDR subnet mask of the given prefix length.
Ronald Liaf8d3e72014-07-05 01:26:28 -0700261 *
Ronald Li383d14e2014-07-07 01:09:18 -0700262 * @param cidrMaskLength the prefix length of the CIDR subnet mask
263 * (i.e. the number of leading one-bits),
Ronald Liaf8d3e72014-07-05 01:26:28 -0700264 * where {@code 0 <= cidrMaskLength <= 32}
265 * @return an {@code IPv4AddressWithMask} object that
266 * represents this IP address masked by the CIDR
267 * subnet mask of the given prefix length
268 * @throws IllegalArgumentException if the given prefix length was invalid
269 * @see #ofCidrMaskLength(int)
270 */
271 @Nonnull
Ronald Libbf01942014-07-07 17:00:13 -0700272 @Override
Ronald Liaf8d3e72014-07-05 01:26:28 -0700273 public IPv4AddressWithMask withMaskOfLength(final int cidrMaskLength) {
Ronald Libbf01942014-07-07 17:00:13 -0700274 return this.withMask(IPv4Address.ofCidrMaskLength(cidrMaskLength));
Ronald Liffa80792014-07-04 17:50:49 -0700275 }
276
Yotam Harcholf3f11152013-09-05 16:47:16 -0700277 public int getInt() {
278 return rawValue;
279 }
280
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800281 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700282
Ronald Liaf8d3e72014-07-05 01:26:28 -0700283 @Override
Yotam Harcholf3f11152013-09-05 16:47:16 -0700284 public byte[] getBytes() {
285 if (bytesCache == null) {
286 synchronized (this) {
287 if (bytesCache == null) {
288 bytesCache =
289 new byte[] { (byte) ((rawValue >>> 24) & 0xFF),
290 (byte) ((rawValue >>> 16) & 0xFF),
291 (byte) ((rawValue >>> 8) & 0xFF),
292 (byte) ((rawValue >>> 0) & 0xFF) };
293 }
294 }
295 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800296 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700297 }
298
299 @Override
300 public int getLength() {
301 return LENGTH;
302 }
303
304 @Override
305 public String toString() {
306 StringBuilder res = new StringBuilder();
307 res.append((rawValue >> 24) & 0xFF).append('.');
308 res.append((rawValue >> 16) & 0xFF).append('.');
309 res.append((rawValue >> 8) & 0xFF).append('.');
310 res.append((rawValue >> 0) & 0xFF);
311 return res.toString();
312 }
313
Yotam Harcholf3f11152013-09-05 16:47:16 -0700314 public void write4Bytes(ChannelBuffer c) {
315 c.writeInt(rawValue);
316 }
Yotam Harchola289d552013-09-16 10:10:40 -0700317
318 public static IPv4Address read4Bytes(ChannelBuffer c) {
319 return IPv4Address.of(c.readInt());
Yotam Harcholf3f11152013-09-05 16:47:16 -0700320 }
321
322 @Override
Yotam Harchola289d552013-09-16 10:10:40 -0700323 public IPv4Address applyMask(IPv4Address mask) {
Aditya Vaja98c96e72014-03-11 15:19:01 -0700324 return and(mask);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700325 }
326
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700327 @Override
328 public int hashCode() {
329 final int prime = 31;
330 int result = 1;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700331 result = prime * result + rawValue;
332 return result;
333 }
Yotam Harchola289d552013-09-16 10:10:40 -0700334
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700335 @Override
336 public boolean equals(Object obj) {
337 if (this == obj)
338 return true;
339 if (obj == null)
340 return false;
341 if (getClass() != obj.getClass())
342 return false;
343 IPv4Address other = (IPv4Address) obj;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700344 if (rawValue != other.rawValue)
345 return false;
346 return true;
347 }
348
349 @Override
350 public int compareTo(IPv4Address o) {
351 return UnsignedInts.compare(rawValue, o.rawValue);
352 }
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700353
354 @Override
355 public void putTo(PrimitiveSink sink) {
356 sink.putInt(rawValue);
357 }
358
Byungjoon Leeba92e292014-07-18 13:13:26 +0900359 @Override
360 public void writeTo(ChannelBuffer bb) {
361 bb.writeInt(rawValue);
362 }
Yotam Harcholf3f11152013-09-05 16:47:16 -0700363}