Pavlin Radoslavov

Updated the implementation of IpAddress:

 * Added new static methods IpAddress.makeMaskPrefix and
   IpAddress.makeMaskedAddress
 * Cleanup

Also, removed obsoleted Javadoc comments in Ip4Prefix and Ip6Prefix classes
...@@ -101,20 +101,6 @@ public final class Ip4Prefix { ...@@ -101,20 +101,6 @@ public final class Ip4Prefix {
101 return this.address.toString() + "/" + this.prefixLen; 101 return this.address.toString() + "/" + this.prefixLen;
102 } 102 }
103 103
104 - /**
105 - * Compares the value of two Ip4Prefix objects.
106 - * <p/>
107 - * Note the value of the IPv4 address is compared directly between the
108 - * objects, and must match exactly for the objects to be considered equal.
109 - * This may result in objects which represent the same IP prefix being
110 - * classified as unequal, because the unsignificant bits of the address
111 - * field don't match (the bits to the right of the prefix length).
112 - * <p/>
113 - * TODO Change this behavior so that objects that represent the same prefix
114 - * are classified as equal according to this equals method.
115 - *
116 - * @see Object#equals(Object)
117 - */
118 @Override 104 @Override
119 public boolean equals(Object other) { 105 public boolean equals(Object other) {
120 if (other == this) { 106 if (other == this) {
......
...@@ -101,20 +101,6 @@ public final class Ip6Prefix { ...@@ -101,20 +101,6 @@ public final class Ip6Prefix {
101 return this.address.toString() + "/" + this.prefixLen; 101 return this.address.toString() + "/" + this.prefixLen;
102 } 102 }
103 103
104 - /**
105 - * Compares the value of two Ip6Prefix objects.
106 - * <p/>
107 - * Note the value of the IPv6 address is compared directly between the
108 - * objects, and must match exactly for the objects to be considered equal.
109 - * This may result in objects which represent the same IP prefix being
110 - * classified as unequal, because the unsignificant bits of the address
111 - * field don't match (the bits to the right of the prefix length).
112 - * <p/>
113 - * TODO Change this behavior so that objects that represent the same prefix
114 - * are classified as equal according to this equals method.
115 - *
116 - * @see Object#equals(Object)
117 - */
118 @Override 104 @Override
119 public boolean equals(Object other) { 105 public boolean equals(Object other) {
120 if (other == this) { 106 if (other == this) {
......
...@@ -17,6 +17,8 @@ package org.onlab.packet; ...@@ -17,6 +17,8 @@ package org.onlab.packet;
17 17
18 import java.nio.ByteBuffer; 18 import java.nio.ByteBuffer;
19 import java.util.Arrays; 19 import java.util.Arrays;
20 +import java.util.Objects;
21 +import static com.google.common.base.Preconditions.checkNotNull;
20 22
21 /** 23 /**
22 * A class representing an IPv4 address. 24 * A class representing an IPv4 address.
...@@ -37,35 +39,68 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -37,35 +39,68 @@ public final class IpAddress implements Comparable<IpAddress> {
37 /** 39 /**
38 * Constructor for given IP address version and address octets. 40 * Constructor for given IP address version and address octets.
39 * 41 *
40 - * @param ver the IP address version 42 + * @param value the IP address value stored in network byte order
41 - * @param octets the IP address octets 43 + * (i.e., the most significant byte first)
44 + * @param value the IP address value
42 */ 45 */
43 - private IpAddress(Version ver, byte[] octets) { 46 + private IpAddress(Version version, byte[] value) {
44 - this.version = ver; 47 + checkNotNull(value);
45 - this.octets = Arrays.copyOf(octets, INET_BYTE_LENGTH); 48 +
49 + this.version = version;
50 + this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH);
51 + }
52 +
53 + /**
54 + * Converts an integer into an IPv4 address.
55 + *
56 + * @param value an integer representing an IPv4 value
57 + * @return an IP address
58 + */
59 + public static IpAddress valueOf(int value) {
60 + byte[] bytes =
61 + ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array();
62 + return new IpAddress(Version.INET, bytes);
46 } 63 }
47 64
48 /** 65 /**
49 * Converts a byte array into an IP address. 66 * Converts a byte array into an IP address.
50 * 67 *
51 - * @param address the IP address value stored in network byte order 68 + * @param value the IP address value stored in network byte order
52 * (i.e., the most significant byte first) 69 * (i.e., the most significant byte first)
53 * @return an IP address 70 * @return an IP address
54 */ 71 */
55 - public static IpAddress valueOf(byte[] address) { 72 + public static IpAddress valueOf(byte[] value) {
56 - return new IpAddress(Version.INET, address); 73 + return new IpAddress(Version.INET, value);
57 } 74 }
58 75
59 /** 76 /**
60 - * Converts an integer into an IPv4 address. 77 + * Converts a byte array and a given offset from the beginning of the
78 + * array into an IP address.
79 + * <p/>
80 + * The IP address is stored in network byte order (i.e., the most
81 + * significant byte first).
61 * 82 *
62 - * @param address an integer representing an IPv4 value 83 + * @param value the value to use
84 + * @param offset the offset in bytes from the beginning of the byte array
63 * @return an IP address 85 * @return an IP address
64 */ 86 */
65 - public static IpAddress valueOf(int address) { 87 + public static IpAddress valueOf(byte[] value, int offset) {
66 - byte[] bytes = 88 + // Verify the arguments
67 - ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(address).array(); 89 + if ((offset < 0) || (offset + INET_BYTE_LENGTH > value.length)) {
68 - return new IpAddress(Version.INET, bytes); 90 + String msg;
91 + if (value.length < INET_BYTE_LENGTH) {
92 + msg = "Invalid IPv4 address array: array length: " +
93 + value.length + ". Must be at least " + INET_BYTE_LENGTH;
94 + } else {
95 + msg = "Invalid IPv4 address array: array offset: " +
96 + offset + ". Must be in the interval [0, " +
97 + (value.length - INET_BYTE_LENGTH) + "]";
98 + }
99 + throw new IllegalArgumentException(msg);
100 + }
101 +
102 + byte[] bc = Arrays.copyOfRange(value, offset, value.length);
103 + return IpAddress.valueOf(bc);
69 } 104 }
70 105
71 /** 106 /**
...@@ -77,8 +112,9 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -77,8 +112,9 @@ public final class IpAddress implements Comparable<IpAddress> {
77 public static IpAddress valueOf(String address) { 112 public static IpAddress valueOf(String address) {
78 final String[] net = address.split("\\."); 113 final String[] net = address.split("\\.");
79 if (net.length != INET_BYTE_LENGTH) { 114 if (net.length != INET_BYTE_LENGTH) {
80 - throw new IllegalArgumentException("Malformed IP address string; " 115 + String msg = "Malformed IPv4 address string; " +
81 - + "Address must have four decimal values separated by dots (.)"); 116 + "Address must have four decimal values separated by dots (.)";
117 + throw new IllegalArgumentException(msg);
82 } 118 }
83 final byte[] bytes = new byte[INET_BYTE_LENGTH]; 119 final byte[] bytes = new byte[INET_BYTE_LENGTH];
84 for (int i = 0; i < INET_BYTE_LENGTH; i++) { 120 for (int i = 0; i < INET_BYTE_LENGTH; i++) {
...@@ -115,6 +151,48 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -115,6 +151,48 @@ public final class IpAddress implements Comparable<IpAddress> {
115 return bb.getInt(); 151 return bb.getInt();
116 } 152 }
117 153
154 + /**
155 + * Creates an IP network mask prefix.
156 + *
157 + * @param prefixLen the length of the mask prefix. Must be in the interval
158 + * [0, 32] for IPv4
159 + * @return a new IP address that contains a mask prefix of the
160 + * specified length
161 + */
162 + public static IpAddress makeMaskPrefix(int prefixLen) {
163 + // Verify the prefix length
164 + if ((prefixLen < 0) || (prefixLen > INET_BIT_LENGTH)) {
165 + final String msg = "Invalid IPv4 prefix length: " + prefixLen +
166 + ". Must be in the interval [0, 32].";
167 + throw new IllegalArgumentException(msg);
168 + }
169 +
170 + long v = (0xffffffffL << (INET_BIT_LENGTH - prefixLen)) & 0xffffffffL;
171 + return IpAddress.valueOf((int) v);
172 + }
173 +
174 + /**
175 + * Creates an IP address by masking it with a network mask of given
176 + * mask length.
177 + *
178 + * @param addr the address to mask
179 + * @param prefixLen the length of the mask prefix. Must be in the interval
180 + * [0, 32] for IPv4
181 + * @return a new IP address that is masked with a mask prefix of the
182 + * specified length
183 + */
184 + public static IpAddress makeMaskedAddress(final IpAddress addr,
185 + int prefixLen) {
186 + IpAddress mask = IpAddress.makeMaskPrefix(prefixLen);
187 + byte[] net = new byte[INET_BYTE_LENGTH];
188 +
189 + // Mask each byte
190 + for (int i = 0; i < INET_BYTE_LENGTH; i++) {
191 + net[i] = (byte) (addr.octets[i] & mask.octets[i]);
192 + }
193 + return IpAddress.valueOf(net);
194 + }
195 +
118 @Override 196 @Override
119 public int compareTo(IpAddress o) { 197 public int compareTo(IpAddress o) {
120 Long lv = ((long) this.toInt()) & 0xffffffffL; 198 Long lv = ((long) this.toInt()) & 0xffffffffL;
...@@ -124,32 +202,20 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -124,32 +202,20 @@ public final class IpAddress implements Comparable<IpAddress> {
124 202
125 @Override 203 @Override
126 public int hashCode() { 204 public int hashCode() {
127 - final int prime = 31; 205 + return Objects.hash(version, octets);
128 - int result = 1;
129 - result = prime * result + Arrays.hashCode(octets);
130 - result = prime * result + ((version == null) ? 0 : version.hashCode());
131 - return result;
132 } 206 }
133 207
134 @Override 208 @Override
135 public boolean equals(Object obj) { 209 public boolean equals(Object obj) {
136 - if (this == obj) { 210 + if (obj == this) {
137 return true; 211 return true;
138 } 212 }
139 - if (obj == null) { 213 + if ((obj == null) || (getClass() != obj.getClass())) {
140 - return false;
141 - }
142 - if (getClass() != obj.getClass()) {
143 return false; 214 return false;
144 } 215 }
145 IpAddress other = (IpAddress) obj; 216 IpAddress other = (IpAddress) obj;
146 - if (!Arrays.equals(octets, other.octets)) { 217 + return (version == other.version) &&
147 - return false; 218 + Arrays.equals(octets, other.octets);
148 - }
149 - if (version != other.version) {
150 - return false;
151 - }
152 - return true;
153 } 219 }
154 220
155 @Override 221 @Override
......