Pavlin Radoslavov

Refactor the IpPrefix API and implementation:

 * Now IpPrefix uses IpAddress to represent the subnet address
 * The IpPrefix subnet address is masked-out by the prefix length.
   E.g., IpPrefix("1.2.3.4/24") is now stored as IpPrefix("1.2.3.0/24")
 * Removed IpPrefix methods that are not used or don't apply anymore
 * Replaced usage of IpPrefix with IpAddress where appropriate
......@@ -36,7 +36,6 @@ import org.onlab.onos.net.host.InterfaceIpAddress;
import org.onlab.onos.net.host.PortAddresses;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
import org.slf4j.Logger;
......@@ -81,12 +80,8 @@ public class NetworkConfigReader {
if (splits.length != 2) {
throw new IllegalArgumentException("Invalid IP address and prefix length format");
}
//
// TODO: For now we need Ip4Prefix to mask-out the
// subnet address.
//
Ip4Prefix subnet4 = new Ip4Prefix(strIp);
IpPrefix subnet = IpPrefix.valueOf(subnet4.toString());
// NOTE: IpPrefix will mask-out the bits after the prefix length.
IpPrefix subnet = IpPrefix.valueOf(strIp);
IpAddress addr = IpAddress.valueOf(splits[0]);
InterfaceIpAddress ia =
new InterfaceIpAddress(addr, subnet);
......
......@@ -73,7 +73,7 @@ public class RouteEntry {
}
StringBuilder result = new StringBuilder(ip4Prefix.prefixLength());
long value = ip4Prefix.toInt();
long value = ip4Prefix.address().toInt() & 0xffffffffL;
for (int i = 0; i < ip4Prefix.prefixLength(); i++) {
long mask = 1 << (IpPrefix.MAX_INET_MASK_LENGTH - 1 - i);
result.append(((value & mask) == 0) ? "0" : "1");
......
......@@ -188,7 +188,7 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler {
int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
message.writeByte(prefixBitlen);
IpAddress address = prefix.toIpAddress();
IpAddress address = prefix.address();
long value = address.toInt() & 0xffffffffL;
for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
if (prefixBytelen-- == 0) {
......
......@@ -22,7 +22,7 @@ import java.util.Objects;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.flow.instructions.Instructions;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
......@@ -181,12 +181,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
}
@Override
public Builder setIpSrc(IpPrefix addr) {
public Builder setIpSrc(IpAddress addr) {
return add(Instructions.modL3Src(addr));
}
@Override
public Builder setIpDst(IpPrefix addr) {
public Builder setIpDst(IpAddress addr) {
return add(Instructions.modL3Dst(addr));
}
......
......@@ -19,7 +19,7 @@ import java.util.List;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
......@@ -92,14 +92,14 @@ public interface TrafficTreatment {
* @param addr an ip
* @return a treatment builder
*/
public Builder setIpSrc(IpPrefix addr);
public Builder setIpSrc(IpAddress addr);
/**
* Sets the dst l3 address.
* @param addr an ip
* @return a treatment builder
*/
public Builder setIpDst(IpPrefix addr);
public Builder setIpDst(IpAddress addr);
/**
* Sets the optical channel ID or lambda.
......
......@@ -27,7 +27,7 @@ import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.L2SubType;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.L3SubType;
import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
......@@ -115,7 +115,7 @@ public final class Instructions {
* @param addr the ip address to modify to.
* @return a L3 modification
*/
public static L3ModificationInstruction modL3Src(IpPrefix addr) {
public static L3ModificationInstruction modL3Src(IpAddress addr) {
checkNotNull(addr, "Src l3 address cannot be null");
return new ModIPInstruction(L3SubType.IP_SRC, addr);
}
......@@ -125,7 +125,7 @@ public final class Instructions {
* @param addr the ip address to modify to.
* @return a L3 modification
*/
public static L3ModificationInstruction modL3Dst(IpPrefix addr) {
public static L3ModificationInstruction modL3Dst(IpAddress addr) {
checkNotNull(addr, "Dst l3 address cannot be null");
return new ModIPInstruction(L3SubType.IP_DST, addr);
}
......
......@@ -19,7 +19,7 @@ import static com.google.common.base.MoreObjects.toStringHelper;
import java.util.Objects;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.IpAddress;
/**
* Abstraction of a single traffic treatment step.
......@@ -60,9 +60,9 @@ public abstract class L3ModificationInstruction implements Instruction {
public static final class ModIPInstruction extends L3ModificationInstruction {
private final L3SubType subtype;
private final IpPrefix ip;
private final IpAddress ip;
public ModIPInstruction(L3SubType subType, IpPrefix addr) {
public ModIPInstruction(L3SubType subType, IpAddress addr) {
this.subtype = subType;
this.ip = addr;
......@@ -73,7 +73,7 @@ public abstract class L3ModificationInstruction implements Instruction {
return this.subtype;
}
public IpPrefix ip() {
public IpAddress ip() {
return this.ip;
}
......
......@@ -38,7 +38,7 @@ public final class IpPrefixSerializer extends Serializer<IpPrefix> {
@Override
public void write(Kryo kryo, Output output,
IpPrefix object) {
byte[] octs = object.toOctets();
byte[] octs = object.address().toOctets();
output.writeInt(octs.length);
output.writeBytes(octs);
output.writeInt(object.prefixLength());
......
......@@ -31,6 +31,7 @@ import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.openflow.controller.Dpid;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
......@@ -167,24 +168,12 @@ public class FlowEntryBuilder {
case SET_NW_DST:
OFActionSetNwDst nwdst = (OFActionSetNwDst) act;
IPv4Address di = nwdst.getNwAddr();
if (di.isCidrMask()) {
builder.setIpDst(IpPrefix.valueOf(di.getInt(),
di.asCidrMaskLength()));
} else {
builder.setIpDst(IpPrefix.valueOf(di.getInt(),
IpPrefix.MAX_INET_MASK_LENGTH));
}
builder.setIpDst(IpAddress.valueOf(di.getInt()));
break;
case SET_NW_SRC:
OFActionSetNwSrc nwsrc = (OFActionSetNwSrc) act;
IPv4Address si = nwsrc.getNwAddr();
if (si.isCidrMask()) {
builder.setIpSrc(IpPrefix.valueOf(si.getInt(),
si.asCidrMaskLength()));
} else {
builder.setIpSrc(IpPrefix.valueOf(si.getInt(),
IpPrefix.MAX_INET_MASK_LENGTH));
}
builder.setIpSrc(IpAddress.valueOf(si.getInt()));
break;
case EXPERIMENTER:
OFActionExperimenter exp = (OFActionExperimenter) act;
......
......@@ -29,6 +29,8 @@ import org.onlab.onos.net.flow.criteria.Criteria.TcpPortCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFFlowAdd;
import org.projectfloodlight.openflow.protocol.OFFlowDelete;
......@@ -141,22 +143,30 @@ public abstract class FlowModBuilder {
break;
case IPV4_DST:
ip = (IPCriterion) c;
if (ip.ip().isMasked()) {
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toInt()),
IPv4Address.of(ip.ip().netmask().toInt()));
if (ip.ip().prefixLength() != IpPrefix.MAX_INET_MASK_LENGTH) {
IpAddress maskAddr =
IpAddress.makeMaskPrefix(ip.ip().prefixLength());
Masked<IPv4Address> maskedIp =
Masked.of(IPv4Address.of(ip.ip().address().toInt()),
IPv4Address.of(maskAddr.toInt()));
mBuilder.setMasked(MatchField.IPV4_DST, maskedIp);
} else {
mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toInt()));
mBuilder.setExact(MatchField.IPV4_DST,
IPv4Address.of(ip.ip().address().toInt()));
}
break;
case IPV4_SRC:
ip = (IPCriterion) c;
if (ip.ip().isMasked()) {
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toInt()),
IPv4Address.of(ip.ip().netmask().toInt()));
if (ip.ip().prefixLength() != IpPrefix.MAX_INET_MASK_LENGTH) {
IpAddress maskAddr =
IpAddress.makeMaskPrefix(ip.ip().prefixLength());
Masked<IPv4Address> maskedIp =
Masked.of(IPv4Address.of(ip.ip().address().toInt()),
IPv4Address.of(maskAddr.toInt()));
mBuilder.setMasked(MatchField.IPV4_SRC, maskedIp);
} else {
mBuilder.setExact(MatchField.IPV4_SRC, IPv4Address.of(ip.ip().toInt()));
mBuilder.setExact(MatchField.IPV4_SRC,
IPv4Address.of(ip.ip().address().toInt()));
}
break;
case IP_PROTO:
......
......@@ -21,7 +21,8 @@ import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A class representing an IPv4 address.
* A class representing an IP address.
* TODO: Add support for IPv6 as well.
*/
public final class IpAddress implements Comparable<IpAddress> {
// IP Versions
......@@ -44,8 +45,6 @@ public final class IpAddress implements Comparable<IpAddress> {
* @param value the IP address value
*/
private IpAddress(Version version, byte[] value) {
checkNotNull(value);
this.version = version;
this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH);
}
......@@ -53,7 +52,7 @@ public final class IpAddress implements Comparable<IpAddress> {
/**
* Converts an integer into an IPv4 address.
*
* @param value an integer representing an IPv4 value
* @param value an integer representing an IPv4 address value
* @return an IP address
*/
public static IpAddress valueOf(int value) {
......@@ -70,6 +69,7 @@ public final class IpAddress implements Comparable<IpAddress> {
* @return an IP address
*/
public static IpAddress valueOf(byte[] value) {
checkNotNull(value);
return new IpAddress(Version.INET, value);
}
......@@ -106,13 +106,13 @@ public final class IpAddress implements Comparable<IpAddress> {
/**
* Converts a dotted-decimal string (x.x.x.x) into an IPv4 address.
*
* @param address a IP address in string form, e.g. "10.0.0.1".
* @param address an IP address in string form, e.g. "10.0.0.1"
* @return an IP address
*/
public static IpAddress valueOf(String address) {
final String[] net = address.split("\\.");
if (net.length != INET_BYTE_LENGTH) {
String msg = "Malformed IPv4 address string; " +
String msg = "Malformed IPv4 address string: " + address + "." +
"Address must have four decimal values separated by dots (.)";
throw new IllegalArgumentException(msg);
}
......@@ -154,20 +154,21 @@ public final class IpAddress implements Comparable<IpAddress> {
/**
* Creates an IP network mask prefix.
*
* @param prefixLen the length of the mask prefix. Must be in the interval
* [0, 32] for IPv4
* @param prefixLength the length of the mask prefix. Must be in the
* interval [0, 32] for IPv4
* @return a new IP address that contains a mask prefix of the
* specified length
*/
public static IpAddress makeMaskPrefix(int prefixLen) {
public static IpAddress makeMaskPrefix(int prefixLength) {
// Verify the prefix length
if ((prefixLen < 0) || (prefixLen > INET_BIT_LENGTH)) {
final String msg = "Invalid IPv4 prefix length: " + prefixLen +
if ((prefixLength < 0) || (prefixLength > INET_BIT_LENGTH)) {
final String msg = "Invalid IPv4 prefix length: " + prefixLength +
". Must be in the interval [0, 32].";
throw new IllegalArgumentException(msg);
}
long v = (0xffffffffL << (INET_BIT_LENGTH - prefixLen)) & 0xffffffffL;
long v =
(0xffffffffL << (INET_BIT_LENGTH - prefixLength)) & 0xffffffffL;
return IpAddress.valueOf((int) v);
}
......@@ -176,14 +177,14 @@ public final class IpAddress implements Comparable<IpAddress> {
* mask length.
*
* @param addr the address to mask
* @param prefixLen the length of the mask prefix. Must be in the interval
* [0, 32] for IPv4
* @param prefixLength the length of the mask prefix. Must be in the
* interval [0, 32] for IPv4
* @return a new IP address that is masked with a mask prefix of the
* specified length
*/
public static IpAddress makeMaskedAddress(final IpAddress addr,
int prefixLen) {
IpAddress mask = IpAddress.makeMaskPrefix(prefixLen);
int prefixLength) {
IpAddress mask = IpAddress.makeMaskPrefix(prefixLength);
byte[] net = new byte[INET_BYTE_LENGTH];
// Mask each byte
......@@ -207,7 +208,7 @@ public final class IpAddress implements Comparable<IpAddress> {
@Override
public boolean equals(Object obj) {
if (obj == this) {
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
......@@ -221,7 +222,7 @@ public final class IpAddress implements Comparable<IpAddress> {
@Override
/*
* (non-Javadoc)
* format is "x.x.x.x" for IPv4 addresses.
* The format is "x.x.x.x" for IPv4 addresses.
*
* @see java.lang.Object#toString()
*/
......
......@@ -15,285 +15,174 @@
*/
package org.onlab.packet;
import java.util.Arrays;
import java.util.Objects;
/**
* A class representing an IPv4 prefix.
* A class representing an IP prefix.
* TODO: Add support for IPv6 as well.
* <p/>
* A prefix consists of an IP address and a subnet mask.
* NOTE: The stored IP address in the result IP prefix is masked to
* contain zeroes in all bits after the prefix length.
*/
public final class IpPrefix {
// TODO a comparator for netmasks? E.g. for sorting by prefix match order.
// IP Versions: IPv4 and IPv6
public enum Version { INET, INET6 };
// 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;
//no mask (no network), e.g. a simple address
private static final int DEFAULT_MASK = 0;
private final IpAddress address;
private final short prefixLength;
/**
* Default value indicating an unspecified address.
* Constructor for given IP address, and a prefix length.
*
* @param address the IP address
* @param prefixLength the prefix length
*/
private static final byte[] ANY = new byte[] {0, 0, 0, 0};
private final Version version;
private final byte[] octets;
private final int netmask;
private IpPrefix(IpAddress address, int prefixLength) {
checkPrefixLength(prefixLength);
this.address = IpAddress.makeMaskedAddress(address, prefixLength);
this.prefixLength = (short) prefixLength;
}
/**
* Constructor for given IP address version, prefix address octets,
* and network mask length.
* Checks whether the prefix length is valid.
*
* @param ver the IP address version
* @param octets the IP prefix address octets
* @param netmask the network mask length
* @param prefixLength the prefix length value to check
* @throws IllegalArgumentException if the prefix length value is invalid
*/
private IpPrefix(Version ver, byte[] octets, int netmask) {
this.version = ver;
this.octets = Arrays.copyOf(octets, IpAddress.INET_BYTE_LENGTH);
this.netmask = netmask;
private static void checkPrefixLength(int prefixLength) {
if ((prefixLength < 0) || (prefixLength > MAX_INET_MASK_LENGTH)) {
String msg = "Invalid prefix length " + prefixLength + ". " +
"The value must be in the interval [0, " +
MAX_INET_MASK_LENGTH + "]";
throw new IllegalArgumentException(msg);
}
}
/**
* Converts a byte array into an IP address.
* Converts an integer and a prefix length into an IPv4 prefix.
*
* @param address a byte array
* @param netmask the CIDR value subnet mask
* @return an IP address
* @param address an integer representing the IPv4 address
* @param prefixLength the prefix length
* @return an IP prefix
*/
public static IpPrefix valueOf(byte[] address, int netmask) {
return new IpPrefix(Version.INET, address, netmask);
public static IpPrefix valueOf(int address, int prefixLength) {
return new IpPrefix(IpAddress.valueOf(address), prefixLength);
}
/**
* Helper to convert an integer into a byte array.
* Converts a byte array and a prefix length into an IP prefix.
*
* @param address the integer to convert
* @return a byte array
* @param address the IP address value stored in network byte order
* @param prefixLength the prefix length
* @return an IP prefix
*/
private static byte[] bytes(int address) {
byte[] bytes = new byte [IpAddress.INET_BYTE_LENGTH];
for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
bytes[i] = (byte) ((address >> (IpAddress.INET_BYTE_LENGTH
- (i + 1)) * 8) & 0xff);
}
return bytes;
public static IpPrefix valueOf(byte[] address, int prefixLength) {
return new IpPrefix(IpAddress.valueOf(address), prefixLength);
}
/**
* Converts an integer into an IPv4 address.
* Converts an IP address and a prefix length into IP prefix.
*
* @param address an integer representing an IP value
* @param netmask the CIDR value subnet mask
* @return an IP address
* @param address the IP address
* @param prefixLength the prefix length
* @return an IP prefix
*/
public static IpPrefix valueOf(int address, int netmask) {
return new IpPrefix(Version.INET, bytes(address), netmask);
public static IpPrefix valueOf(IpAddress address, int prefixLength) {
return new IpPrefix(address, prefixLength);
}
/**
* Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
* string can also be in CIDR (slash) notation. If the netmask is omitted,
* it will be set to DEFAULT_MASK (0).
* Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an
* IP prefix.
*
* @param address a IP address in string form, e.g. "10.0.0.1", "10.0.0.1/24"
* @return an IP address
* @param value an IP prefix in string form, e.g. "10.1.0.0/16"
* @return an IP prefix
*/
public static IpPrefix valueOf(String address) {
final String[] parts = address.split("\\/");
if (parts.length > 2) {
throw new IllegalArgumentException("Malformed IP address string; "
+ "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
}
int mask = DEFAULT_MASK;
if (parts.length == 2) {
mask = Integer.parseInt(parts[1]);
if (mask > MAX_INET_MASK_LENGTH) {
throw new IllegalArgumentException(
"Value of subnet mask cannot exceed "
+ MAX_INET_MASK_LENGTH);
}
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\"";
throw new IllegalArgumentException(msg);
}
IpAddress ipAddress = IpAddress.valueOf(parts[0]);
int prefixLength = Integer.parseInt(parts[1]);
final String[] net = parts[0].split("\\.");
if (net.length != IpAddress.INET_BYTE_LENGTH) {
throw new IllegalArgumentException("Malformed IP address string; "
+ "Address must have four decimal values separated by dots (.)");
}
final byte[] bytes = new byte[IpAddress.INET_BYTE_LENGTH];
for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
bytes[i] = (byte) Short.parseShort(net[i], 10);
}
return new IpPrefix(Version.INET, bytes, mask);
return new IpPrefix(ipAddress, prefixLength);
}
/**
* Returns the IP version of this address.
* Returns the IP version of the prefix.
*
* @return the version
* @return the IP version of the prefix
*/
public Version version() {
return this.version;
public IpAddress.Version version() {
return address.version();
}
/**
* Returns the IP address as a byte array.
* Returns the IP address value of the prefix.
*
* @return a byte array
* @return the IP address value of the prefix
*/
public byte[] toOctets() {
return Arrays.copyOf(this.octets, IpAddress.INET_BYTE_LENGTH);
public IpAddress address() {
return address;
}
/**
* Returns the IP address prefix length.
*
* @return prefix length
* @return the IP address prefix length
*/
public int prefixLength() {
return netmask;
return prefixLength;
}
/**
* Returns the integral value of this IP address.
* Determines whether a given IP prefix is contained within this prefix.
*
* @return the IP address's value as an integer
* @param other the IP prefix to test
* @return true if the other IP prefix is contained in this prefix,
* otherwise false
*/
public int toInt() {
int val = 0;
for (int i = 0; i < octets.length; i++) {
val <<= 8;
val |= octets[i] & 0xff;
}
return val;
}
/**
* Helper for computing the mask value from CIDR.
*
* @return an integer bitmask
*/
private int mask() {
int shift = MAX_INET_MASK_LENGTH - this.netmask;
return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
}
/**
* Returns the subnet mask in IpAddress form.
*
* @return the subnet mask as an IpAddress
*/
public IpAddress netmask() {
return IpAddress.valueOf(mask());
}
/**
* Returns the network portion of this address as an IpAddress.
* The netmask of the returned IpAddress is the current mask. If this
* address doesn't have a mask, this returns an all-0 IpAddress.
*
* @return the network address or null
*/
public IpPrefix network() {
if (netmask == DEFAULT_MASK) {
return new IpPrefix(version, ANY, DEFAULT_MASK);
}
byte[] net = new byte [4];
byte[] mask = bytes(mask());
for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
net[i] = (byte) (octets[i] & mask[i]);
}
return new IpPrefix(version, net, netmask);
}
/**
* Returns the host portion of the IPAddress, as an IPAddress.
* The netmask of the returned IpAddress is the current mask. If this
* address doesn't have a mask, this returns a copy of the current
* address.
*
* @return the host address
*/
public IpPrefix host() {
if (netmask == DEFAULT_MASK) {
new IpPrefix(version, octets, netmask);
}
byte[] host = new byte [IpAddress.INET_BYTE_LENGTH];
byte[] mask = bytes(mask());
for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
host[i] = (byte) (octets[i] & ~mask[i]);
public boolean contains(IpPrefix other) {
if (this.prefixLength > other.prefixLength) {
return false; // This prefix has smaller prefix size
}
return new IpPrefix(version, host, netmask);
}
/**
* Returns an IpAddress of the bytes contained in this prefix.
* FIXME this is a hack for now and only works because IpPrefix doesn't
* mask the input bytes on creation.
*
* @return the IpAddress
*/
public IpAddress toIpAddress() {
return IpAddress.valueOf(octets);
}
public boolean isMasked() {
return mask() != 0;
//
// Mask the other address with my prefix length.
// If the other prefix is within this prefix, the masked address must
// be same as the address of this prefix.
//
IpAddress maskedAddr =
IpAddress.makeMaskedAddress(other.address, this.prefixLength);
return this.address.equals(maskedAddr);
}
/**
* Determines whether a given address is contained within this IpAddress'
* network.
* Determines whether a given IP address is contained within this prefix.
*
* @param other another IP address that could be contained in this network
* @return true if the other IP address is contained in this address'
* network, otherwise false
* @param other the IP address to test
* @return true if the IP address is contained in this prefix, otherwise
* false
*/
public boolean contains(IpPrefix other) {
if (this.netmask <= other.netmask) {
// Special case where they're both /32 addresses
if (this.netmask == MAX_INET_MASK_LENGTH) {
return Arrays.equals(octets, other.octets);
}
// Mask the other address with our network mask
IpPrefix otherMasked =
IpPrefix.valueOf(other.octets, netmask).network();
return network().equals(otherMasked);
}
return false;
}
public boolean contains(IpAddress address) {
// Need to get the network address because prefixes aren't automatically
// masked on creation
IpPrefix meMasked = network();
IpPrefix otherMasked =
IpPrefix.valueOf(address.toOctets(), netmask).network();
return Arrays.equals(meMasked.octets, otherMasked.octets);
public boolean contains(IpAddress other) {
//
// Mask the other address with my prefix length.
// If the other prefix is within this prefix, the masked address must
// be same as the address of this prefix.
//
IpAddress maskedAddr =
IpAddress.makeMaskedAddress(other, this.prefixLength);
return this.address.equals(maskedAddr);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + netmask;
result = prime * result + Arrays.hashCode(octets);
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
return Objects.hash(address, prefixLength);
}
@Override
......@@ -301,46 +190,26 @@ public final class IpPrefix {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
IpPrefix other = (IpPrefix) obj;
if (netmask != other.netmask) {
return false;
}
// TODO not quite right until we mask the input
if (!Arrays.equals(octets, other.octets)) {
return false;
}
if (version != other.version) {
return false;
}
return true;
return ((prefixLength == other.prefixLength) &&
address.equals(other.address));
}
@Override
/*
* (non-Javadoc)
* format is "x.x.x.x" for non-masked (netmask 0) addresses,
* and "x.x.x.x/y" for masked addresses.
* The format is "x.x.x.x/y" for IPv4 prefixes.
*
* @see java.lang.Object#toString()
*/
public String toString() {
final StringBuilder builder = new StringBuilder();
for (final byte b : this.octets) {
if (builder.length() > 0) {
builder.append(".");
}
builder.append(String.format("%d", b & 0xff));
}
if (netmask != DEFAULT_MASK) {
builder.append("/");
builder.append(String.format("%d", netmask));
}
builder.append(address.toString());
builder.append("/");
builder.append(String.format("%d", prefixLength));
return builder.toString();
}
}
......
......@@ -22,7 +22,7 @@ import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.junit.Test;
import org.onlab.packet.IpPrefix.Version;
import org.onlab.packet.IpAddress.Version;
import com.google.common.testing.EqualsTester;
......@@ -30,8 +30,9 @@ public class IpPrefixTest {
private static final byte [] BYTES1 = new byte [] {0xa, 0x0, 0x0, 0xa};
private static final byte [] BYTES2 = new byte [] {0xa, 0x0, 0x0, 0xb};
private static final int INTVAL1 = 167772170;
private static final int INTVAL2 = 167772171;
private static final int INTVAL0 = 0x0a000000;
private static final int INTVAL1 = 0x0a00000a;
private static final int INTVAL2 = 0x0a00000b;
private static final String STRVAL = "10.0.0.12/16";
private static final int MASK_LENGTH = 16;
......@@ -59,27 +60,29 @@ public class IpPrefixTest {
@Test
public void basics() {
IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK_LENGTH);
final byte [] bytes = new byte [] {0xa, 0x0, 0x0, 0xa};
final byte [] bytes = new byte [] {0xa, 0x0, 0x0, 0x0};
//check fields
// check fields
assertEquals("incorrect IP Version", Version.INET, ip1.version());
assertEquals("incorrect netmask", 16, ip1.prefixLength());
assertTrue("faulty toOctets()", Arrays.equals(bytes, ip1.toOctets()));
assertEquals("faulty toInt()", INTVAL1, ip1.toInt());
assertEquals("faulty toString()", "10.0.0.10/16", ip1.toString());
assertTrue("faulty toOctets()",
Arrays.equals(bytes, ip1.address().toOctets()));
assertEquals("faulty toInt()", INTVAL0, ip1.address().toInt());
assertEquals("faulty toString()", "10.0.0.0/16", ip1.toString());
}
@Test
public void netmasks() {
// masked
IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK_LENGTH);
IpPrefix host = IpPrefix.valueOf("0.0.0.10/16");
IpPrefix network = IpPrefix.valueOf("10.0.0.0/16");
assertEquals("incorrect host address", host, ip1.host());
assertEquals("incorrect network address", network, ip1.network());
assertEquals("incorrect netmask", "255.255.0.0", ip1.netmask().toString());
IpPrefix ip2 = IpPrefix.valueOf("10.0.0.10/16");
IpPrefix ip3 = IpPrefix.valueOf("10.0.0.0/16");
assertEquals("incorrect binary masked address",
ip1.toString(), "10.0.0.0/16");
assertEquals("incorrect string masked address",
ip2.toString(), "10.0.0.0/16");
assertEquals("incorrect network address",
ip2.toString(), "10.0.0.0/16");
}
@Test
......