blob: 91510b1b2deb0deddd4bfa8f72d9a6c014a0c5b7 [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 */
22 public static final int ADDRESS_LENGTH = 4;
pingping-lina2cbfad2013-03-07 08:39:21 +080023
Ray Milkey269ffb92014-04-03 14:43:30 -070024 private final int prefixLength;
25 private final byte[] address;
Jonathan Hart61ba9372013-05-19 20:10:29 -070026
Jonathan Hart31e15f12014-04-10 10:33:00 -070027 // For verifying the arguments and pretty printing
Ray Milkey269ffb92014-04-03 14:43:30 -070028 private final InetAddress inetAddress;
Jonathan Hart32e18222013-08-07 22:05:42 +120029
Jonathan Hart31e15f12014-04-10 10:33:00 -070030 /**
31 * Class constructor, taking an byte array representing and IP address and
32 * a prefix length.
33 * <p/>
34 * The valid values for addr and prefixLength are bounded by
35 * {@link #ADDRESS_LENGTH}.
36 * <p/>
37 * A valid addr array satisfies
38 * {@code addr.length == }{@value #ADDRESS_LENGTH}.
39 * <p/>
40 * A valid prefixLength satisfies
41 * {@code (prefixLength > 0 && prefixLength <=} {@link Byte#SIZE}
42 * {@code * }{@value #ADDRESS_LENGTH}{@code )}.
43 *
44 * @param addr a byte array representing the address
45 * @param prefixLength length of the prefix of the specified address
46 */
Ray Milkey269ffb92014-04-03 14:43:30 -070047 public Prefix(byte[] addr, int prefixLength) {
Jonathan Hart31e15f12014-04-10 10:33:00 -070048 if (addr == null || addr.length != ADDRESS_LENGTH ||
49 prefixLength < 0 || prefixLength > ADDRESS_LENGTH * Byte.SIZE) {
Ray Milkey269ffb92014-04-03 14:43:30 -070050 throw new IllegalArgumentException();
51 }
Jonathan Hart61ba9372013-05-19 20:10:29 -070052
Ray Milkey269ffb92014-04-03 14:43:30 -070053 address = canonicalizeAddress(addr, prefixLength);
54 this.prefixLength = prefixLength;
55
56 try {
57 inetAddress = InetAddress.getByAddress(address);
58 } catch (UnknownHostException e) {
Jonathan Hart738980f2014-04-04 10:11:15 -070059 throw new IllegalArgumentException("Couldn't parse IP address", e);
Ray Milkey269ffb92014-04-03 14:43:30 -070060 }
61 }
62
Jonathan Hart31e15f12014-04-10 10:33:00 -070063 /**
64 * Class constructor, taking an address in String format and a prefix
65 * length. The address must be in dot-notation form (e.g. {@code 0.0.0.0}).
66 *
67 * @param strAddress a String representing the address
68 * @param prefixLength length of the prefix of the specified address
69 */
Ray Milkey269ffb92014-04-03 14:43:30 -070070 public Prefix(String strAddress, int prefixLength) {
71 byte[] addr = null;
72 addr = InetAddresses.forString(strAddress).getAddress();
73
Jonathan Hart31e15f12014-04-10 10:33:00 -070074 if (addr == null || addr.length != ADDRESS_LENGTH ||
75 prefixLength < 0 || prefixLength > ADDRESS_LENGTH * Byte.SIZE) {
Ray Milkey269ffb92014-04-03 14:43:30 -070076 throw new IllegalArgumentException();
77 }
78
79 address = canonicalizeAddress(addr, prefixLength);
80 this.prefixLength = prefixLength;
81
82 try {
83 inetAddress = InetAddress.getByAddress(address);
84 } catch (UnknownHostException e) {
Jonathan Hart738980f2014-04-04 10:11:15 -070085 throw new IllegalArgumentException("Couldn't parse IP address", e);
Ray Milkey269ffb92014-04-03 14:43:30 -070086 }
87 }
88
Ray Milkey5df613b2014-04-15 10:50:56 -070089 private byte[] canonicalizeAddress(byte[] addressValue,
90 int prefixLengthValue) {
91 byte[] result = new byte[addressValue.length];
Ray Milkey269ffb92014-04-03 14:43:30 -070092
Ray Milkey5df613b2014-04-15 10:50:56 -070093 if (prefixLengthValue == 0) {
Jonathan Hart31e15f12014-04-10 10:33:00 -070094 for (int i = 0; i < ADDRESS_LENGTH; i++) {
Ray Milkey269ffb92014-04-03 14:43:30 -070095 result[i] = 0;
96 }
97
98 return result;
99 }
100
Ray Milkey5df613b2014-04-15 10:50:56 -0700101 result = Arrays.copyOf(addressValue, addressValue.length);
Ray Milkey269ffb92014-04-03 14:43:30 -0700102
103 //Set all bytes after the end of the prefix to 0
Ray Milkey5df613b2014-04-15 10:50:56 -0700104 int lastByteIndex = (prefixLengthValue - 1) / Byte.SIZE;
Jonathan Hart31e15f12014-04-10 10:33:00 -0700105 for (int i = lastByteIndex; i < ADDRESS_LENGTH; i++) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700106 result[i] = 0;
107 }
108
Ray Milkey5df613b2014-04-15 10:50:56 -0700109 byte lastByte = addressValue[lastByteIndex];
Ray Milkey269ffb92014-04-03 14:43:30 -0700110 byte mask = 0;
111 byte msb = (byte) 0x80;
Ray Milkey5df613b2014-04-15 10:50:56 -0700112 int lastBit = (prefixLengthValue - 1) % Byte.SIZE;
Ray Milkey269ffb92014-04-03 14:43:30 -0700113 for (int i = 0; i < Byte.SIZE; i++) {
114 if (i <= lastBit) {
115 mask |= (msb >> i);
116 }
117 }
118
119 result[lastByteIndex] = (byte) (lastByte & mask);
120
121 return result;
122 }
123
Jonathan Hart31e15f12014-04-10 10:33:00 -0700124 /**
125 * Gets the length of the prefix of the address.
126 *
127 * @return the prefix length
128 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700129 public int getPrefixLength() {
130 return prefixLength;
131 }
132
Jonathan Hart31e15f12014-04-10 10:33:00 -0700133 /**
134 * Gets the address.
135 *
136 * @return the address as a byte array
137 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 public byte[] getAddress() {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700139 return Arrays.copyOf(address, address.length);
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 }
141
142 @Override
143 public boolean equals(Object other) {
Jonathan Hart738980f2014-04-04 10:11:15 -0700144 if (!(other instanceof Prefix)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 return false;
146 }
147
148 Prefix otherPrefix = (Prefix) other;
149
150 return (Arrays.equals(address, otherPrefix.address)) &&
151 (prefixLength == otherPrefix.prefixLength);
152 }
153
154 @Override
155 public int hashCode() {
156 int hash = 17;
157 hash = 31 * hash + prefixLength;
158 hash = 31 * hash + Arrays.hashCode(address);
159 return hash;
160 }
161
162 @Override
163 public String toString() {
164 return inetAddress.getHostAddress() + "/" + prefixLength;
165 }
166
Jonathan Hart31e15f12014-04-10 10:33:00 -0700167 /**
168 * Print the prefix to a String showing the bits of the address.
169 *
170 * @return the bit-string of the prefix
171 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700172 public String printAsBits() {
Jonathan Hart738980f2014-04-04 10:11:15 -0700173 StringBuilder result = new StringBuilder();
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 for (int i = 0; i < address.length; i++) {
175 byte b = address[i];
176 for (int j = 0; j < Byte.SIZE; j++) {
177 byte mask = (byte) (0x80 >>> j);
Jonathan Hart738980f2014-04-04 10:11:15 -0700178 result.append(((b & mask) == 0) ? "0" : "1");
Ray Milkey269ffb92014-04-03 14:43:30 -0700179 if (i * Byte.SIZE + j == prefixLength - 1) {
Jonathan Hart738980f2014-04-04 10:11:15 -0700180 return result.toString();
Ray Milkey269ffb92014-04-03 14:43:30 -0700181 }
182 }
Jonathan Hart938a0152014-04-07 18:27:31 -0700183 result.append(' ');
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 }
185 return result.substring(0, result.length() - 1);
186 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800187}