blob: 180b7711de23b3dd045fc1ab55104dfb22bc8d37 [file] [log] [blame]
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import java.util.Objects;
// TODO: Add support for IPv6 as well.
/**
* A class representing an IP prefix. A prefix consists of an IP address and
* a subnet mask.
* <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 {
// 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;
private final IpAddress address;
private final short prefixLength;
/**
* Constructor for given IP address, and a prefix length.
*
* @param address the IP address
* @param prefixLength the prefix length
*/
private IpPrefix(IpAddress address, int prefixLength) {
checkPrefixLength(prefixLength);
this.address = IpAddress.makeMaskedAddress(address, prefixLength);
this.prefixLength = (short) prefixLength;
}
/**
* Checks whether the prefix length is valid.
*
* @param prefixLength the prefix length value to check
* @throws IllegalArgumentException if the prefix length value is invalid
*/
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 an integer and a prefix length into an IPv4 prefix.
*
* @param address an integer representing the IPv4 address
* @param prefixLength the prefix length
* @return an IP prefix
*/
public static IpPrefix valueOf(int address, int prefixLength) {
return new IpPrefix(IpAddress.valueOf(address), prefixLength);
}
/**
* Converts a byte array and a prefix length into an IP prefix.
*
* @param address the IP address value stored in network byte order
* @param prefixLength the prefix length
* @return an IP prefix
*/
public static IpPrefix valueOf(byte[] address, int prefixLength) {
return new IpPrefix(IpAddress.valueOf(address), prefixLength);
}
/**
* Converts an IP address and a prefix length into IP prefix.
*
* @param address the IP address
* @param prefixLength the prefix length
* @return an IP prefix
*/
public static IpPrefix valueOf(IpAddress address, int prefixLength) {
return new IpPrefix(address, prefixLength);
}
/**
* Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an
* IP prefix.
*
* @param address 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) {
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]);
return new IpPrefix(ipAddress, prefixLength);
}
/**
* Returns the IP version of the prefix.
*
* @return the IP version of the prefix
*/
public IpAddress.Version version() {
return address.version();
}
/**
* Returns the IP address value of the prefix.
*
* @return the IP address value of the prefix
*/
public IpAddress address() {
return address;
}
/**
* Returns the IP address prefix length.
*
* @return the IP address prefix length
*/
public int prefixLength() {
return prefixLength;
}
/**
* Determines whether a given IP prefix is contained within this prefix.
*
* @param other the IP prefix to test
* @return true if the other IP prefix is contained in this prefix,
* otherwise false
*/
public boolean contains(IpPrefix other) {
if (this.prefixLength > other.prefixLength) {
return false; // This prefix has smaller prefix size
}
//
// 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 IP address is contained within this prefix.
*
* @param other the IP address to test
* @return true if the IP address is contained in this prefix, otherwise
* false
*/
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() {
return Objects.hash(address, prefixLength);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
IpPrefix other = (IpPrefix) obj;
return ((prefixLength == other.prefixLength) &&
address.equals(other.address));
}
@Override
/*
* (non-Javadoc)
* The format is "x.x.x.x/y" for IPv4 prefixes.
*
* @see java.lang.Object#toString()
*/
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(address.toString());
builder.append("/");
builder.append(String.format("%d", prefixLength));
return builder.toString();
}
}