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
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ip4Address.java b/utils/misc/src/main/java/org/onlab/packet/Ip4Address.java
index 7b7b989..114f126 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ip4Address.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ip4Address.java
@@ -15,203 +15,160 @@
*/
package org.onlab.packet;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.nio.ByteBuffer;
-import static com.google.common.base.Preconditions.checkNotNull;
+import java.util.Arrays;
+
+import com.google.common.net.InetAddresses;
/**
- * The class representing an IPv4 address.
+ * A class representing an IPv4 address.
* This class is immutable.
*/
-public final class Ip4Address implements Comparable<Ip4Address> {
- private final int value;
-
- /** The length of the address in bytes (octets). */
- public static final int BYTE_LENGTH = 4;
-
- /** The length of the address in bits. */
- public static final int BIT_LENGTH = BYTE_LENGTH * Byte.SIZE;
+public final class Ip4Address extends IpAddress {
+ public static final IpAddress.Version VERSION = IpAddress.Version.INET;
+ public static final int BYTE_LENGTH = IpAddress.INET_BYTE_LENGTH;
+ public static final int BIT_LENGTH = IpAddress.INET_BIT_LENGTH;
/**
- * Default constructor.
+ * Constructor for given IP address version and address octets.
+ *
+ * @param value the IP address value stored in network byte order
+ * (i.e., the most significant byte first)
+ * @throws IllegalArgumentException if the arguments are invalid
*/
- public Ip4Address() {
- this.value = 0;
+ private Ip4Address(byte[] value) {
+ super(VERSION, value);
}
/**
- * Copy constructor.
+ * Returns the integer value of this IPv4 address.
*
- * @param other the object to copy from
+ * @return the IPv4 address's value as an integer
*/
- public Ip4Address(Ip4Address other) {
- this.value = other.value;
+ public int toInt() {
+ ByteBuffer bb = ByteBuffer.wrap(super.toOctets());
+ return bb.getInt();
}
/**
- * Constructor from an integer value.
+ * Converts an integer into an IPv4 address.
*
- * @param value the value to use
+ * @param value an integer representing an IPv4 address value
+ * @return an IPv4 address
*/
- public Ip4Address(int value) {
- this.value = value;
+ public static Ip4Address valueOf(int value) {
+ byte[] bytes =
+ ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array();
+ return new Ip4Address(bytes);
}
/**
- * Constructor from a byte array with the IPv4 address stored in network
- * byte order (i.e., the most significant byte first).
+ * Converts a byte array into an IPv4 address.
*
- * @param value the value to use
+ * @param value the IPv4 address value stored in network byte order
+ * (i.e., the most significant byte first)
+ * @return an IPv4 address
+ * @throws IllegalArgumentException if the argument is invalid
*/
- public Ip4Address(byte[] value) {
- this(value, 0);
+ public static Ip4Address valueOf(byte[] value) {
+ return new Ip4Address(value);
}
/**
- * Constructor from a byte array with the IPv4 address stored in network
- * byte order (i.e., the most significant byte first), and a given offset
- * from the beginning of the byte array.
- *
+ * Converts a byte array and a given offset from the beginning of the
+ * array into an IPv4 address.
+ * <p>
+ * The IP address is stored in network byte order (i.e., the most
+ * significant byte first).
+ * </p>
* @param value the value to use
* @param offset the offset in bytes from the beginning of the byte array
+ * @return an IPv4 address
+ * @throws IllegalArgumentException if the arguments are invalid
*/
- public Ip4Address(byte[] value, int offset) {
- checkNotNull(value);
-
- // Verify the arguments
- if ((offset < 0) || (offset + BYTE_LENGTH > value.length)) {
- String msg;
- if (value.length < BYTE_LENGTH) {
- msg = "Invalid IPv4 address array: array length: " +
- value.length + ". Must be at least " + BYTE_LENGTH;
- } else {
- msg = "Invalid IPv4 address array: array offset: " +
- offset + ". Must be in the interval [0, " +
- (value.length - BYTE_LENGTH) + "]";
- }
- throw new IllegalArgumentException(msg);
- }
-
- // Read the address
- ByteBuffer bb = ByteBuffer.wrap(value);
- this.value = bb.getInt(offset);
+ public static Ip4Address valueOf(byte[] value, int offset) {
+ IpAddress.checkArguments(VERSION, value, offset);
+ byte[] bc = Arrays.copyOfRange(value, offset, value.length);
+ return Ip4Address.valueOf(bc);
}
/**
- * Constructs an IPv4 address from a string representation of the address.
- *<p>
- * Example: "1.2.3.4"
+ * Converts an InetAddress into an IPv4 address.
*
- * @param value the value to use
+ * @param inetAddress the InetAddress value to use. It must contain an IPv4
+ * address
+ * @return an IPv4 address
+ * @throws IllegalArgumentException if the argument is invalid
*/
- public Ip4Address(String value) {
- checkNotNull(value);
-
- String[] splits = value.split("\\.");
- if (splits.length != 4) {
- final String msg = "Invalid IPv4 address string: " + value;
+ public static Ip4Address valueOf(InetAddress inetAddress) {
+ byte[] bytes = inetAddress.getAddress();
+ if (inetAddress instanceof Inet4Address) {
+ return new Ip4Address(bytes);
+ }
+ if ((inetAddress instanceof Inet6Address) ||
+ (bytes.length == INET6_BYTE_LENGTH)) {
+ final String msg = "Invalid IPv4 version address string: " +
+ inetAddress.toString();
throw new IllegalArgumentException(msg);
}
-
- int result = 0;
- for (int i = 0; i < BYTE_LENGTH; i++) {
- result |= Integer.parseInt(splits[i]) <<
- ((BYTE_LENGTH - (i + 1)) * Byte.SIZE);
+ // Use the number of bytes as a hint
+ if (bytes.length == INET_BYTE_LENGTH) {
+ return new Ip4Address(bytes);
}
- this.value = result;
+ final String msg = "Unrecognized IP version address string: " +
+ inetAddress.toString();
+ throw new IllegalArgumentException(msg);
}
/**
- * Gets the IPv4 address as a byte array.
+ * Converts an IPv4 string literal (e.g., "10.2.3.4") into an IP address.
*
- * @return a byte array with the IPv4 address stored in network byte order
- * (i.e., the most significant byte first).
+ * @param value an IPv4 address value in string form
+ * @return an IPv4 address
+ * @throws IllegalArgumentException if the argument is invalid
*/
- public byte[] toOctets() {
- return ByteBuffer.allocate(BYTE_LENGTH).putInt(value).array();
+ public static Ip4Address valueOf(String value) {
+ InetAddress inetAddress = null;
+ try {
+ inetAddress = InetAddresses.forString(value);
+ } catch (IllegalArgumentException e) {
+ final String msg = "Invalid IP address string: " + value;
+ throw new IllegalArgumentException(msg);
+ }
+ return valueOf(inetAddress);
}
/**
* Creates an IPv4 network mask prefix.
*
- * @param prefixLen the length of the mask prefix. Must be in the interval
- * [0, 32].
+ * @param prefixLength the length of the mask prefix. Must be in the
+ * interval [0, 32]
* @return a new IPv4 address that contains a mask prefix of the
* specified length
+ * @throws IllegalArgumentException if the argument is invalid
*/
- public static Ip4Address makeMaskPrefix(int prefixLen) {
- // Verify the prefix length
- if ((prefixLen < 0) || (prefixLen > Ip4Address.BIT_LENGTH)) {
- final String msg = "Invalid IPv4 prefix length: " + prefixLen +
- ". Must be in the interval [0, 32].";
- throw new IllegalArgumentException(msg);
- }
-
- long v =
- (0xffffffffL << (Ip4Address.BIT_LENGTH - prefixLen)) & 0xffffffffL;
- return new Ip4Address((int) v);
+ public static Ip4Address makeMaskPrefix(int prefixLength) {
+ byte[] mask = IpAddress.makeMaskPrefixArray(VERSION, prefixLength);
+ return new Ip4Address(mask);
}
/**
* Creates an IPv4 address by masking it with a network mask of given
* mask length.
*
- * @param addr the address to mask
- * @param prefixLen the length of the mask prefix. Must be in the interval
- * [0, 32].
+ * @param address the address to mask
+ * @param prefixLength the length of the mask prefix. Must be in the
+ * interval [0, 32]
* @return a new IPv4 address that is masked with a mask prefix of the
* specified length
+ * @throws IllegalArgumentException if the prefix length is invalid
*/
- public static Ip4Address makeMaskedAddress(final Ip4Address addr,
- int prefixLen) {
- Ip4Address mask = Ip4Address.makeMaskPrefix(prefixLen);
- long v = addr.value & mask.value;
-
- return new Ip4Address((int) v);
- }
-
- /**
- * Gets the value of the IPv4 address.
- *
- * @return the value of the IPv4 address
- */
- public int getValue() {
- return value;
- }
-
- /**
- * Converts the IPv4 value to a '.' separated string.
- *
- * @return the IPv4 value as a '.' separated string
- */
- @Override
- public String toString() {
- return ((this.value >> 24) & 0xff) + "." +
- ((this.value >> 16) & 0xff) + "." +
- ((this.value >> 8) & 0xff) + "." +
- (this.value & 0xff);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Ip4Address)) {
- return false;
- }
- Ip4Address other = (Ip4Address) o;
- if (this.value != other.value) {
- return false;
- }
- return true;
- }
-
- @Override
- public int hashCode() {
- return this.value;
- }
-
- @Override
- public int compareTo(Ip4Address o) {
- Long lv = ((long) this.value) & 0xffffffffL;
- Long rv = ((long) o.value) & 0xffffffffL;
- return lv.compareTo(rv);
+ public static Ip4Address makeMaskedAddress(final Ip4Address address,
+ int prefixLength) {
+ byte[] net = makeMaskedAddressArray(address, prefixLength);
+ return Ip4Address.valueOf(net);
}
}
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java b/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java
index e3b5246..ca9fc61 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java
@@ -15,110 +15,90 @@
*/
package org.onlab.packet;
-import java.util.Objects;
-
/**
* The class representing an IPv4 network address.
* This class is immutable.
*/
-public final class Ip4Prefix {
- private final Ip4Address address; // The IPv4 address
- private final short prefixLen; // The prefix length
+public final class Ip4Prefix extends IpPrefix {
+ public static final IpAddress.Version VERSION = IpAddress.Version.INET;
+ // Maximum network mask length
+ public static final int MAX_MASK_LENGTH = IpPrefix.MAX_INET_MASK_LENGTH;
/**
- * Default constructor.
+ * Constructor for given IPv4 address, and a prefix length.
+ *
+ * @param address the IPv4 address
+ * @param prefixLength the prefix length
+ * @throws IllegalArgumentException if the prefix length value is invalid
*/
- public Ip4Prefix() {
- this.address = new Ip4Address();
- this.prefixLen = 0;
+ private Ip4Prefix(Ip4Address address, int prefixLength) {
+ super(address, prefixLength);
}
/**
- * Copy constructor.
+ * Returns the IPv4 address value of the prefix.
*
- * @param other the object to copy from
+ * @return the IPv4 address value of the prefix
*/
- public Ip4Prefix(Ip4Prefix other) {
- this.address = new Ip4Address(other.address);
- this.prefixLen = other.prefixLen;
+ public Ip4Address address() {
+ IpAddress a = super.address();
+ return (Ip4Address) a;
}
/**
- * Constructor for a given address and prefix length.
+ * Converts an integer and a prefix length into an IPv4 prefix.
*
- * @param address the address to use
- * @param prefixLen the prefix length to use
+ * @param address an integer representing the IPv4 address
+ * @param prefixLength the prefix length
+ * @return an IPv4 prefix
+ * @throws IllegalArgumentException if the prefix length value is invalid
*/
- public Ip4Prefix(Ip4Address address, short prefixLen) {
- this.address = Ip4Address.makeMaskedAddress(address, prefixLen);
- this.prefixLen = prefixLen;
+ public static Ip4Prefix valueOf(int address, int prefixLength) {
+ return new Ip4Prefix(Ip4Address.valueOf(address), prefixLength);
}
/**
- * Constructs an IPv4 prefix from a string representation of the
- * prefix.
- *<p>
- * Example: "1.2.0.0/16"
+ * Converts a byte array and a prefix length into an IPv4 prefix.
*
- * @param value the value to use
+ * @param address the IPv4 address value stored in network byte order
+ * @param prefixLength the prefix length
+ * @return an IPv4 prefix
+ * @throws IllegalArgumentException if the prefix length value is invalid
*/
- public Ip4Prefix(String value) {
- String[] splits = value.split("/");
- if (splits.length != 2) {
- throw new IllegalArgumentException("Specified IPv4 prefix must contain an IPv4 " +
- "address and a prefix length separated by '/'");
+ public static Ip4Prefix valueOf(byte[] address, int prefixLength) {
+ return new Ip4Prefix(Ip4Address.valueOf(address), prefixLength);
+ }
+
+ /**
+ * Converts an IPv4 address and a prefix length into an IPv4 prefix.
+ *
+ * @param address the IPv4 address
+ * @param prefixLength the prefix length
+ * @return an IPv4 prefix
+ * @throws IllegalArgumentException if the prefix length value is invalid
+ */
+ public static Ip4Prefix valueOf(Ip4Address address, int prefixLength) {
+ return new Ip4Prefix(address, prefixLength);
+ }
+
+ /**
+ * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16")
+ * into an IPv4 prefix.
+ *
+ * @param address an IP prefix in string form (e.g., "10.1.0.0/16")
+ * @return an IPv4 prefix
+ * @throws IllegalArgumentException if the arguments are invalid
+ */
+ public static Ip4Prefix valueOf(String address) {
+ final String[] parts = address.split("/");
+ if (parts.length != 2) {
+ String msg = "Malformed IPv4 prefix string: " + address + "." +
+ "Address must take form \"x.x.x.x/y\"";
+ throw new IllegalArgumentException(msg);
}
- this.prefixLen = Short.decode(splits[1]);
- this.address = Ip4Address.makeMaskedAddress(new Ip4Address(splits[0]),
- this.prefixLen);
- }
+ Ip4Address ipAddress = Ip4Address.valueOf(parts[0]);
+ int prefixLength = Integer.parseInt(parts[1]);
- /**
- * Gets the address value of the IPv4 prefix.
- *
- * @return the address value of the IPv4 prefix
- */
- public Ip4Address getAddress() {
- return address;
- }
-
- /**
- * Gets the prefix length value of the IPv4 prefix.
- *
- * @return the prefix length value of the IPv4 prefix
- */
- public short getPrefixLen() {
- return prefixLen;
- }
-
- /**
- * Converts the IPv4 prefix value to an "address/prefixLen" string.
- *
- * @return the IPv4 prefix value as an "address/prefixLen" string
- */
- @Override
- public String toString() {
- return this.address.toString() + "/" + this.prefixLen;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (!(other instanceof Ip4Prefix)) {
- return false;
- }
-
- Ip4Prefix otherIp4Prefix = (Ip4Prefix) other;
-
- return Objects.equals(this.address, otherIp4Prefix.address)
- && this.prefixLen == otherIp4Prefix.prefixLen;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(address, prefixLen);
+ return new Ip4Prefix(ipAddress, prefixLength);
}
}
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java b/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java
index 8ad9112..d353422 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java
@@ -16,260 +16,137 @@
package org.onlab.packet;
import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.Objects;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.util.Arrays;
import com.google.common.net.InetAddresses;
-import com.google.common.primitives.UnsignedLongs;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
/**
- * The class representing an IPv6 address.
+ * A class representing an IPv6 address.
* This class is immutable.
*/
-public final class Ip6Address implements Comparable<Ip6Address> {
- private final long valueHigh; // The higher (more significant) 64 bits
- private final long valueLow; // The lower (less significant) 64 bits
-
- /** The length of the address in bytes (octets). */
- public static final int BYTE_LENGTH = 16;
-
- /** The length of the address in bits. */
- public static final int BIT_LENGTH = BYTE_LENGTH * Byte.SIZE;
+public final class Ip6Address extends IpAddress {
+ public static final IpAddress.Version VERSION = IpAddress.Version.INET6;
+ public static final int BYTE_LENGTH = IpAddress.INET6_BYTE_LENGTH;
+ public static final int BIT_LENGTH = IpAddress.INET6_BIT_LENGTH;
/**
- * Default constructor.
+ * Constructor for given IP address version and address octets.
+ *
+ * @param value the IP address value stored in network byte order
+ * (i.e., the most significant byte first)
+ * @throws IllegalArgumentException if the arguments are invalid
*/
- public Ip6Address() {
- this.valueHigh = 0;
- this.valueLow = 0;
+ private Ip6Address(byte[] value) {
+ super(VERSION, value);
}
/**
- * Copy constructor.
+ * Converts a byte array into an IPv6 address.
*
- * @param other the object to copy from
+ * @param value the IPv6 address value stored in network byte order
+ * (i.e., the most significant byte first)
+ * @return an IPv6 address
+ * @throws IllegalArgumentException if the argument is invalid
*/
- public Ip6Address(Ip6Address other) {
- this.valueHigh = other.valueHigh;
- this.valueLow = other.valueLow;
+ public static Ip6Address valueOf(byte[] value) {
+ return new Ip6Address(value);
}
/**
- * Constructor from integer values.
- *
- * @param valueHigh the higher (more significant) 64 bits of the address
- * @param valueLow the lower (less significant) 64 bits of the address
- */
- public Ip6Address(long valueHigh, long valueLow) {
- this.valueHigh = valueHigh;
- this.valueLow = valueLow;
- }
-
- /**
- * Constructor from a byte array with the IPv6 address stored in network
- * byte order (i.e., the most significant byte first).
- *
- * @param value the value to use
- */
- public Ip6Address(byte[] value) {
- this(value, 0);
- }
-
- /**
- * Constructor from a byte array with the IPv6 address stored in network
- * byte order (i.e., the most significant byte first), and a given offset
- * from the beginning of the byte array.
- *
+ * Converts a byte array and a given offset from the beginning of the
+ * array into an IPv6 address.
+ * <p>
+ * The IP address is stored in network byte order (i.e., the most
+ * significant byte first).
+ * </p>
* @param value the value to use
* @param offset the offset in bytes from the beginning of the byte array
+ * @return an IPv6 address
+ * @throws IllegalArgumentException if the arguments are invalid
*/
- public Ip6Address(byte[] value, int offset) {
- checkNotNull(value);
-
- // Verify the arguments
- if ((offset < 0) || (offset + BYTE_LENGTH > value.length)) {
- String msg;
- if (value.length < BYTE_LENGTH) {
- msg = "Invalid IPv6 address array: array length: " +
- value.length + ". Must be at least " + BYTE_LENGTH;
- } else {
- msg = "Invalid IPv6 address array: array offset: " +
- offset + ". Must be in the interval [0, " +
- (value.length - BYTE_LENGTH) + "]";
- }
- throw new IllegalArgumentException(msg);
- }
-
- // Read the address
- ByteBuffer bb = ByteBuffer.wrap(value);
- bb.position(offset);
- this.valueHigh = bb.getLong();
- this.valueLow = bb.getLong();
+ public static Ip6Address valueOf(byte[] value, int offset) {
+ IpAddress.checkArguments(VERSION, value, offset);
+ byte[] bc = Arrays.copyOfRange(value, offset, value.length);
+ return Ip6Address.valueOf(bc);
}
/**
- * Constructs an IPv6 address from a string representation of the address.
- *<p>
- * Example: "1111:2222::8888"
+ * Converts an InetAddress into an IPv6 address.
*
- * @param value the value to use
+ * @param inetAddress the InetAddress value to use. It must contain an IPv6
+ * address
+ * @return an IPv6 address
+ * @throws IllegalArgumentException if the argument is invalid
*/
- public Ip6Address(String value) {
- checkNotNull(value);
-
- if (value.isEmpty()) {
- final String msg = "Specified IPv6 cannot be an empty string";
+ public static Ip6Address valueOf(InetAddress inetAddress) {
+ byte[] bytes = inetAddress.getAddress();
+ if (inetAddress instanceof Inet6Address) {
+ return new Ip6Address(bytes);
+ }
+ if ((inetAddress instanceof Inet4Address) ||
+ (bytes.length == INET_BYTE_LENGTH)) {
+ final String msg = "Invalid IPv6 version address string: " +
+ inetAddress.toString();
throw new IllegalArgumentException(msg);
}
- InetAddress addr = null;
+ // Use the number of bytes as a hint
+ if (bytes.length == INET6_BYTE_LENGTH) {
+ return new Ip6Address(bytes);
+ }
+ final String msg = "Unrecognized IP version address string: " +
+ inetAddress.toString();
+ throw new IllegalArgumentException(msg);
+ }
+
+ /**
+ * Converts an IPv6 string literal (e.g., "1111:2222::8888") into an IP
+ * address.
+ *
+ * @param value an IPv6 address value in string form
+ * @return an IPv6 address
+ * @throws IllegalArgumentException if the argument is invalid
+ */
+ public static Ip6Address valueOf(String value) {
+ InetAddress inetAddress = null;
try {
- addr = InetAddresses.forString(value);
+ inetAddress = InetAddresses.forString(value);
} catch (IllegalArgumentException e) {
- final String msg = "Invalid IPv6 address string: " + value;
+ final String msg = "Invalid IP address string: " + value;
throw new IllegalArgumentException(msg);
}
- byte[] bytes = addr.getAddress();
- ByteBuffer bb = ByteBuffer.wrap(bytes);
- this.valueHigh = bb.getLong();
- this.valueLow = bb.getLong();
- }
-
- /**
- * Gets the IPv6 address as a byte array.
- *
- * @return a byte array with the IPv6 address stored in network byte order
- * (i.e., the most significant byte first).
- */
- public byte[] toOctets() {
- return ByteBuffer.allocate(BYTE_LENGTH)
- .putLong(valueHigh).putLong(valueLow).array();
+ return valueOf(inetAddress);
}
/**
* Creates an IPv6 network mask prefix.
*
- * @param prefixLen the length of the mask prefix. Must be in the interval
- * [0, 128].
+ * @param prefixLength the length of the mask prefix. Must be in the
+ * interval [0, 128]
* @return a new IPv6 address that contains a mask prefix of the
* specified length
+ * @throws IllegalArgumentException if the arguments are invalid
*/
- public static Ip6Address makeMaskPrefix(int prefixLen) {
- long vh, vl;
-
- // Verify the prefix length
- if ((prefixLen < 0) || (prefixLen > Ip6Address.BIT_LENGTH)) {
- final String msg = "Invalid IPv6 prefix length: " + prefixLen +
- ". Must be in the interval [0, 128].";
- throw new IllegalArgumentException(msg);
- }
-
- if (prefixLen == 0) {
- //
- // NOTE: Apparently, the result of "<< 64" shifting to the left
- // results in all 1s instead of all 0s, hence we handle it as
- // a special case.
- //
- vh = 0;
- vl = 0;
- } else if (prefixLen <= 64) {
- vh = (0xffffffffffffffffL << (64 - prefixLen)) & 0xffffffffffffffffL;
- vl = 0;
- } else {
- vh = -1L; // All 1s
- vl = (0xffffffffffffffffL << (128 - prefixLen)) & 0xffffffffffffffffL;
- }
- return new Ip6Address(vh, vl);
+ public static Ip6Address makeMaskPrefix(int prefixLength) {
+ byte[] mask = IpAddress.makeMaskPrefixArray(VERSION, prefixLength);
+ return new Ip6Address(mask);
}
/**
* Creates an IPv6 address by masking it with a network mask of given
* mask length.
*
- * @param addr the address to mask
- * @param prefixLen the length of the mask prefix. Must be in the interval
- * [0, 128].
+ * @param address the address to mask
+ * @param prefixLength the length of the mask prefix. Must be in the
+ * interval [0, 128]
* @return a new IPv6 address that is masked with a mask prefix of the
* specified length
+ * @throws IllegalArgumentException if the prefix length is invalid
*/
- public static Ip6Address makeMaskedAddress(final Ip6Address addr,
- int prefixLen) {
- Ip6Address mask = Ip6Address.makeMaskPrefix(prefixLen);
- long vh = addr.valueHigh & mask.valueHigh;
- long vl = addr.valueLow & mask.valueLow;
-
- return new Ip6Address(vh, vl);
- }
-
- /**
- * Gets the value of the higher (more significant) 64 bits of the address.
- *
- * @return the value of the higher (more significant) 64 bits of the
- * address
- */
- public long getValueHigh() {
- return valueHigh;
- }
-
- /**
- * Gets the value of the lower (less significant) 64 bits of the address.
- *
- * @return the value of the lower (less significant) 64 bits of the
- * address
- */
- public long getValueLow() {
- return valueLow;
- }
-
- /**
- * Converts the IPv6 value to a ':' separated string.
- *
- * @return the IPv6 value as a ':' separated string
- */
- @Override
- public String toString() {
- ByteBuffer bb = ByteBuffer.allocate(Ip6Address.BYTE_LENGTH);
- bb.putLong(valueHigh);
- bb.putLong(valueLow);
- InetAddress inetAddr = null;
- try {
- inetAddr = InetAddress.getByAddress(bb.array());
- } catch (UnknownHostException e) {
- // Should never happen
- checkState(false, "Internal error: Ip6Address.toString()");
- return "::";
- }
- return InetAddresses.toAddrString(inetAddr);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Ip6Address)) {
- return false;
- }
- Ip6Address other = (Ip6Address) o;
- return this.valueHigh == other.valueHigh
- && this.valueLow == other.valueLow;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(valueHigh, valueLow);
- }
-
- @Override
- public int compareTo(Ip6Address o) {
- // Compare the high-order 64-bit value
- if (this.valueHigh != o.valueHigh) {
- return UnsignedLongs.compare(this.valueHigh, o.valueHigh);
- }
- // Compare the low-order 64-bit value
- if (this.valueLow != o.valueLow) {
- return UnsignedLongs.compare(this.valueLow, o.valueLow);
- }
- return 0;
+ public static Ip6Address makeMaskedAddress(final Ip6Address address,
+ int prefixLength) {
+ byte[] net = makeMaskedAddressArray(address, prefixLength);
+ return Ip6Address.valueOf(net);
}
}
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java b/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java
index 5422ae1..ca9985e 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java
@@ -15,110 +15,79 @@
*/
package org.onlab.packet;
-import java.util.Objects;
-
/**
* The class representing an IPv6 network address.
* This class is immutable.
*/
-public final class Ip6Prefix {
- private final Ip6Address address; // The IPv6 address
- private final short prefixLen; // The prefix length
+public final class Ip6Prefix extends IpPrefix {
+ public static final IpAddress.Version VERSION = IpAddress.Version.INET6;
+ // Maximum network mask length
+ public static final int MAX_MASK_LENGTH = IpPrefix.MAX_INET6_MASK_LENGTH;
/**
- * Default constructor.
+ * Constructor for given IPv6 address, and a prefix length.
+ *
+ * @param address the IPv6 address
+ * @param prefixLength the prefix length
+ * @throws IllegalArgumentException if the prefix length value is invalid
*/
- public Ip6Prefix() {
- this.address = new Ip6Address();
- this.prefixLen = 0;
+ private Ip6Prefix(Ip6Address address, int prefixLength) {
+ super(address, prefixLength);
}
/**
- * Copy constructor.
+ * Returns the IPv6 address value of the prefix.
*
- * @param other the object to copy from
+ * @return the IPv6 address value of the prefix
*/
- public Ip6Prefix(Ip6Prefix other) {
- this.address = new Ip6Address(other.address);
- this.prefixLen = other.prefixLen;
+ public Ip6Address address() {
+ IpAddress a = super.address();
+ return (Ip6Address) a;
}
/**
- * Constructor for a given address and prefix length.
+ * Converts a byte array and a prefix length into an IPv6 prefix.
*
- * @param address the address to use
- * @param prefixLen the prefix length to use
+ * @param address the IPv6 address value stored in network byte order
+ * @param prefixLength the prefix length
+ * @return an IPv6 prefix
+ * @throws IllegalArgumentException if the prefix length value is invalid
*/
- public Ip6Prefix(Ip6Address address, short prefixLen) {
- this.address = Ip6Address.makeMaskedAddress(address, prefixLen);
- this.prefixLen = prefixLen;
+ public static Ip6Prefix valueOf(byte[] address, int prefixLength) {
+ return new Ip6Prefix(Ip6Address.valueOf(address), prefixLength);
}
/**
- * Constructs an IPv6 prefix from a string representation of the
- * prefix.
- *<p>
- * Example: "1111:2222::/32"
+ * Converts an IPv6 address and a prefix length into an IPv6 prefix.
*
- * @param value the value to use
+ * @param address the IPv6 address
+ * @param prefixLength the prefix length
+ * @return an IPv6 prefix
+ * @throws IllegalArgumentException if the prefix length value is invalid
*/
- public Ip6Prefix(String value) {
- String[] splits = value.split("/");
- if (splits.length != 2) {
- throw new IllegalArgumentException("Specified IPv6 prefix must contain an IPv6 " +
- "address and a prefix length separated by '/'");
+ public static Ip6Prefix valueOf(Ip6Address address, int prefixLength) {
+ return new Ip6Prefix(address, prefixLength);
+ }
+
+ /**
+ * Converts a CIDR (slash) notation string (e.g., "1111:2222::/64")
+ * into an IPv6 prefix.
+ *
+ * @param address an IP prefix in string form (e.g.,"1111:2222::/64")
+ * @return an IPv6 prefix
+ * @throws IllegalArgumentException if the arguments are invalid
+ */
+ public static Ip6Prefix valueOf(String address) {
+ final String[] parts = address.split("/");
+ if (parts.length != 2) {
+ String msg = "Malformed IPv6 prefix string: " + address + "." +
+ "Address must take form " +
+ "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\"";
+ throw new IllegalArgumentException(msg);
}
- this.prefixLen = Short.decode(splits[1]);
- this.address = Ip6Address.makeMaskedAddress(new Ip6Address(splits[0]),
- this.prefixLen);
- }
+ Ip6Address ipAddress = Ip6Address.valueOf(parts[0]);
+ int prefixLength = Integer.parseInt(parts[1]);
- /**
- * Gets the address value of the IPv6 prefix.
- *
- * @return the address value of the IPv6 prefix
- */
- public Ip6Address getAddress() {
- return address;
- }
-
- /**
- * Gets the prefix length value of the IPv6 prefix.
- *
- * @return the prefix length value of the IPv6 prefix
- */
- public short getPrefixLen() {
- return prefixLen;
- }
-
- /**
- * Converts the IPv6 prefix value to an "address/prefixLen" string.
- *
- * @return the IPv6 prefix value as an "address/prefixLen" string
- */
- @Override
- public String toString() {
- return this.address.toString() + "/" + this.prefixLen;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (!(other instanceof Ip6Prefix)) {
- return false;
- }
-
- Ip6Prefix otherIp6Prefix = (Ip6Prefix) other;
-
- return Objects.equals(this.address, otherIp6Prefix.address)
- && this.prefixLen == otherIp6Prefix.prefixLen;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(address, prefixLen);
+ return new Ip6Prefix(ipAddress, prefixLength);
}
}
diff --git a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
index f685e79..45c0207 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
@@ -30,8 +30,9 @@
/**
* A class representing an IP address.
+ * This class is immutable.
*/
-public final class IpAddress implements Comparable<IpAddress> {
+public class IpAddress implements Comparable<IpAddress> {
// IP Versions
public enum Version { INET, INET6 };
@@ -52,7 +53,7 @@
* (i.e., the most significant byte first)
* @throws IllegalArgumentException if the arguments are invalid
*/
- private IpAddress(Version version, byte[] value) {
+ protected IpAddress(Version version, byte[] value) {
checkArguments(version, value, 0);
this.version = version;
switch (version) {
@@ -88,7 +89,7 @@
}
/**
- * Returns the integral value of this IP address.
+ * Returns the integer value of this IP address.
* TODO: This method should be moved to Ip4Address.
*
* @return the IP address's value as an integer
@@ -219,31 +220,7 @@
* @throws IllegalArgumentException if the arguments are invalid
*/
public static IpAddress makeMaskPrefix(Version version, int prefixLength) {
- int addrByteLength = byteLength(version);
- int addrBitLength = addrByteLength * Byte.SIZE;
-
- // Verify the prefix length
- if ((prefixLength < 0) || (prefixLength > addrBitLength)) {
- final String msg = "Invalid IP prefix length: " + prefixLength +
- ". Must be in the interval [0, " + addrBitLength + "].";
- throw new IllegalArgumentException(msg);
- }
-
- // Number of bytes and extra bits that should be all 1s
- int maskBytes = prefixLength / Byte.SIZE;
- int maskBits = prefixLength % Byte.SIZE;
- byte[] mask = new byte[addrByteLength];
-
- // Set the bytes and extra bits to 1s
- for (int i = 0; i < maskBytes; i++) {
- mask[i] = (byte) 0xff; // Set mask bytes to 1s
- }
- for (int i = maskBytes; i < addrByteLength; i++) {
- mask[i] = 0; // Set remaining bytes to 0s
- }
- if (maskBits > 0) {
- mask[maskBytes] = (byte) (0xff << (Byte.SIZE - maskBits));
- }
+ byte[] mask = makeMaskPrefixArray(version, prefixLength);
return new IpAddress(version, mask);
}
@@ -251,24 +228,26 @@
* Creates an IP address by masking it with a network mask of given
* mask length.
*
- * @param addr the address to mask
+ * @param address the address to mask
* @param prefixLength the length of the mask prefix. Must be in the
* interval [0, 32] for IPv4, or [0, 128] for IPv6
* @return a new IP address that is masked with a mask prefix of the
* specified length
* @throws IllegalArgumentException if the prefix length is invalid
*/
- public static IpAddress makeMaskedAddress(final IpAddress addr,
+ public static IpAddress makeMaskedAddress(final IpAddress address,
int prefixLength) {
- IpAddress mask = IpAddress.makeMaskPrefix(addr.version(),
- prefixLength);
- byte[] net = new byte[mask.octets.length];
-
- // Mask each byte
- for (int i = 0; i < net.length; i++) {
- net[i] = (byte) (addr.octets[i] & mask.octets[i]);
+ // TODO: The code below should go away and replaced with generics
+ if (address instanceof Ip4Address) {
+ Ip4Address ip4a = (Ip4Address) address;
+ return Ip4Address.makeMaskedAddress(ip4a, prefixLength);
+ } else if (address instanceof Ip6Address) {
+ Ip6Address ip6a = (Ip6Address) address;
+ return Ip6Address.makeMaskedAddress(ip6a, prefixLength);
+ } else {
+ byte[] net = makeMaskedAddressArray(address, prefixLength);
+ return IpAddress.valueOf(address.version(), net);
}
- return IpAddress.valueOf(addr.version(), net);
}
@Override
@@ -352,8 +331,7 @@
* array with the address
* @throws IllegalArgumentException if any of the arguments is invalid
*/
- private static void checkArguments(Version version, byte[] value,
- int offset) {
+ static void checkArguments(Version version, byte[] value, int offset) {
// Check the offset and byte array length
int addrByteLength = byteLength(version);
if ((offset < 0) || (offset + addrByteLength > value.length)) {
@@ -371,4 +349,67 @@
throw new IllegalArgumentException(msg);
}
}
+
+ /**
+ * Creates a byte array for IP network mask prefix.
+ *
+ * @param version the IP address version
+ * @param prefixLength the length of the mask prefix. Must be in the
+ * interval [0, 32] for IPv4, or [0, 128] for IPv6
+ * @return a byte array that contains a mask prefix of the
+ * specified length
+ * @throws IllegalArgumentException if the arguments are invalid
+ */
+ static byte[] makeMaskPrefixArray(Version version, int prefixLength) {
+ int addrByteLength = byteLength(version);
+ int addrBitLength = addrByteLength * Byte.SIZE;
+
+ // Verify the prefix length
+ if ((prefixLength < 0) || (prefixLength > addrBitLength)) {
+ final String msg = "Invalid IP prefix length: " + prefixLength +
+ ". Must be in the interval [0, " + addrBitLength + "].";
+ throw new IllegalArgumentException(msg);
+ }
+
+ // Number of bytes and extra bits that should be all 1s
+ int maskBytes = prefixLength / Byte.SIZE;
+ int maskBits = prefixLength % Byte.SIZE;
+ byte[] mask = new byte[addrByteLength];
+
+ // Set the bytes and extra bits to 1s
+ for (int i = 0; i < maskBytes; i++) {
+ mask[i] = (byte) 0xff; // Set mask bytes to 1s
+ }
+ for (int i = maskBytes; i < addrByteLength; i++) {
+ mask[i] = 0; // Set remaining bytes to 0s
+ }
+ if (maskBits > 0) {
+ mask[maskBytes] = (byte) (0xff << (Byte.SIZE - maskBits));
+ }
+ return mask;
+ }
+
+ /**
+ * Creates a byte array that represents an IP address masked with
+ * a network mask of given mask length.
+ *
+ * @param addr the address to mask
+ * @param prefixLength the length of the mask prefix. Must be in the
+ * interval [0, 32] for IPv4, or [0, 128] for IPv6
+ * @return a byte array that represents the IP address masked with
+ * a mask prefix of the specified length
+ * @throws IllegalArgumentException if the prefix length is invalid
+ */
+ static byte[] makeMaskedAddressArray(final IpAddress addr,
+ int prefixLength) {
+ byte[] mask = IpAddress.makeMaskPrefixArray(addr.version(),
+ prefixLength);
+ byte[] net = new byte[mask.length];
+
+ // Mask each byte
+ for (int i = 0; i < net.length; i++) {
+ net[i] = (byte) (addr.octets[i] & mask[i]);
+ }
+ return net;
+ }
}
diff --git a/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java b/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java
index 4fef5a4..83592aa 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java
@@ -20,12 +20,13 @@
/**
* A class representing an IP prefix. A prefix consists of an IP address and
* a subnet mask.
+ * This class is immutable.
* <p>
* NOTE: The stored IP address in the result IP prefix is masked to
* contain zeroes in all bits after the prefix length.
* </p>
*/
-public final class IpPrefix {
+public class IpPrefix {
// Maximum network mask length
public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH;
public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH;
@@ -40,7 +41,7 @@
* @param prefixLength the prefix length
* @throws IllegalArgumentException if the prefix length value is invalid
*/
- private IpPrefix(IpAddress address, int prefixLength) {
+ protected IpPrefix(IpAddress address, int prefixLength) {
checkPrefixLength(address.version(), prefixLength);
this.address = IpAddress.makeMaskedAddress(address, prefixLength);
this.prefixLength = (short) prefixLength;
@@ -100,7 +101,7 @@
}
/**
- * Converts an IP address and a prefix length into IP prefix.
+ * Converts an IP address and a prefix length into an IP prefix.
*
* @param address the IP address
* @param prefixLength the prefix length
@@ -112,10 +113,11 @@
}
/**
- * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an
- * IP prefix.
+ * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16" or
+ * "1111:2222::/64") into an IP prefix.
*
- * @param address an IP prefix in string form, e.g. "10.1.0.0/16"
+ * @param address an IP prefix in string form (e.g. "10.1.0.0/16" or
+ * "1111:2222::/64")
* @return an IP prefix
* @throws IllegalArgumentException if the arguments are invalid
*/
@@ -123,7 +125,8 @@
final String[] parts = address.split("/");
if (parts.length != 2) {
String msg = "Malformed IP prefix string: " + address + "." +
- "Address must take form \"x.x.x.x/y\"";
+ "Address must take form \"x.x.x.x/y\" or " +
+ "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\"";
throw new IllegalArgumentException(msg);
}
IpAddress ipAddress = IpAddress.valueOf(parts[0]);