blob: 81010d64bc1945363497e5a8efdb95805f8ba8f0 [file] [log] [blame]
Jonathan Hart8f6dc092014-04-18 15:56:43 -07001package net.onrc.onos.apps.sdnip;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
3import java.net.InetAddress;
4import java.net.UnknownHostException;
Jonathan Hart32e18222013-08-07 22:05:42 +12005import java.util.Arrays;
pingping-lina2cbfad2013-03-07 08:39:21 +08006
Jonathan Hartabf10222013-08-13 10:19:34 +12007import com.google.common.net.InetAddresses;
8
Jonathan Hart31e15f12014-04-10 10:33:00 -07009/**
10 * Represents an IP prefix.
11 * <p/>
12 * It is made up of an IP address and a number of significant bits in the
13 * prefix (i.e. the size of the network part of the address).
14 * E.g. {@code 192.168.0.0/16}.
15 * <p/>
16 * Currently only IPv4 is supported, so a prefix length can be up to 32 bits.
17 */
pingping-lina2cbfad2013-03-07 08:39:21 +080018public class Prefix {
Jonathan Hart31e15f12014-04-10 10:33:00 -070019 /**
20 * The length of addresses this class can represent prefixes of, in bytes.
21 */
Jonathan Hartf6978ce2014-06-23 11:20:04 -070022 public static final int ADDRESS_LENGTH_BYTES = 4;
23
24 /**
25 * The length of addresses this class can represent prefixes of, in bits.
26 */
27 public static final int MAX_PREFIX_LENGTH = Byte.SIZE * ADDRESS_LENGTH_BYTES;
28
29 public static final int MIN_PREFIX_LENGTH = 0;
pingping-lina2cbfad2013-03-07 08:39:21 +080030
Ray Milkey269ffb92014-04-03 14:43:30 -070031 private final int prefixLength;
32 private final byte[] address;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070033 private final String binaryString;
Jonathan Hart61ba9372013-05-19 20:10:29 -070034
Jonathan Hart31e15f12014-04-10 10:33:00 -070035 // For verifying the arguments and pretty printing
Ray Milkey269ffb92014-04-03 14:43:30 -070036 private final InetAddress inetAddress;
Jonathan Hart32e18222013-08-07 22:05:42 +120037
Jonathan Hart31e15f12014-04-10 10:33:00 -070038 /**
39 * Class constructor, taking an byte array representing and IP address and
40 * a prefix length.
41 * <p/>
42 * The valid values for addr and prefixLength are bounded by
Jonathan Hartf6978ce2014-06-23 11:20:04 -070043 * {@link #ADDRESS_LENGTH_BYTES}.
Jonathan Hart31e15f12014-04-10 10:33:00 -070044 * <p/>
45 * A valid addr array satisfies
Jonathan Hartf6978ce2014-06-23 11:20:04 -070046 * {@code addr.length == }{@value #ADDRESS_LENGTH_BYTES}.
Jonathan Hart31e15f12014-04-10 10:33:00 -070047 * <p/>
48 * A valid prefixLength satisfies
Jonathan Hartf6978ce2014-06-23 11:20:04 -070049 * {@code (prefixLength >= 0 && prefixLength <=} {@link Byte#SIZE}
50 * {@code * }{@value #ADDRESS_LENGTH_BYTES}{@code )}.
Jonathan Hart31e15f12014-04-10 10:33:00 -070051 *
52 * @param addr a byte array representing the address
53 * @param prefixLength length of the prefix of the specified address
54 */
Ray Milkey269ffb92014-04-03 14:43:30 -070055 public Prefix(byte[] addr, int prefixLength) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -070056 if (addr == null || addr.length != ADDRESS_LENGTH_BYTES ||
57 prefixLength < MIN_PREFIX_LENGTH ||
58 prefixLength > MAX_PREFIX_LENGTH) {
Ray Milkey269ffb92014-04-03 14:43:30 -070059 throw new IllegalArgumentException();
60 }
Jonathan Hart61ba9372013-05-19 20:10:29 -070061
Ray Milkey269ffb92014-04-03 14:43:30 -070062 address = canonicalizeAddress(addr, prefixLength);
63 this.prefixLength = prefixLength;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070064 binaryString = createBinaryString();
Ray Milkey269ffb92014-04-03 14:43:30 -070065
66 try {
67 inetAddress = InetAddress.getByAddress(address);
68 } catch (UnknownHostException e) {
Jonathan Hart738980f2014-04-04 10:11:15 -070069 throw new IllegalArgumentException("Couldn't parse IP address", e);
Ray Milkey269ffb92014-04-03 14:43:30 -070070 }
71 }
72
Jonathan Hart31e15f12014-04-10 10:33:00 -070073 /**
74 * Class constructor, taking an address in String format and a prefix
75 * length. The address must be in dot-notation form (e.g. {@code 0.0.0.0}).
76 *
77 * @param strAddress a String representing the address
78 * @param prefixLength length of the prefix of the specified address
79 */
Ray Milkey269ffb92014-04-03 14:43:30 -070080 public Prefix(String strAddress, int prefixLength) {
81 byte[] addr = null;
82 addr = InetAddresses.forString(strAddress).getAddress();
83
Jonathan Hartf6978ce2014-06-23 11:20:04 -070084 if (addr == null || addr.length != ADDRESS_LENGTH_BYTES ||
85 prefixLength < MIN_PREFIX_LENGTH ||
86 prefixLength > MAX_PREFIX_LENGTH) {
Ray Milkey269ffb92014-04-03 14:43:30 -070087 throw new IllegalArgumentException();
88 }
89
90 address = canonicalizeAddress(addr, prefixLength);
91 this.prefixLength = prefixLength;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070092 binaryString = createBinaryString();
Ray Milkey269ffb92014-04-03 14:43:30 -070093
94 try {
95 inetAddress = InetAddress.getByAddress(address);
96 } catch (UnknownHostException e) {
Jonathan Hart738980f2014-04-04 10:11:15 -070097 throw new IllegalArgumentException("Couldn't parse IP address", e);
Ray Milkey269ffb92014-04-03 14:43:30 -070098 }
99 }
100
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700101 /**
102 * This method takes a byte array passed in by the user and ensures it
103 * conforms to the format we want. The byte array can contain anything,
104 * but only some of the bits are significant. The bits after
105 * prefixLengthValue are not significant, and this method will zero them
106 * out in order to ensure there is a canonical representation for each
107 * prefix. This simplifies the equals and hashcode methods, because once we
108 * have a canonical byte array representation we can simply compare byte
109 * arrays to test equality.
110 *
111 * @param addressValue the byte array to canonicalize
112 * @param prefixLengthValue The length of the prefix. Bits up to and including
113 * prefixLength are significant, bits following prefixLength are not
114 * significant and will be zeroed out.
115 * @return the canonicalized representation of the prefix
116 */
Ray Milkey5df613b2014-04-15 10:50:56 -0700117 private byte[] canonicalizeAddress(byte[] addressValue,
118 int prefixLengthValue) {
119 byte[] result = new byte[addressValue.length];
Ray Milkey269ffb92014-04-03 14:43:30 -0700120
Ray Milkey5df613b2014-04-15 10:50:56 -0700121 if (prefixLengthValue == 0) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700122 for (int i = 0; i < ADDRESS_LENGTH_BYTES; i++) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700123 result[i] = 0;
124 }
125
126 return result;
127 }
128
Ray Milkey5df613b2014-04-15 10:50:56 -0700129 result = Arrays.copyOf(addressValue, addressValue.length);
Ray Milkey269ffb92014-04-03 14:43:30 -0700130
131 //Set all bytes after the end of the prefix to 0
Ray Milkey5df613b2014-04-15 10:50:56 -0700132 int lastByteIndex = (prefixLengthValue - 1) / Byte.SIZE;
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700133 for (int i = lastByteIndex; i < ADDRESS_LENGTH_BYTES; i++) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 result[i] = 0;
135 }
136
Ray Milkey5df613b2014-04-15 10:50:56 -0700137 byte lastByte = addressValue[lastByteIndex];
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 byte mask = 0;
139 byte msb = (byte) 0x80;
Ray Milkey5df613b2014-04-15 10:50:56 -0700140 int lastBit = (prefixLengthValue - 1) % Byte.SIZE;
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 for (int i = 0; i < Byte.SIZE; i++) {
142 if (i <= lastBit) {
143 mask |= (msb >> i);
144 }
145 }
146
147 result[lastByteIndex] = (byte) (lastByte & mask);
148
149 return result;
150 }
151
Jonathan Hart31e15f12014-04-10 10:33:00 -0700152 /**
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700153 * Creates the binary string representation of the prefix.
154 * The strings length is equal to prefixLength.
155 *
156 * @return the binary string representation
157 */
158 private String createBinaryString() {
159 if (prefixLength == 0) {
160 return "";
161 }
162
163 StringBuilder result = new StringBuilder(prefixLength);
164 for (int i = 0; i < address.length; i++) {
165 byte b = address[i];
166 for (int j = 0; j < Byte.SIZE; j++) {
167 byte mask = (byte) (0x80 >>> j);
168 result.append(((b & mask) == 0) ? "0" : "1");
169 if (i * Byte.SIZE + j == prefixLength - 1) {
170 return result.toString();
171 }
172 }
173 }
174 return result.toString();
175 }
176
177 /**
Jonathan Hart31e15f12014-04-10 10:33:00 -0700178 * Gets the length of the prefix of the address.
179 *
180 * @return the prefix length
181 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 public int getPrefixLength() {
183 return prefixLength;
184 }
185
Jonathan Hart31e15f12014-04-10 10:33:00 -0700186 /**
187 * Gets the address.
188 *
189 * @return the address as a byte array
190 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 public byte[] getAddress() {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700192 return Arrays.copyOf(address, address.length);
Ray Milkey269ffb92014-04-03 14:43:30 -0700193 }
194
pingping-lin1ada7ce2014-08-14 13:45:22 -0700195 /**
196 * Gets the InetAddress.
197 *
198 * @return the inetAddress
199 */
200 public InetAddress getInetAddress() {
201 return inetAddress;
202 }
203
204
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 @Override
206 public boolean equals(Object other) {
Jonathan Hart738980f2014-04-04 10:11:15 -0700207 if (!(other instanceof Prefix)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 return false;
209 }
210
211 Prefix otherPrefix = (Prefix) other;
212
213 return (Arrays.equals(address, otherPrefix.address)) &&
214 (prefixLength == otherPrefix.prefixLength);
215 }
216
217 @Override
218 public int hashCode() {
219 int hash = 17;
220 hash = 31 * hash + prefixLength;
221 hash = 31 * hash + Arrays.hashCode(address);
222 return hash;
223 }
224
225 @Override
226 public String toString() {
227 return inetAddress.getHostAddress() + "/" + prefixLength;
228 }
229
Jonathan Hart31e15f12014-04-10 10:33:00 -0700230 /**
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700231 * Gets a binary string representation of the prefix.
232 *
233 * @return a binary string representation
234 */
235 public String toBinaryString() {
236 return binaryString;
237 }
238
239 /**
Jonathan Hart31e15f12014-04-10 10:33:00 -0700240 * Print the prefix to a String showing the bits of the address.
241 *
242 * @return the bit-string of the prefix
243 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700244 public String printAsBits() {
Jonathan Hart738980f2014-04-04 10:11:15 -0700245 StringBuilder result = new StringBuilder();
Ray Milkey269ffb92014-04-03 14:43:30 -0700246 for (int i = 0; i < address.length; i++) {
247 byte b = address[i];
248 for (int j = 0; j < Byte.SIZE; j++) {
249 byte mask = (byte) (0x80 >>> j);
Jonathan Hart738980f2014-04-04 10:11:15 -0700250 result.append(((b & mask) == 0) ? "0" : "1");
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 if (i * Byte.SIZE + j == prefixLength - 1) {
Jonathan Hart738980f2014-04-04 10:11:15 -0700252 return result.toString();
Ray Milkey269ffb92014-04-03 14:43:30 -0700253 }
254 }
Jonathan Hart938a0152014-04-07 18:27:31 -0700255 result.append(' ');
Ray Milkey269ffb92014-04-03 14:43:30 -0700256 }
257 return result.substring(0, result.length() - 1);
258 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800259}