Reimplementation of classes Ip4Address/Ip6Address/Ip4Prefix/Ip6Prefix
and the corresponding unit tests. * Reimplemented classes Ip4Address and Ip6Address by inheriting from class IpAddress * Reimplemented classes Ip4Prefix and Ip6Prefix by inheriting from class IpPrefix * Reimplemented the unit tests Ip4AddressTest and Ip6AddressTest to match the corresponding IpAddressTest unit tests * Reimplemented the unit tests Ip4PrefixTest and Ip6PrefixTest to match the corresponding IpPrefixTest unit tests * Minor refactoring/cleanup of classes IpAddress and IpPrefix
Showing
12 changed files
with
187 additions
and
192 deletions
This diff is collapsed. Click to expand it.
... | @@ -15,110 +15,90 @@ | ... | @@ -15,110 +15,90 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.packet; | 16 | package org.onlab.packet; |
17 | 17 | ||
18 | -import java.util.Objects; | ||
19 | - | ||
20 | /** | 18 | /** |
21 | * The class representing an IPv4 network address. | 19 | * The class representing an IPv4 network address. |
22 | * This class is immutable. | 20 | * This class is immutable. |
23 | */ | 21 | */ |
24 | -public final class Ip4Prefix { | 22 | +public final class Ip4Prefix extends IpPrefix { |
25 | - private final Ip4Address address; // The IPv4 address | 23 | + public static final IpAddress.Version VERSION = IpAddress.Version.INET; |
26 | - private final short prefixLen; // The prefix length | 24 | + // Maximum network mask length |
25 | + public static final int MAX_MASK_LENGTH = IpPrefix.MAX_INET_MASK_LENGTH; | ||
27 | 26 | ||
28 | /** | 27 | /** |
29 | - * Default constructor. | 28 | + * Constructor for given IPv4 address, and a prefix length. |
30 | - */ | ||
31 | - public Ip4Prefix() { | ||
32 | - this.address = new Ip4Address(); | ||
33 | - this.prefixLen = 0; | ||
34 | - } | ||
35 | - | ||
36 | - /** | ||
37 | - * Copy constructor. | ||
38 | * | 29 | * |
39 | - * @param other the object to copy from | 30 | + * @param address the IPv4 address |
31 | + * @param prefixLength the prefix length | ||
32 | + * @throws IllegalArgumentException if the prefix length value is invalid | ||
40 | */ | 33 | */ |
41 | - public Ip4Prefix(Ip4Prefix other) { | 34 | + private Ip4Prefix(Ip4Address address, int prefixLength) { |
42 | - this.address = new Ip4Address(other.address); | 35 | + super(address, prefixLength); |
43 | - this.prefixLen = other.prefixLen; | ||
44 | } | 36 | } |
45 | 37 | ||
46 | /** | 38 | /** |
47 | - * Constructor for a given address and prefix length. | 39 | + * Returns the IPv4 address value of the prefix. |
48 | * | 40 | * |
49 | - * @param address the address to use | 41 | + * @return the IPv4 address value of the prefix |
50 | - * @param prefixLen the prefix length to use | ||
51 | */ | 42 | */ |
52 | - public Ip4Prefix(Ip4Address address, short prefixLen) { | 43 | + public Ip4Address address() { |
53 | - this.address = Ip4Address.makeMaskedAddress(address, prefixLen); | 44 | + IpAddress a = super.address(); |
54 | - this.prefixLen = prefixLen; | 45 | + return (Ip4Address) a; |
55 | } | 46 | } |
56 | 47 | ||
57 | /** | 48 | /** |
58 | - * Constructs an IPv4 prefix from a string representation of the | 49 | + * Converts an integer and a prefix length into an IPv4 prefix. |
59 | - * prefix. | ||
60 | - *<p> | ||
61 | - * Example: "1.2.0.0/16" | ||
62 | * | 50 | * |
63 | - * @param value the value to use | 51 | + * @param address an integer representing the IPv4 address |
52 | + * @param prefixLength the prefix length | ||
53 | + * @return an IPv4 prefix | ||
54 | + * @throws IllegalArgumentException if the prefix length value is invalid | ||
64 | */ | 55 | */ |
65 | - public Ip4Prefix(String value) { | 56 | + public static Ip4Prefix valueOf(int address, int prefixLength) { |
66 | - String[] splits = value.split("/"); | 57 | + return new Ip4Prefix(Ip4Address.valueOf(address), prefixLength); |
67 | - if (splits.length != 2) { | ||
68 | - throw new IllegalArgumentException("Specified IPv4 prefix must contain an IPv4 " + | ||
69 | - "address and a prefix length separated by '/'"); | ||
70 | - } | ||
71 | - this.prefixLen = Short.decode(splits[1]); | ||
72 | - this.address = Ip4Address.makeMaskedAddress(new Ip4Address(splits[0]), | ||
73 | - this.prefixLen); | ||
74 | } | 58 | } |
75 | 59 | ||
76 | /** | 60 | /** |
77 | - * Gets the address value of the IPv4 prefix. | 61 | + * Converts a byte array and a prefix length into an IPv4 prefix. |
78 | * | 62 | * |
79 | - * @return the address value of the IPv4 prefix | 63 | + * @param address the IPv4 address value stored in network byte order |
64 | + * @param prefixLength the prefix length | ||
65 | + * @return an IPv4 prefix | ||
66 | + * @throws IllegalArgumentException if the prefix length value is invalid | ||
80 | */ | 67 | */ |
81 | - public Ip4Address getAddress() { | 68 | + public static Ip4Prefix valueOf(byte[] address, int prefixLength) { |
82 | - return address; | 69 | + return new Ip4Prefix(Ip4Address.valueOf(address), prefixLength); |
83 | } | 70 | } |
84 | 71 | ||
85 | /** | 72 | /** |
86 | - * Gets the prefix length value of the IPv4 prefix. | 73 | + * Converts an IPv4 address and a prefix length into an IPv4 prefix. |
87 | * | 74 | * |
88 | - * @return the prefix length value of the IPv4 prefix | 75 | + * @param address the IPv4 address |
76 | + * @param prefixLength the prefix length | ||
77 | + * @return an IPv4 prefix | ||
78 | + * @throws IllegalArgumentException if the prefix length value is invalid | ||
89 | */ | 79 | */ |
90 | - public short getPrefixLen() { | 80 | + public static Ip4Prefix valueOf(Ip4Address address, int prefixLength) { |
91 | - return prefixLen; | 81 | + return new Ip4Prefix(address, prefixLength); |
92 | } | 82 | } |
93 | 83 | ||
94 | /** | 84 | /** |
95 | - * Converts the IPv4 prefix value to an "address/prefixLen" string. | 85 | + * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") |
86 | + * into an IPv4 prefix. | ||
96 | * | 87 | * |
97 | - * @return the IPv4 prefix value as an "address/prefixLen" string | 88 | + * @param address an IP prefix in string form (e.g., "10.1.0.0/16") |
89 | + * @return an IPv4 prefix | ||
90 | + * @throws IllegalArgumentException if the arguments are invalid | ||
98 | */ | 91 | */ |
99 | - @Override | 92 | + public static Ip4Prefix valueOf(String address) { |
100 | - public String toString() { | 93 | + final String[] parts = address.split("/"); |
101 | - return this.address.toString() + "/" + this.prefixLen; | 94 | + if (parts.length != 2) { |
102 | - } | 95 | + String msg = "Malformed IPv4 prefix string: " + address + "." + |
103 | - | 96 | + "Address must take form \"x.x.x.x/y\""; |
104 | - @Override | 97 | + throw new IllegalArgumentException(msg); |
105 | - public boolean equals(Object other) { | ||
106 | - if (other == this) { | ||
107 | - return true; | ||
108 | - } | ||
109 | - | ||
110 | - if (!(other instanceof Ip4Prefix)) { | ||
111 | - return false; | ||
112 | } | 98 | } |
99 | + Ip4Address ipAddress = Ip4Address.valueOf(parts[0]); | ||
100 | + int prefixLength = Integer.parseInt(parts[1]); | ||
113 | 101 | ||
114 | - Ip4Prefix otherIp4Prefix = (Ip4Prefix) other; | 102 | + return new Ip4Prefix(ipAddress, prefixLength); |
115 | - | ||
116 | - return Objects.equals(this.address, otherIp4Prefix.address) | ||
117 | - && this.prefixLen == otherIp4Prefix.prefixLen; | ||
118 | - } | ||
119 | - | ||
120 | - @Override | ||
121 | - public int hashCode() { | ||
122 | - return Objects.hash(address, prefixLen); | ||
123 | } | 103 | } |
124 | } | 104 | } | ... | ... |
This diff is collapsed. Click to expand it.
... | @@ -15,110 +15,79 @@ | ... | @@ -15,110 +15,79 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.packet; | 16 | package org.onlab.packet; |
17 | 17 | ||
18 | -import java.util.Objects; | ||
19 | - | ||
20 | /** | 18 | /** |
21 | * The class representing an IPv6 network address. | 19 | * The class representing an IPv6 network address. |
22 | * This class is immutable. | 20 | * This class is immutable. |
23 | */ | 21 | */ |
24 | -public final class Ip6Prefix { | 22 | +public final class Ip6Prefix extends IpPrefix { |
25 | - private final Ip6Address address; // The IPv6 address | 23 | + public static final IpAddress.Version VERSION = IpAddress.Version.INET6; |
26 | - private final short prefixLen; // The prefix length | 24 | + // Maximum network mask length |
27 | - | 25 | + public static final int MAX_MASK_LENGTH = IpPrefix.MAX_INET6_MASK_LENGTH; |
28 | - /** | ||
29 | - * Default constructor. | ||
30 | - */ | ||
31 | - public Ip6Prefix() { | ||
32 | - this.address = new Ip6Address(); | ||
33 | - this.prefixLen = 0; | ||
34 | - } | ||
35 | - | ||
36 | - /** | ||
37 | - * Copy constructor. | ||
38 | - * | ||
39 | - * @param other the object to copy from | ||
40 | - */ | ||
41 | - public Ip6Prefix(Ip6Prefix other) { | ||
42 | - this.address = new Ip6Address(other.address); | ||
43 | - this.prefixLen = other.prefixLen; | ||
44 | - } | ||
45 | 26 | ||
46 | /** | 27 | /** |
47 | - * Constructor for a given address and prefix length. | 28 | + * Constructor for given IPv6 address, and a prefix length. |
48 | * | 29 | * |
49 | - * @param address the address to use | 30 | + * @param address the IPv6 address |
50 | - * @param prefixLen the prefix length to use | 31 | + * @param prefixLength the prefix length |
32 | + * @throws IllegalArgumentException if the prefix length value is invalid | ||
51 | */ | 33 | */ |
52 | - public Ip6Prefix(Ip6Address address, short prefixLen) { | 34 | + private Ip6Prefix(Ip6Address address, int prefixLength) { |
53 | - this.address = Ip6Address.makeMaskedAddress(address, prefixLen); | 35 | + super(address, prefixLength); |
54 | - this.prefixLen = prefixLen; | ||
55 | } | 36 | } |
56 | 37 | ||
57 | /** | 38 | /** |
58 | - * Constructs an IPv6 prefix from a string representation of the | 39 | + * Returns the IPv6 address value of the prefix. |
59 | - * prefix. | ||
60 | - *<p> | ||
61 | - * Example: "1111:2222::/32" | ||
62 | * | 40 | * |
63 | - * @param value the value to use | 41 | + * @return the IPv6 address value of the prefix |
64 | */ | 42 | */ |
65 | - public Ip6Prefix(String value) { | 43 | + public Ip6Address address() { |
66 | - String[] splits = value.split("/"); | 44 | + IpAddress a = super.address(); |
67 | - if (splits.length != 2) { | 45 | + return (Ip6Address) a; |
68 | - throw new IllegalArgumentException("Specified IPv6 prefix must contain an IPv6 " + | ||
69 | - "address and a prefix length separated by '/'"); | ||
70 | - } | ||
71 | - this.prefixLen = Short.decode(splits[1]); | ||
72 | - this.address = Ip6Address.makeMaskedAddress(new Ip6Address(splits[0]), | ||
73 | - this.prefixLen); | ||
74 | } | 46 | } |
75 | 47 | ||
76 | /** | 48 | /** |
77 | - * Gets the address value of the IPv6 prefix. | 49 | + * Converts a byte array and a prefix length into an IPv6 prefix. |
78 | * | 50 | * |
79 | - * @return the address value of the IPv6 prefix | 51 | + * @param address the IPv6 address value stored in network byte order |
52 | + * @param prefixLength the prefix length | ||
53 | + * @return an IPv6 prefix | ||
54 | + * @throws IllegalArgumentException if the prefix length value is invalid | ||
80 | */ | 55 | */ |
81 | - public Ip6Address getAddress() { | 56 | + public static Ip6Prefix valueOf(byte[] address, int prefixLength) { |
82 | - return address; | 57 | + return new Ip6Prefix(Ip6Address.valueOf(address), prefixLength); |
83 | } | 58 | } |
84 | 59 | ||
85 | /** | 60 | /** |
86 | - * Gets the prefix length value of the IPv6 prefix. | 61 | + * Converts an IPv6 address and a prefix length into an IPv6 prefix. |
87 | * | 62 | * |
88 | - * @return the prefix length value of the IPv6 prefix | 63 | + * @param address the IPv6 address |
64 | + * @param prefixLength the prefix length | ||
65 | + * @return an IPv6 prefix | ||
66 | + * @throws IllegalArgumentException if the prefix length value is invalid | ||
89 | */ | 67 | */ |
90 | - public short getPrefixLen() { | 68 | + public static Ip6Prefix valueOf(Ip6Address address, int prefixLength) { |
91 | - return prefixLen; | 69 | + return new Ip6Prefix(address, prefixLength); |
92 | } | 70 | } |
93 | 71 | ||
94 | /** | 72 | /** |
95 | - * Converts the IPv6 prefix value to an "address/prefixLen" string. | 73 | + * Converts a CIDR (slash) notation string (e.g., "1111:2222::/64") |
74 | + * into an IPv6 prefix. | ||
96 | * | 75 | * |
97 | - * @return the IPv6 prefix value as an "address/prefixLen" string | 76 | + * @param address an IP prefix in string form (e.g.,"1111:2222::/64") |
77 | + * @return an IPv6 prefix | ||
78 | + * @throws IllegalArgumentException if the arguments are invalid | ||
98 | */ | 79 | */ |
99 | - @Override | 80 | + public static Ip6Prefix valueOf(String address) { |
100 | - public String toString() { | 81 | + final String[] parts = address.split("/"); |
101 | - return this.address.toString() + "/" + this.prefixLen; | 82 | + if (parts.length != 2) { |
102 | - } | 83 | + String msg = "Malformed IPv6 prefix string: " + address + "." + |
103 | - | 84 | + "Address must take form " + |
104 | - @Override | 85 | + "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\""; |
105 | - public boolean equals(Object other) { | 86 | + throw new IllegalArgumentException(msg); |
106 | - if (other == this) { | ||
107 | - return true; | ||
108 | } | 87 | } |
88 | + Ip6Address ipAddress = Ip6Address.valueOf(parts[0]); | ||
89 | + int prefixLength = Integer.parseInt(parts[1]); | ||
109 | 90 | ||
110 | - if (!(other instanceof Ip6Prefix)) { | 91 | + return new Ip6Prefix(ipAddress, prefixLength); |
111 | - return false; | ||
112 | - } | ||
113 | - | ||
114 | - Ip6Prefix otherIp6Prefix = (Ip6Prefix) other; | ||
115 | - | ||
116 | - return Objects.equals(this.address, otherIp6Prefix.address) | ||
117 | - && this.prefixLen == otherIp6Prefix.prefixLen; | ||
118 | - } | ||
119 | - | ||
120 | - @Override | ||
121 | - public int hashCode() { | ||
122 | - return Objects.hash(address, prefixLen); | ||
123 | } | 92 | } |
124 | } | 93 | } | ... | ... |
... | @@ -30,8 +30,9 @@ import static com.google.common.base.Preconditions.checkState; | ... | @@ -30,8 +30,9 @@ import static com.google.common.base.Preconditions.checkState; |
30 | 30 | ||
31 | /** | 31 | /** |
32 | * A class representing an IP address. | 32 | * A class representing an IP address. |
33 | + * This class is immutable. | ||
33 | */ | 34 | */ |
34 | -public final class IpAddress implements Comparable<IpAddress> { | 35 | +public class IpAddress implements Comparable<IpAddress> { |
35 | // IP Versions | 36 | // IP Versions |
36 | public enum Version { INET, INET6 }; | 37 | public enum Version { INET, INET6 }; |
37 | 38 | ||
... | @@ -52,7 +53,7 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -52,7 +53,7 @@ public final class IpAddress implements Comparable<IpAddress> { |
52 | * (i.e., the most significant byte first) | 53 | * (i.e., the most significant byte first) |
53 | * @throws IllegalArgumentException if the arguments are invalid | 54 | * @throws IllegalArgumentException if the arguments are invalid |
54 | */ | 55 | */ |
55 | - private IpAddress(Version version, byte[] value) { | 56 | + protected IpAddress(Version version, byte[] value) { |
56 | checkArguments(version, value, 0); | 57 | checkArguments(version, value, 0); |
57 | this.version = version; | 58 | this.version = version; |
58 | switch (version) { | 59 | switch (version) { |
... | @@ -88,7 +89,7 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -88,7 +89,7 @@ public final class IpAddress implements Comparable<IpAddress> { |
88 | } | 89 | } |
89 | 90 | ||
90 | /** | 91 | /** |
91 | - * Returns the integral value of this IP address. | 92 | + * Returns the integer value of this IP address. |
92 | * TODO: This method should be moved to Ip4Address. | 93 | * TODO: This method should be moved to Ip4Address. |
93 | * | 94 | * |
94 | * @return the IP address's value as an integer | 95 | * @return the IP address's value as an integer |
... | @@ -219,31 +220,7 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -219,31 +220,7 @@ public final class IpAddress implements Comparable<IpAddress> { |
219 | * @throws IllegalArgumentException if the arguments are invalid | 220 | * @throws IllegalArgumentException if the arguments are invalid |
220 | */ | 221 | */ |
221 | public static IpAddress makeMaskPrefix(Version version, int prefixLength) { | 222 | public static IpAddress makeMaskPrefix(Version version, int prefixLength) { |
222 | - int addrByteLength = byteLength(version); | 223 | + byte[] mask = makeMaskPrefixArray(version, prefixLength); |
223 | - int addrBitLength = addrByteLength * Byte.SIZE; | ||
224 | - | ||
225 | - // Verify the prefix length | ||
226 | - if ((prefixLength < 0) || (prefixLength > addrBitLength)) { | ||
227 | - final String msg = "Invalid IP prefix length: " + prefixLength + | ||
228 | - ". Must be in the interval [0, " + addrBitLength + "]."; | ||
229 | - throw new IllegalArgumentException(msg); | ||
230 | - } | ||
231 | - | ||
232 | - // Number of bytes and extra bits that should be all 1s | ||
233 | - int maskBytes = prefixLength / Byte.SIZE; | ||
234 | - int maskBits = prefixLength % Byte.SIZE; | ||
235 | - byte[] mask = new byte[addrByteLength]; | ||
236 | - | ||
237 | - // Set the bytes and extra bits to 1s | ||
238 | - for (int i = 0; i < maskBytes; i++) { | ||
239 | - mask[i] = (byte) 0xff; // Set mask bytes to 1s | ||
240 | - } | ||
241 | - for (int i = maskBytes; i < addrByteLength; i++) { | ||
242 | - mask[i] = 0; // Set remaining bytes to 0s | ||
243 | - } | ||
244 | - if (maskBits > 0) { | ||
245 | - mask[maskBytes] = (byte) (0xff << (Byte.SIZE - maskBits)); | ||
246 | - } | ||
247 | return new IpAddress(version, mask); | 224 | return new IpAddress(version, mask); |
248 | } | 225 | } |
249 | 226 | ||
... | @@ -251,24 +228,26 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -251,24 +228,26 @@ public final class IpAddress implements Comparable<IpAddress> { |
251 | * Creates an IP address by masking it with a network mask of given | 228 | * Creates an IP address by masking it with a network mask of given |
252 | * mask length. | 229 | * mask length. |
253 | * | 230 | * |
254 | - * @param addr the address to mask | 231 | + * @param address the address to mask |
255 | * @param prefixLength the length of the mask prefix. Must be in the | 232 | * @param prefixLength the length of the mask prefix. Must be in the |
256 | * interval [0, 32] for IPv4, or [0, 128] for IPv6 | 233 | * interval [0, 32] for IPv4, or [0, 128] for IPv6 |
257 | * @return a new IP address that is masked with a mask prefix of the | 234 | * @return a new IP address that is masked with a mask prefix of the |
258 | * specified length | 235 | * specified length |
259 | * @throws IllegalArgumentException if the prefix length is invalid | 236 | * @throws IllegalArgumentException if the prefix length is invalid |
260 | */ | 237 | */ |
261 | - public static IpAddress makeMaskedAddress(final IpAddress addr, | 238 | + public static IpAddress makeMaskedAddress(final IpAddress address, |
262 | int prefixLength) { | 239 | int prefixLength) { |
263 | - IpAddress mask = IpAddress.makeMaskPrefix(addr.version(), | 240 | + // TODO: The code below should go away and replaced with generics |
264 | - prefixLength); | 241 | + if (address instanceof Ip4Address) { |
265 | - byte[] net = new byte[mask.octets.length]; | 242 | + Ip4Address ip4a = (Ip4Address) address; |
266 | - | 243 | + return Ip4Address.makeMaskedAddress(ip4a, prefixLength); |
267 | - // Mask each byte | 244 | + } else if (address instanceof Ip6Address) { |
268 | - for (int i = 0; i < net.length; i++) { | 245 | + Ip6Address ip6a = (Ip6Address) address; |
269 | - net[i] = (byte) (addr.octets[i] & mask.octets[i]); | 246 | + return Ip6Address.makeMaskedAddress(ip6a, prefixLength); |
247 | + } else { | ||
248 | + byte[] net = makeMaskedAddressArray(address, prefixLength); | ||
249 | + return IpAddress.valueOf(address.version(), net); | ||
270 | } | 250 | } |
271 | - return IpAddress.valueOf(addr.version(), net); | ||
272 | } | 251 | } |
273 | 252 | ||
274 | @Override | 253 | @Override |
... | @@ -352,8 +331,7 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -352,8 +331,7 @@ public final class IpAddress implements Comparable<IpAddress> { |
352 | * array with the address | 331 | * array with the address |
353 | * @throws IllegalArgumentException if any of the arguments is invalid | 332 | * @throws IllegalArgumentException if any of the arguments is invalid |
354 | */ | 333 | */ |
355 | - private static void checkArguments(Version version, byte[] value, | 334 | + static void checkArguments(Version version, byte[] value, int offset) { |
356 | - int offset) { | ||
357 | // Check the offset and byte array length | 335 | // Check the offset and byte array length |
358 | int addrByteLength = byteLength(version); | 336 | int addrByteLength = byteLength(version); |
359 | if ((offset < 0) || (offset + addrByteLength > value.length)) { | 337 | if ((offset < 0) || (offset + addrByteLength > value.length)) { |
... | @@ -371,4 +349,67 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -371,4 +349,67 @@ public final class IpAddress implements Comparable<IpAddress> { |
371 | throw new IllegalArgumentException(msg); | 349 | throw new IllegalArgumentException(msg); |
372 | } | 350 | } |
373 | } | 351 | } |
352 | + | ||
353 | + /** | ||
354 | + * Creates a byte array for IP network mask prefix. | ||
355 | + * | ||
356 | + * @param version the IP address version | ||
357 | + * @param prefixLength the length of the mask prefix. Must be in the | ||
358 | + * interval [0, 32] for IPv4, or [0, 128] for IPv6 | ||
359 | + * @return a byte array that contains a mask prefix of the | ||
360 | + * specified length | ||
361 | + * @throws IllegalArgumentException if the arguments are invalid | ||
362 | + */ | ||
363 | + static byte[] makeMaskPrefixArray(Version version, int prefixLength) { | ||
364 | + int addrByteLength = byteLength(version); | ||
365 | + int addrBitLength = addrByteLength * Byte.SIZE; | ||
366 | + | ||
367 | + // Verify the prefix length | ||
368 | + if ((prefixLength < 0) || (prefixLength > addrBitLength)) { | ||
369 | + final String msg = "Invalid IP prefix length: " + prefixLength + | ||
370 | + ". Must be in the interval [0, " + addrBitLength + "]."; | ||
371 | + throw new IllegalArgumentException(msg); | ||
372 | + } | ||
373 | + | ||
374 | + // Number of bytes and extra bits that should be all 1s | ||
375 | + int maskBytes = prefixLength / Byte.SIZE; | ||
376 | + int maskBits = prefixLength % Byte.SIZE; | ||
377 | + byte[] mask = new byte[addrByteLength]; | ||
378 | + | ||
379 | + // Set the bytes and extra bits to 1s | ||
380 | + for (int i = 0; i < maskBytes; i++) { | ||
381 | + mask[i] = (byte) 0xff; // Set mask bytes to 1s | ||
382 | + } | ||
383 | + for (int i = maskBytes; i < addrByteLength; i++) { | ||
384 | + mask[i] = 0; // Set remaining bytes to 0s | ||
385 | + } | ||
386 | + if (maskBits > 0) { | ||
387 | + mask[maskBytes] = (byte) (0xff << (Byte.SIZE - maskBits)); | ||
388 | + } | ||
389 | + return mask; | ||
390 | + } | ||
391 | + | ||
392 | + /** | ||
393 | + * Creates a byte array that represents an IP address masked with | ||
394 | + * a network mask of given mask length. | ||
395 | + * | ||
396 | + * @param addr the address to mask | ||
397 | + * @param prefixLength the length of the mask prefix. Must be in the | ||
398 | + * interval [0, 32] for IPv4, or [0, 128] for IPv6 | ||
399 | + * @return a byte array that represents the IP address masked with | ||
400 | + * a mask prefix of the specified length | ||
401 | + * @throws IllegalArgumentException if the prefix length is invalid | ||
402 | + */ | ||
403 | + static byte[] makeMaskedAddressArray(final IpAddress addr, | ||
404 | + int prefixLength) { | ||
405 | + byte[] mask = IpAddress.makeMaskPrefixArray(addr.version(), | ||
406 | + prefixLength); | ||
407 | + byte[] net = new byte[mask.length]; | ||
408 | + | ||
409 | + // Mask each byte | ||
410 | + for (int i = 0; i < net.length; i++) { | ||
411 | + net[i] = (byte) (addr.octets[i] & mask[i]); | ||
412 | + } | ||
413 | + return net; | ||
414 | + } | ||
374 | } | 415 | } | ... | ... |
... | @@ -20,12 +20,13 @@ import java.util.Objects; | ... | @@ -20,12 +20,13 @@ import java.util.Objects; |
20 | /** | 20 | /** |
21 | * A class representing an IP prefix. A prefix consists of an IP address and | 21 | * A class representing an IP prefix. A prefix consists of an IP address and |
22 | * a subnet mask. | 22 | * a subnet mask. |
23 | + * This class is immutable. | ||
23 | * <p> | 24 | * <p> |
24 | * NOTE: The stored IP address in the result IP prefix is masked to | 25 | * NOTE: The stored IP address in the result IP prefix is masked to |
25 | * contain zeroes in all bits after the prefix length. | 26 | * contain zeroes in all bits after the prefix length. |
26 | * </p> | 27 | * </p> |
27 | */ | 28 | */ |
28 | -public final class IpPrefix { | 29 | +public class IpPrefix { |
29 | // Maximum network mask length | 30 | // Maximum network mask length |
30 | public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH; | 31 | public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH; |
31 | public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH; | 32 | public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH; |
... | @@ -40,7 +41,7 @@ public final class IpPrefix { | ... | @@ -40,7 +41,7 @@ public final class IpPrefix { |
40 | * @param prefixLength the prefix length | 41 | * @param prefixLength the prefix length |
41 | * @throws IllegalArgumentException if the prefix length value is invalid | 42 | * @throws IllegalArgumentException if the prefix length value is invalid |
42 | */ | 43 | */ |
43 | - private IpPrefix(IpAddress address, int prefixLength) { | 44 | + protected IpPrefix(IpAddress address, int prefixLength) { |
44 | checkPrefixLength(address.version(), prefixLength); | 45 | checkPrefixLength(address.version(), prefixLength); |
45 | this.address = IpAddress.makeMaskedAddress(address, prefixLength); | 46 | this.address = IpAddress.makeMaskedAddress(address, prefixLength); |
46 | this.prefixLength = (short) prefixLength; | 47 | this.prefixLength = (short) prefixLength; |
... | @@ -100,7 +101,7 @@ public final class IpPrefix { | ... | @@ -100,7 +101,7 @@ public final class IpPrefix { |
100 | } | 101 | } |
101 | 102 | ||
102 | /** | 103 | /** |
103 | - * Converts an IP address and a prefix length into IP prefix. | 104 | + * Converts an IP address and a prefix length into an IP prefix. |
104 | * | 105 | * |
105 | * @param address the IP address | 106 | * @param address the IP address |
106 | * @param prefixLength the prefix length | 107 | * @param prefixLength the prefix length |
... | @@ -112,10 +113,11 @@ public final class IpPrefix { | ... | @@ -112,10 +113,11 @@ public final class IpPrefix { |
112 | } | 113 | } |
113 | 114 | ||
114 | /** | 115 | /** |
115 | - * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an | 116 | + * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16" or |
116 | - * IP prefix. | 117 | + * "1111:2222::/64") into an IP prefix. |
117 | * | 118 | * |
118 | - * @param address an IP prefix in string form, e.g. "10.1.0.0/16" | 119 | + * @param address an IP prefix in string form (e.g. "10.1.0.0/16" or |
120 | + * "1111:2222::/64") | ||
119 | * @return an IP prefix | 121 | * @return an IP prefix |
120 | * @throws IllegalArgumentException if the arguments are invalid | 122 | * @throws IllegalArgumentException if the arguments are invalid |
121 | */ | 123 | */ |
... | @@ -123,7 +125,8 @@ public final class IpPrefix { | ... | @@ -123,7 +125,8 @@ public final class IpPrefix { |
123 | final String[] parts = address.split("/"); | 125 | final String[] parts = address.split("/"); |
124 | if (parts.length != 2) { | 126 | if (parts.length != 2) { |
125 | String msg = "Malformed IP prefix string: " + address + "." + | 127 | String msg = "Malformed IP prefix string: " + address + "." + |
126 | - "Address must take form \"x.x.x.x/y\""; | 128 | + "Address must take form \"x.x.x.x/y\" or " + |
129 | + "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\""; | ||
127 | throw new IllegalArgumentException(msg); | 130 | throw new IllegalArgumentException(msg); |
128 | } | 131 | } |
129 | IpAddress ipAddress = IpAddress.valueOf(parts[0]); | 132 | IpAddress ipAddress = IpAddress.valueOf(parts[0]); | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
16 | package org.onlab.packet; | 16 | package org.onlab.packet; |
17 | 17 | ||
18 | import com.google.common.testing.EqualsTester; | 18 | import com.google.common.testing.EqualsTester; |
19 | +import org.junit.Ignore; | ||
19 | import org.junit.Test; | 20 | import org.junit.Test; |
20 | 21 | ||
21 | import static org.hamcrest.Matchers.equalTo; | 22 | import static org.hamcrest.Matchers.equalTo; |
... | @@ -32,6 +33,7 @@ public class IpPrefixTest { | ... | @@ -32,6 +33,7 @@ public class IpPrefixTest { |
32 | /** | 33 | /** |
33 | * Tests the immutability of {@link IpPrefix}. | 34 | * Tests the immutability of {@link IpPrefix}. |
34 | */ | 35 | */ |
36 | + @Ignore("The class is not pure immutable, because it is not 'final'") | ||
35 | @Test | 37 | @Test |
36 | public void testImmutable() { | 38 | public void testImmutable() { |
37 | assertThatClassIsImmutable(IpPrefix.class); | 39 | assertThatClassIsImmutable(IpPrefix.class); | ... | ... |
-
Please register or login to post a comment