blob: 8f3cce34f9f3517e8200acc2c5c02b35df4ab657 [file] [log] [blame]
Yotam Harcholf3f11152013-09-05 16:47:16 -07001package org.projectfloodlight.openflow.types;
2
Andreas Wundsam5f71b412014-02-18 12:56:35 -08003import java.util.Arrays;
4
Andreas Wundsam3700d162014-03-11 04:43:38 -07005import javax.annotation.Nonnull;
6
Yotam Harcholf3f11152013-09-05 16:47:16 -07007import org.jboss.netty.buffer.ChannelBuffer;
8
Sovietaced9dfc1ef2014-06-27 11:13:57 -07009import com.google.common.base.Preconditions;
Andreas Wundsam22ba3af2013-10-04 16:00:30 -070010import com.google.common.hash.PrimitiveSink;
Andreas Wundsam85c961f2013-09-29 21:22:12 -070011import com.google.common.primitives.UnsignedInts;
12
Yotam Harcholf3f11152013-09-05 16:47:16 -070013
14
15/**
Yotam Harchola289d552013-09-16 10:10:40 -070016 * Wrapper around an IPv4Address address
Yotam Harcholf3f11152013-09-05 16:47:16 -070017 *
18 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
19 */
Yotam Harchol4d634682013-09-26 13:21:06 -070020public class IPv4Address extends IPAddress<IPv4Address> {
Yotam Harcholf3f11152013-09-05 16:47:16 -070021 static final int LENGTH = 4;
22 private final int rawValue;
Yotam Harcholf3f11152013-09-05 16:47:16 -070023
Gregor Maier1acb4502013-12-12 11:25:07 -080024 private static final int NOT_A_CIDR_MASK = -1;
25 private static final int CIDR_MASK_CACHE_UNSET = -2;
Gregor Maier5615b6c2013-12-11 22:29:07 -080026 // Must appear before the static IPv4Address constant assignments
27 private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
28
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070029 private final static int NONE_VAL = 0x0;
30 public final static IPv4Address NONE = new IPv4Address(NONE_VAL);
31
Yotam Harchola289d552013-09-16 10:10:40 -070032 public static final IPv4Address NO_MASK = IPv4Address.of(0xFFFFFFFF);
33 public static final IPv4Address FULL_MASK = IPv4Address.of(0x00000000);
34
35 private IPv4Address(final int rawValue) {
Yotam Harcholf3f11152013-09-05 16:47:16 -070036 this.rawValue = rawValue;
37 }
38
Yotam Harchol4d634682013-09-26 13:21:06 -070039 @Override
Yotam Harcholeb023dc2013-09-26 15:45:44 -070040 public IPVersion getIpVersion() {
41 return IPVersion.IPv4;
Yotam Harchol4d634682013-09-26 13:21:06 -070042 }
43
Gregor Maier5615b6c2013-12-11 22:29:07 -080044 private int asCidrMaskLengthInternal() {
45 if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
46 // No lock required. We only write cidrMaskLengthCache once
47 int maskint = getInt();
48 if (maskint == 0) {
49 cidrMaskLengthCache = 0;
50 } else if (Integer.bitCount((~maskint) + 1) == 1) {
51 // IP represents a true CIDR prefix length
52 cidrMaskLengthCache = Integer.bitCount(maskint);
53 } else {
54 cidrMaskLengthCache = NOT_A_CIDR_MASK;
55 }
56 }
57 return cidrMaskLengthCache;
58 }
59
60 @Override
61 public boolean isCidrMask() {
62 return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
63 }
Gregor Maier7f987e62013-12-10 19:34:18 -080064
65 @Override
66 public int asCidrMaskLength() {
Gregor Maier5615b6c2013-12-11 22:29:07 -080067 if (!isCidrMask()) {
68 throw new IllegalStateException("IP is not a valid CIDR prefix " +
69 "mask " + toString());
Gregor Maier7f987e62013-12-10 19:34:18 -080070 } else {
Gregor Maier5615b6c2013-12-11 22:29:07 -080071 return asCidrMaskLengthInternal();
Gregor Maier7f987e62013-12-10 19:34:18 -080072 }
73 }
74
Aditya Vaja56b8b182014-03-11 13:13:58 -070075 @Override
76 public boolean isBroadcast() {
77 return this.equals(NO_MASK);
78 }
79
80 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -070081 public IPv4Address and(IPv4Address other) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -070082 Preconditions.checkNotNull(other, "other must not be null");
83
84 IPv4Address otherIp = other;
Aditya Vaja56b8b182014-03-11 13:13:58 -070085 return IPv4Address.of(rawValue & otherIp.rawValue);
86 }
87
88 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -070089 public IPv4Address or(IPv4Address other) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -070090 Preconditions.checkNotNull(other, "other must not be null");
91
92 IPv4Address otherIp = other;
Aditya Vaja56b8b182014-03-11 13:13:58 -070093 return IPv4Address.of(rawValue | otherIp.rawValue);
94 }
95
96 @Override
97 public IPv4Address not() {
98 return IPv4Address.of(~rawValue);
99 }
100
Yotam Harchola289d552013-09-16 10:10:40 -0700101 public static IPv4Address of(final byte[] address) {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700102 Preconditions.checkNotNull(address, "address must not be null");
103
Yotam Harcholf3f11152013-09-05 16:47:16 -0700104 if (address.length != LENGTH) {
105 throw new IllegalArgumentException(
Andreas Wundsamc85b5c52013-09-24 13:01:43 -0700106 "Invalid byte array length for IPv4Address address: " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700107 }
108
109 int raw =
110 (address[0] & 0xFF) << 24 | (address[1] & 0xFF) << 16
111 | (address[2] & 0xFF) << 8 | (address[3] & 0xFF) << 0;
Yotam Harchola289d552013-09-16 10:10:40 -0700112 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700113 }
114
Andreas Wundsam3700d162014-03-11 04:43:38 -0700115 /** construct an IPv4Address from a 32-bit integer value.
116 *
117 * @param raw the IPAdress represented as a 32-bit integer
118 * @return the constructed IPv4Address
119 */
Yotam Harchola289d552013-09-16 10:10:40 -0700120 public static IPv4Address of(final int raw) {
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -0700121 if(raw == NONE_VAL)
122 return NONE;
Yotam Harchola289d552013-09-16 10:10:40 -0700123 return new IPv4Address(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700124 }
125
Andreas Wundsam3700d162014-03-11 04:43:38 -0700126 /** parse an IPv4Address from the canonical dotted-quad representation
127 * (1.2.3.4).
128 *
129 * @param string an IPv4 address in dotted-quad representation
130 * @return the parsed IPv4 address
131 * @throws NullPointerException if string is null
132 * @throws IllegalArgumentException if string is not a valid IPv4Address
133 */
134 @Nonnull
135 public static IPv4Address of(@Nonnull final String string) throws IllegalArgumentException {
Sovietaced9dfc1ef2014-06-27 11:13:57 -0700136 Preconditions.checkNotNull(string, "string must not be null");
137
Yotam Harcholf3f11152013-09-05 16:47:16 -0700138 int start = 0;
139 int shift = 24;
140
141 int raw = 0;
142 while (shift >= 0) {
143 int end = string.indexOf('.', start);
144 if (end == start || !((shift > 0) ^ (end < 0)))
145 throw new IllegalArgumentException("IP Address not well formed: " + string);
146
147 String substr =
148 end > 0 ? string.substring(start, end) : string.substring(start);
149 int val = Integer.parseInt(substr);
150 if (val < 0 || val > 255)
151 throw new IllegalArgumentException("IP Address not well formed: " + string);
152
153 raw |= val << shift;
154
155 shift -= 8;
156 start = end + 1;
157 }
Yotam Harchola289d552013-09-16 10:10:40 -0700158 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700159 }
160
Ronald Lia7484222014-07-03 17:14:12 -0700161 public static IPv4Address ofCidrMaskLength(final int cidrMaskLength) {
162 Preconditions.checkArgument(
163 cidrMaskLength >= 0 && cidrMaskLength <= 32,
164 "Invalid IPv4 CIDR mask length: %s", cidrMaskLength);
165
166 if (cidrMaskLength == 32) {
167 return IPv4Address.NO_MASK;
168 } else if (cidrMaskLength == 0) {
169 return IPv4Address.FULL_MASK;
170 } else {
171 int mask = (-1) << (32 - cidrMaskLength);
172 return IPv4Address.of(mask);
173 }
174 }
175
Yotam Harcholf3f11152013-09-05 16:47:16 -0700176 public int getInt() {
177 return rawValue;
178 }
179
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800180 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700181
182 public byte[] getBytes() {
183 if (bytesCache == null) {
184 synchronized (this) {
185 if (bytesCache == null) {
186 bytesCache =
187 new byte[] { (byte) ((rawValue >>> 24) & 0xFF),
188 (byte) ((rawValue >>> 16) & 0xFF),
189 (byte) ((rawValue >>> 8) & 0xFF),
190 (byte) ((rawValue >>> 0) & 0xFF) };
191 }
192 }
193 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800194 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700195 }
196
197 @Override
198 public int getLength() {
199 return LENGTH;
200 }
201
202 @Override
203 public String toString() {
204 StringBuilder res = new StringBuilder();
205 res.append((rawValue >> 24) & 0xFF).append('.');
206 res.append((rawValue >> 16) & 0xFF).append('.');
207 res.append((rawValue >> 8) & 0xFF).append('.');
208 res.append((rawValue >> 0) & 0xFF);
209 return res.toString();
210 }
211
Yotam Harcholf3f11152013-09-05 16:47:16 -0700212 public void write4Bytes(ChannelBuffer c) {
213 c.writeInt(rawValue);
214 }
Yotam Harchola289d552013-09-16 10:10:40 -0700215
216 public static IPv4Address read4Bytes(ChannelBuffer c) {
217 return IPv4Address.of(c.readInt());
Yotam Harcholf3f11152013-09-05 16:47:16 -0700218 }
219
220 @Override
Yotam Harchola289d552013-09-16 10:10:40 -0700221 public IPv4Address applyMask(IPv4Address mask) {
Aditya Vaja98c96e72014-03-11 15:19:01 -0700222 return and(mask);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700223 }
224
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700225 @Override
226 public int hashCode() {
227 final int prime = 31;
228 int result = 1;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700229 result = prime * result + rawValue;
230 return result;
231 }
Yotam Harchola289d552013-09-16 10:10:40 -0700232
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700233 @Override
234 public boolean equals(Object obj) {
235 if (this == obj)
236 return true;
237 if (obj == null)
238 return false;
239 if (getClass() != obj.getClass())
240 return false;
241 IPv4Address other = (IPv4Address) obj;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700242 if (rawValue != other.rawValue)
243 return false;
244 return true;
245 }
246
247 @Override
248 public int compareTo(IPv4Address o) {
249 return UnsignedInts.compare(rawValue, o.rawValue);
250 }
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700251
252 @Override
253 public void putTo(PrimitiveSink sink) {
254 sink.putInt(rawValue);
255 }
256
Yotam Harcholf3f11152013-09-05 16:47:16 -0700257}