blob: 865fb79d616492bc266e62439d04736863486044 [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
Andreas Wundsam22ba3af2013-10-04 16:00:30 -07009import com.google.common.hash.PrimitiveSink;
Andreas Wundsam85c961f2013-09-29 21:22:12 -070010import com.google.common.primitives.UnsignedInts;
11
Yotam Harcholf3f11152013-09-05 16:47:16 -070012
13
14/**
Yotam Harchola289d552013-09-16 10:10:40 -070015 * Wrapper around an IPv4Address address
Yotam Harcholf3f11152013-09-05 16:47:16 -070016 *
17 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
18 */
Yotam Harchol4d634682013-09-26 13:21:06 -070019public class IPv4Address extends IPAddress<IPv4Address> {
Yotam Harcholf3f11152013-09-05 16:47:16 -070020 static final int LENGTH = 4;
21 private final int rawValue;
Yotam Harcholf3f11152013-09-05 16:47:16 -070022
Gregor Maier1acb4502013-12-12 11:25:07 -080023 private static final int NOT_A_CIDR_MASK = -1;
24 private static final int CIDR_MASK_CACHE_UNSET = -2;
Gregor Maier5615b6c2013-12-11 22:29:07 -080025 // Must appear before the static IPv4Address constant assignments
26 private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
27
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070028 private final static int NONE_VAL = 0x0;
29 public final static IPv4Address NONE = new IPv4Address(NONE_VAL);
30
Yotam Harchola289d552013-09-16 10:10:40 -070031 public static final IPv4Address NO_MASK = IPv4Address.of(0xFFFFFFFF);
32 public static final IPv4Address FULL_MASK = IPv4Address.of(0x00000000);
33
34 private IPv4Address(final int rawValue) {
Yotam Harcholf3f11152013-09-05 16:47:16 -070035 this.rawValue = rawValue;
36 }
37
Yotam Harchol4d634682013-09-26 13:21:06 -070038 @Override
Yotam Harcholeb023dc2013-09-26 15:45:44 -070039 public IPVersion getIpVersion() {
40 return IPVersion.IPv4;
Yotam Harchol4d634682013-09-26 13:21:06 -070041 }
42
Gregor Maier5615b6c2013-12-11 22:29:07 -080043 private int asCidrMaskLengthInternal() {
44 if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
45 // No lock required. We only write cidrMaskLengthCache once
46 int maskint = getInt();
47 if (maskint == 0) {
48 cidrMaskLengthCache = 0;
49 } else if (Integer.bitCount((~maskint) + 1) == 1) {
50 // IP represents a true CIDR prefix length
51 cidrMaskLengthCache = Integer.bitCount(maskint);
52 } else {
53 cidrMaskLengthCache = NOT_A_CIDR_MASK;
54 }
55 }
56 return cidrMaskLengthCache;
57 }
58
59 @Override
60 public boolean isCidrMask() {
61 return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
62 }
Gregor Maier7f987e62013-12-10 19:34:18 -080063
64 @Override
65 public int asCidrMaskLength() {
Gregor Maier5615b6c2013-12-11 22:29:07 -080066 if (!isCidrMask()) {
67 throw new IllegalStateException("IP is not a valid CIDR prefix " +
68 "mask " + toString());
Gregor Maier7f987e62013-12-10 19:34:18 -080069 } else {
Gregor Maier5615b6c2013-12-11 22:29:07 -080070 return asCidrMaskLengthInternal();
Gregor Maier7f987e62013-12-10 19:34:18 -080071 }
72 }
73
Aditya Vaja56b8b182014-03-11 13:13:58 -070074 @Override
75 public boolean isBroadcast() {
76 return this.equals(NO_MASK);
77 }
78
79 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -070080 public IPv4Address and(IPv4Address other) {
Aditya Vaja56b8b182014-03-11 13:13:58 -070081 if (other == null) {
82 throw new NullPointerException("Other IP Address must not be null");
83 }
84 IPv4Address otherIp = (IPv4Address) other;
85 return IPv4Address.of(rawValue & otherIp.rawValue);
86 }
87
88 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -070089 public IPv4Address or(IPv4Address other) {
Aditya Vaja56b8b182014-03-11 13:13:58 -070090 if (other == null) {
91 throw new NullPointerException("Other IP Address must not be null");
92 }
93 IPv4Address otherIp = (IPv4Address) other;
94 return IPv4Address.of(rawValue | otherIp.rawValue);
95 }
96
97 @Override
98 public IPv4Address not() {
99 return IPv4Address.of(~rawValue);
100 }
101
Yotam Harchola289d552013-09-16 10:10:40 -0700102 public static IPv4Address of(final byte[] address) {
Gregor Maier1ff55972013-12-11 02:22:56 -0800103 if (address == null) {
104 throw new NullPointerException("Address must not be null");
105 }
Yotam Harcholf3f11152013-09-05 16:47:16 -0700106 if (address.length != LENGTH) {
107 throw new IllegalArgumentException(
Andreas Wundsamc85b5c52013-09-24 13:01:43 -0700108 "Invalid byte array length for IPv4Address address: " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700109 }
110
111 int raw =
112 (address[0] & 0xFF) << 24 | (address[1] & 0xFF) << 16
113 | (address[2] & 0xFF) << 8 | (address[3] & 0xFF) << 0;
Yotam Harchola289d552013-09-16 10:10:40 -0700114 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700115 }
116
Andreas Wundsam3700d162014-03-11 04:43:38 -0700117 /** construct an IPv4Address from a 32-bit integer value.
118 *
119 * @param raw the IPAdress represented as a 32-bit integer
120 * @return the constructed IPv4Address
121 */
Yotam Harchola289d552013-09-16 10:10:40 -0700122 public static IPv4Address of(final int raw) {
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -0700123 if(raw == NONE_VAL)
124 return NONE;
Yotam Harchola289d552013-09-16 10:10:40 -0700125 return new IPv4Address(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700126 }
127
Andreas Wundsam3700d162014-03-11 04:43:38 -0700128 /** parse an IPv4Address from the canonical dotted-quad representation
129 * (1.2.3.4).
130 *
131 * @param string an IPv4 address in dotted-quad representation
132 * @return the parsed IPv4 address
133 * @throws NullPointerException if string is null
134 * @throws IllegalArgumentException if string is not a valid IPv4Address
135 */
136 @Nonnull
137 public static IPv4Address of(@Nonnull final String string) throws IllegalArgumentException {
Gregor Maier1ff55972013-12-11 02:22:56 -0800138 if (string == null) {
139 throw new NullPointerException("String must not be null");
140 }
Yotam Harcholf3f11152013-09-05 16:47:16 -0700141 int start = 0;
142 int shift = 24;
143
144 int raw = 0;
145 while (shift >= 0) {
146 int end = string.indexOf('.', start);
147 if (end == start || !((shift > 0) ^ (end < 0)))
148 throw new IllegalArgumentException("IP Address not well formed: " + string);
149
150 String substr =
151 end > 0 ? string.substring(start, end) : string.substring(start);
152 int val = Integer.parseInt(substr);
153 if (val < 0 || val > 255)
154 throw new IllegalArgumentException("IP Address not well formed: " + string);
155
156 raw |= val << shift;
157
158 shift -= 8;
159 start = end + 1;
160 }
Yotam Harchola289d552013-09-16 10:10:40 -0700161 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700162 }
163
164 public int getInt() {
165 return rawValue;
166 }
167
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800168 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700169
170 public byte[] getBytes() {
171 if (bytesCache == null) {
172 synchronized (this) {
173 if (bytesCache == null) {
174 bytesCache =
175 new byte[] { (byte) ((rawValue >>> 24) & 0xFF),
176 (byte) ((rawValue >>> 16) & 0xFF),
177 (byte) ((rawValue >>> 8) & 0xFF),
178 (byte) ((rawValue >>> 0) & 0xFF) };
179 }
180 }
181 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800182 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700183 }
184
185 @Override
186 public int getLength() {
187 return LENGTH;
188 }
189
190 @Override
191 public String toString() {
192 StringBuilder res = new StringBuilder();
193 res.append((rawValue >> 24) & 0xFF).append('.');
194 res.append((rawValue >> 16) & 0xFF).append('.');
195 res.append((rawValue >> 8) & 0xFF).append('.');
196 res.append((rawValue >> 0) & 0xFF);
197 return res.toString();
198 }
199
Yotam Harcholf3f11152013-09-05 16:47:16 -0700200 public void write4Bytes(ChannelBuffer c) {
201 c.writeInt(rawValue);
202 }
Yotam Harchola289d552013-09-16 10:10:40 -0700203
204 public static IPv4Address read4Bytes(ChannelBuffer c) {
205 return IPv4Address.of(c.readInt());
Yotam Harcholf3f11152013-09-05 16:47:16 -0700206 }
207
208 @Override
Yotam Harchola289d552013-09-16 10:10:40 -0700209 public IPv4Address applyMask(IPv4Address mask) {
Aditya Vaja98c96e72014-03-11 15:19:01 -0700210 return and(mask);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700211 }
212
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700213 @Override
214 public int hashCode() {
215 final int prime = 31;
216 int result = 1;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700217 result = prime * result + rawValue;
218 return result;
219 }
Yotam Harchola289d552013-09-16 10:10:40 -0700220
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700221 @Override
222 public boolean equals(Object obj) {
223 if (this == obj)
224 return true;
225 if (obj == null)
226 return false;
227 if (getClass() != obj.getClass())
228 return false;
229 IPv4Address other = (IPv4Address) obj;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700230 if (rawValue != other.rawValue)
231 return false;
232 return true;
233 }
234
235 @Override
236 public int compareTo(IPv4Address o) {
237 return UnsignedInts.compare(rawValue, o.rawValue);
238 }
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700239
240 @Override
241 public void putTo(PrimitiveSink sink) {
242 sink.putInt(rawValue);
243 }
244
Yotam Harcholf3f11152013-09-05 16:47:16 -0700245}