diff options
Diffstat (limited to 'framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java')
-rw-r--r-- | framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java new file mode 100644 index 00000000..14d07fed --- /dev/null +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java @@ -0,0 +1,303 @@ +/* + * Copyright 2014-2015 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; + +/** + * 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 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 + * @throws IllegalArgumentException if the prefix length value is invalid + */ + protected IpPrefix(IpAddress address, int prefixLength) { + checkPrefixLength(address.version(), prefixLength); + this.address = IpAddress.makeMaskedAddress(address, prefixLength); + this.prefixLength = (short) prefixLength; + } + + /** + * Returns the IP version of the prefix. + * + * @return the IP version of the prefix + */ + public IpAddress.Version version() { + return address.version(); + } + + /** + * Tests whether the IP version of this prefix is IPv4. + * + * @return true if the IP version of this prefix is IPv4, otherwise false. + */ + public boolean isIp4() { + return address.isIp4(); + } + + /** + * Tests whether the IP version of this prefix is IPv6. + * + * @return true if the IP version of this prefix is IPv6, otherwise false. + */ + public boolean isIp6() { + return address.isIp6(); + } + + /** + * 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; + } + + /** + * Gets the {@link Ip4Prefix} view of the IP prefix. + * + * @return the {@link Ip4Prefix} view of the IP prefix if it is IPv4, + * otherwise null + */ + public Ip4Prefix getIp4Prefix() { + if (!isIp4()) { + return null; + } + + // Return this object itself if it is already instance of Ip4Prefix + if (this instanceof Ip4Prefix) { + return (Ip4Prefix) this; + } + return Ip4Prefix.valueOf(address.getIp4Address(), prefixLength); + } + + /** + * Gets the {@link Ip6Prefix} view of the IP prefix. + * + * @return the {@link Ip6Prefix} view of the IP prefix if it is IPv6, + * otherwise null + */ + public Ip6Prefix getIp6Prefix() { + if (!isIp6()) { + return null; + } + + // Return this object itself if it is already instance of Ip6Prefix + if (this instanceof Ip6Prefix) { + return (Ip6Prefix) this; + } + return Ip6Prefix.valueOf(address.getIp6Address(), prefixLength); + } + + /** + * 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 + * @throws IllegalArgumentException if the prefix length value is invalid + */ + 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 version the IP address version + * @param address the IP address value stored in network byte order + * @param prefixLength the prefix length + * @return an IP prefix + * @throws IllegalArgumentException if the prefix length value is invalid + */ + public static IpPrefix valueOf(IpAddress.Version version, byte[] address, + int prefixLength) { + return new IpPrefix(IpAddress.valueOf(version, address), prefixLength); + } + + /** + * Converts an IP address and a prefix length into an IP prefix. + * + * @param address the IP address + * @param prefixLength the prefix length + * @return an IP prefix + * @throws IllegalArgumentException if the prefix length value is invalid + */ + 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" or + * "1111:2222::/64") into an IP prefix. + * + * @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 + */ + 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\" or " + + "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\""; + throw new IllegalArgumentException(msg); + } + IpAddress ipAddress = IpAddress.valueOf(parts[0]); + int prefixLength = Integer.parseInt(parts[1]); + + return new IpPrefix(ipAddress, 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 (version() != other.version()) { + return false; + } + + 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) { + if (version() != other.version()) { + return false; + } + + // + // 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) || (!(obj instanceof IpPrefix))) { + 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(); + } + + /** + * Checks whether the prefix length is valid. + * + * @param version the IP address version + * @param prefixLength the prefix length value to check + * @throws IllegalArgumentException if the prefix length value is invalid + */ + private static void checkPrefixLength(IpAddress.Version version, + int prefixLength) { + int maxPrefixLen = 0; + + switch (version) { + case INET: + maxPrefixLen = MAX_INET_MASK_LENGTH; + break; + case INET6: + maxPrefixLen = MAX_INET6_MASK_LENGTH; + break; + default: + String msg = "Invalid IP version " + version; + throw new IllegalArgumentException(msg); + } + + if ((prefixLength < 0) || (prefixLength > maxPrefixLen)) { + String msg = "Invalid prefix length " + prefixLength + ". " + + "The value must be in the interval [0, " + + maxPrefixLen + "]"; + throw new IllegalArgumentException(msg); + } + } +} |