blob: 43fefac4c6a0ffdd560c7adc42e738d3b4d75ee6 [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
Yotam Harcholf3f11152013-09-05 16:47:16 -07005import org.jboss.netty.buffer.ChannelBuffer;
6
Andreas Wundsam22ba3af2013-10-04 16:00:30 -07007import com.google.common.hash.PrimitiveSink;
Andreas Wundsam85c961f2013-09-29 21:22:12 -07008import com.google.common.primitives.UnsignedInts;
9
Yotam Harcholf3f11152013-09-05 16:47:16 -070010
11
12/**
Yotam Harchola289d552013-09-16 10:10:40 -070013 * Wrapper around an IPv4Address address
Yotam Harcholf3f11152013-09-05 16:47:16 -070014 *
15 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
16 */
Yotam Harchol4d634682013-09-26 13:21:06 -070017public class IPv4Address extends IPAddress<IPv4Address> {
Yotam Harcholf3f11152013-09-05 16:47:16 -070018 static final int LENGTH = 4;
19 private final int rawValue;
Yotam Harcholf3f11152013-09-05 16:47:16 -070020
Gregor Maier1acb4502013-12-12 11:25:07 -080021 private static final int NOT_A_CIDR_MASK = -1;
22 private static final int CIDR_MASK_CACHE_UNSET = -2;
Gregor Maier5615b6c2013-12-11 22:29:07 -080023 // Must appear before the static IPv4Address constant assignments
24 private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
25
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070026 private final static int NONE_VAL = 0x0;
27 public final static IPv4Address NONE = new IPv4Address(NONE_VAL);
28
Yotam Harchola289d552013-09-16 10:10:40 -070029 public static final IPv4Address NO_MASK = IPv4Address.of(0xFFFFFFFF);
30 public static final IPv4Address FULL_MASK = IPv4Address.of(0x00000000);
31
32 private IPv4Address(final int rawValue) {
Yotam Harcholf3f11152013-09-05 16:47:16 -070033 this.rawValue = rawValue;
34 }
35
Yotam Harchol4d634682013-09-26 13:21:06 -070036 @Override
Yotam Harcholeb023dc2013-09-26 15:45:44 -070037 public IPVersion getIpVersion() {
38 return IPVersion.IPv4;
Yotam Harchol4d634682013-09-26 13:21:06 -070039 }
40
Gregor Maier5615b6c2013-12-11 22:29:07 -080041 private int asCidrMaskLengthInternal() {
42 if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
43 // No lock required. We only write cidrMaskLengthCache once
44 int maskint = getInt();
45 if (maskint == 0) {
46 cidrMaskLengthCache = 0;
47 } else if (Integer.bitCount((~maskint) + 1) == 1) {
48 // IP represents a true CIDR prefix length
49 cidrMaskLengthCache = Integer.bitCount(maskint);
50 } else {
51 cidrMaskLengthCache = NOT_A_CIDR_MASK;
52 }
53 }
54 return cidrMaskLengthCache;
55 }
56
57 @Override
58 public boolean isCidrMask() {
59 return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
60 }
Gregor Maier7f987e62013-12-10 19:34:18 -080061
62 @Override
63 public int asCidrMaskLength() {
Gregor Maier5615b6c2013-12-11 22:29:07 -080064 if (!isCidrMask()) {
65 throw new IllegalStateException("IP is not a valid CIDR prefix " +
66 "mask " + toString());
Gregor Maier7f987e62013-12-10 19:34:18 -080067 } else {
Gregor Maier5615b6c2013-12-11 22:29:07 -080068 return asCidrMaskLengthInternal();
Gregor Maier7f987e62013-12-10 19:34:18 -080069 }
70 }
71
Aditya Vaja56b8b182014-03-11 13:13:58 -070072 @Override
73 public boolean isBroadcast() {
74 return this.equals(NO_MASK);
75 }
76
77 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -070078 public IPv4Address and(IPv4Address other) {
Aditya Vaja56b8b182014-03-11 13:13:58 -070079 if (other == null) {
80 throw new NullPointerException("Other IP Address must not be null");
81 }
82 IPv4Address otherIp = (IPv4Address) other;
83 return IPv4Address.of(rawValue & otherIp.rawValue);
84 }
85
86 @Override
Aditya Vaja98c96e72014-03-11 15:19:01 -070087 public IPv4Address or(IPv4Address other) {
Aditya Vaja56b8b182014-03-11 13:13:58 -070088 if (other == null) {
89 throw new NullPointerException("Other IP Address must not be null");
90 }
91 IPv4Address otherIp = (IPv4Address) other;
92 return IPv4Address.of(rawValue | otherIp.rawValue);
93 }
94
95 @Override
96 public IPv4Address not() {
97 return IPv4Address.of(~rawValue);
98 }
99
Yotam Harchola289d552013-09-16 10:10:40 -0700100 public static IPv4Address of(final byte[] address) {
Gregor Maier1ff55972013-12-11 02:22:56 -0800101 if (address == null) {
102 throw new NullPointerException("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
Yotam Harchola289d552013-09-16 10:10:40 -0700115 public static IPv4Address of(final int raw) {
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -0700116 if(raw == NONE_VAL)
117 return NONE;
Yotam Harchola289d552013-09-16 10:10:40 -0700118 return new IPv4Address(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700119 }
120
Yotam Harchola289d552013-09-16 10:10:40 -0700121 public static IPv4Address of(final String string) {
Gregor Maier1ff55972013-12-11 02:22:56 -0800122 if (string == null) {
123 throw new NullPointerException("String must not be null");
124 }
Yotam Harcholf3f11152013-09-05 16:47:16 -0700125 int start = 0;
126 int shift = 24;
127
128 int raw = 0;
129 while (shift >= 0) {
130 int end = string.indexOf('.', start);
131 if (end == start || !((shift > 0) ^ (end < 0)))
132 throw new IllegalArgumentException("IP Address not well formed: " + string);
133
134 String substr =
135 end > 0 ? string.substring(start, end) : string.substring(start);
136 int val = Integer.parseInt(substr);
137 if (val < 0 || val > 255)
138 throw new IllegalArgumentException("IP Address not well formed: " + string);
139
140 raw |= val << shift;
141
142 shift -= 8;
143 start = end + 1;
144 }
Yotam Harchola289d552013-09-16 10:10:40 -0700145 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700146 }
147
148 public int getInt() {
149 return rawValue;
150 }
151
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800152 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -0700153
154 public byte[] getBytes() {
155 if (bytesCache == null) {
156 synchronized (this) {
157 if (bytesCache == null) {
158 bytesCache =
159 new byte[] { (byte) ((rawValue >>> 24) & 0xFF),
160 (byte) ((rawValue >>> 16) & 0xFF),
161 (byte) ((rawValue >>> 8) & 0xFF),
162 (byte) ((rawValue >>> 0) & 0xFF) };
163 }
164 }
165 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800166 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700167 }
168
169 @Override
170 public int getLength() {
171 return LENGTH;
172 }
173
174 @Override
175 public String toString() {
176 StringBuilder res = new StringBuilder();
177 res.append((rawValue >> 24) & 0xFF).append('.');
178 res.append((rawValue >> 16) & 0xFF).append('.');
179 res.append((rawValue >> 8) & 0xFF).append('.');
180 res.append((rawValue >> 0) & 0xFF);
181 return res.toString();
182 }
183
Yotam Harcholf3f11152013-09-05 16:47:16 -0700184 public void write4Bytes(ChannelBuffer c) {
185 c.writeInt(rawValue);
186 }
Yotam Harchola289d552013-09-16 10:10:40 -0700187
188 public static IPv4Address read4Bytes(ChannelBuffer c) {
189 return IPv4Address.of(c.readInt());
Yotam Harcholf3f11152013-09-05 16:47:16 -0700190 }
191
192 @Override
Yotam Harchola289d552013-09-16 10:10:40 -0700193 public IPv4Address applyMask(IPv4Address mask) {
Aditya Vaja98c96e72014-03-11 15:19:01 -0700194 return and(mask);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700195 }
196
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700197 @Override
198 public int hashCode() {
199 final int prime = 31;
200 int result = 1;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700201 result = prime * result + rawValue;
202 return result;
203 }
Yotam Harchola289d552013-09-16 10:10:40 -0700204
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700205 @Override
206 public boolean equals(Object obj) {
207 if (this == obj)
208 return true;
209 if (obj == null)
210 return false;
211 if (getClass() != obj.getClass())
212 return false;
213 IPv4Address other = (IPv4Address) obj;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700214 if (rawValue != other.rawValue)
215 return false;
216 return true;
217 }
218
219 @Override
220 public int compareTo(IPv4Address o) {
221 return UnsignedInts.compare(rawValue, o.rawValue);
222 }
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700223
224 @Override
225 public void putTo(PrimitiveSink sink) {
226 sink.putInt(rawValue);
227 }
228
Yotam Harcholf3f11152013-09-05 16:47:16 -0700229}