blob: a9da63737d8b7f13c1add1ebcd318b6f4895faad [file] [log] [blame]
Yotam Harcholf3f11152013-09-05 16:47:16 -07001package org.projectfloodlight.openflow.types;
2
3import org.jboss.netty.buffer.ChannelBuffer;
4
Andreas Wundsam22ba3af2013-10-04 16:00:30 -07005import com.google.common.hash.PrimitiveSink;
Andreas Wundsam85c961f2013-09-29 21:22:12 -07006import com.google.common.primitives.UnsignedInts;
7
Yotam Harcholf3f11152013-09-05 16:47:16 -07008
9
10/**
Yotam Harchola289d552013-09-16 10:10:40 -070011 * Wrapper around an IPv4Address address
Yotam Harcholf3f11152013-09-05 16:47:16 -070012 *
13 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
14 */
Yotam Harchol4d634682013-09-26 13:21:06 -070015public class IPv4Address extends IPAddress<IPv4Address> {
Yotam Harcholf3f11152013-09-05 16:47:16 -070016 static final int LENGTH = 4;
17 private final int rawValue;
Yotam Harcholf3f11152013-09-05 16:47:16 -070018
Gregor Maier1acb4502013-12-12 11:25:07 -080019 private static final int NOT_A_CIDR_MASK = -1;
20 private static final int CIDR_MASK_CACHE_UNSET = -2;
Gregor Maier5615b6c2013-12-11 22:29:07 -080021 // Must appear before the static IPv4Address constant assignments
22 private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
23
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070024 private final static int NONE_VAL = 0x0;
25 public final static IPv4Address NONE = new IPv4Address(NONE_VAL);
26
Yotam Harchola289d552013-09-16 10:10:40 -070027 public static final IPv4Address NO_MASK = IPv4Address.of(0xFFFFFFFF);
28 public static final IPv4Address FULL_MASK = IPv4Address.of(0x00000000);
29
30 private IPv4Address(final int rawValue) {
Yotam Harcholf3f11152013-09-05 16:47:16 -070031 this.rawValue = rawValue;
32 }
33
Yotam Harchol4d634682013-09-26 13:21:06 -070034 @Override
Yotam Harcholeb023dc2013-09-26 15:45:44 -070035 public IPVersion getIpVersion() {
36 return IPVersion.IPv4;
Yotam Harchol4d634682013-09-26 13:21:06 -070037 }
38
Gregor Maier5615b6c2013-12-11 22:29:07 -080039 private int asCidrMaskLengthInternal() {
40 if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
41 // No lock required. We only write cidrMaskLengthCache once
42 int maskint = getInt();
43 if (maskint == 0) {
44 cidrMaskLengthCache = 0;
45 } else if (Integer.bitCount((~maskint) + 1) == 1) {
46 // IP represents a true CIDR prefix length
47 cidrMaskLengthCache = Integer.bitCount(maskint);
48 } else {
49 cidrMaskLengthCache = NOT_A_CIDR_MASK;
50 }
51 }
52 return cidrMaskLengthCache;
53 }
54
55 @Override
56 public boolean isCidrMask() {
57 return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
58 }
Gregor Maier7f987e62013-12-10 19:34:18 -080059
60 @Override
61 public int asCidrMaskLength() {
Gregor Maier5615b6c2013-12-11 22:29:07 -080062 if (!isCidrMask()) {
63 throw new IllegalStateException("IP is not a valid CIDR prefix " +
64 "mask " + toString());
Gregor Maier7f987e62013-12-10 19:34:18 -080065 } else {
Gregor Maier5615b6c2013-12-11 22:29:07 -080066 return asCidrMaskLengthInternal();
Gregor Maier7f987e62013-12-10 19:34:18 -080067 }
68 }
69
Yotam Harchola289d552013-09-16 10:10:40 -070070 public static IPv4Address of(final byte[] address) {
Gregor Maier1ff55972013-12-11 02:22:56 -080071 if (address == null) {
72 throw new NullPointerException("Address must not be null");
73 }
Yotam Harcholf3f11152013-09-05 16:47:16 -070074 if (address.length != LENGTH) {
75 throw new IllegalArgumentException(
Andreas Wundsamc85b5c52013-09-24 13:01:43 -070076 "Invalid byte array length for IPv4Address address: " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -070077 }
78
79 int raw =
80 (address[0] & 0xFF) << 24 | (address[1] & 0xFF) << 16
81 | (address[2] & 0xFF) << 8 | (address[3] & 0xFF) << 0;
Yotam Harchola289d552013-09-16 10:10:40 -070082 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -070083 }
84
Yotam Harchola289d552013-09-16 10:10:40 -070085 public static IPv4Address of(final int raw) {
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070086 if(raw == NONE_VAL)
87 return NONE;
Yotam Harchola289d552013-09-16 10:10:40 -070088 return new IPv4Address(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -070089 }
90
Yotam Harchola289d552013-09-16 10:10:40 -070091 public static IPv4Address of(final String string) {
Gregor Maier1ff55972013-12-11 02:22:56 -080092 if (string == null) {
93 throw new NullPointerException("String must not be null");
94 }
Yotam Harcholf3f11152013-09-05 16:47:16 -070095 int start = 0;
96 int shift = 24;
97
98 int raw = 0;
99 while (shift >= 0) {
100 int end = string.indexOf('.', start);
101 if (end == start || !((shift > 0) ^ (end < 0)))
102 throw new IllegalArgumentException("IP Address not well formed: " + string);
103
104 String substr =
105 end > 0 ? string.substring(start, end) : string.substring(start);
106 int val = Integer.parseInt(substr);
107 if (val < 0 || val > 255)
108 throw new IllegalArgumentException("IP Address not well formed: " + string);
109
110 raw |= val << shift;
111
112 shift -= 8;
113 start = end + 1;
114 }
Yotam Harchola289d552013-09-16 10:10:40 -0700115 return IPv4Address.of(raw);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700116 }
117
118 public int getInt() {
119 return rawValue;
120 }
121
122 volatile byte[] bytesCache = null;
123
124 public byte[] getBytes() {
125 if (bytesCache == null) {
126 synchronized (this) {
127 if (bytesCache == null) {
128 bytesCache =
129 new byte[] { (byte) ((rawValue >>> 24) & 0xFF),
130 (byte) ((rawValue >>> 16) & 0xFF),
131 (byte) ((rawValue >>> 8) & 0xFF),
132 (byte) ((rawValue >>> 0) & 0xFF) };
133 }
134 }
135 }
136 return bytesCache;
137 }
138
139 @Override
140 public int getLength() {
141 return LENGTH;
142 }
143
144 @Override
145 public String toString() {
146 StringBuilder res = new StringBuilder();
147 res.append((rawValue >> 24) & 0xFF).append('.');
148 res.append((rawValue >> 16) & 0xFF).append('.');
149 res.append((rawValue >> 8) & 0xFF).append('.');
150 res.append((rawValue >> 0) & 0xFF);
151 return res.toString();
152 }
153
Yotam Harcholf3f11152013-09-05 16:47:16 -0700154 public void write4Bytes(ChannelBuffer c) {
155 c.writeInt(rawValue);
156 }
Yotam Harchola289d552013-09-16 10:10:40 -0700157
158 public static IPv4Address read4Bytes(ChannelBuffer c) {
159 return IPv4Address.of(c.readInt());
Yotam Harcholf3f11152013-09-05 16:47:16 -0700160 }
161
162 @Override
Yotam Harchola289d552013-09-16 10:10:40 -0700163 public IPv4Address applyMask(IPv4Address mask) {
164 return IPv4Address.of(this.rawValue & mask.rawValue);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700165 }
166
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700167 @Override
168 public int hashCode() {
169 final int prime = 31;
170 int result = 1;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700171 result = prime * result + rawValue;
172 return result;
173 }
Yotam Harchola289d552013-09-16 10:10:40 -0700174
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700175 @Override
176 public boolean equals(Object obj) {
177 if (this == obj)
178 return true;
179 if (obj == null)
180 return false;
181 if (getClass() != obj.getClass())
182 return false;
183 IPv4Address other = (IPv4Address) obj;
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700184 if (rawValue != other.rawValue)
185 return false;
186 return true;
187 }
188
189 @Override
190 public int compareTo(IPv4Address o) {
191 return UnsignedInts.compare(rawValue, o.rawValue);
192 }
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700193
194 @Override
195 public void putTo(PrimitiveSink sink) {
196 sink.putInt(rawValue);
197 }
198
Yotam Harcholf3f11152013-09-05 16:47:16 -0700199}