blob: 91510b1b2deb0deddd4bfa8f72d9a6c014a0c5b7 [file] [log] [blame]
package net.onrc.onos.apps.sdnip;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import com.google.common.net.InetAddresses;
/**
* Represents an IP prefix.
* <p/>
* It is made up of an IP address and a number of significant bits in the
* prefix (i.e. the size of the network part of the address).
* E.g. {@code 192.168.0.0/16}.
* <p/>
* Currently only IPv4 is supported, so a prefix length can be up to 32 bits.
*/
public class Prefix {
/**
* The length of addresses this class can represent prefixes of, in bytes.
*/
public static final int ADDRESS_LENGTH = 4;
private final int prefixLength;
private final byte[] address;
// For verifying the arguments and pretty printing
private final InetAddress inetAddress;
/**
* Class constructor, taking an byte array representing and IP address and
* a prefix length.
* <p/>
* The valid values for addr and prefixLength are bounded by
* {@link #ADDRESS_LENGTH}.
* <p/>
* A valid addr array satisfies
* {@code addr.length == }{@value #ADDRESS_LENGTH}.
* <p/>
* A valid prefixLength satisfies
* {@code (prefixLength > 0 && prefixLength <=} {@link Byte#SIZE}
* {@code * }{@value #ADDRESS_LENGTH}{@code )}.
*
* @param addr a byte array representing the address
* @param prefixLength length of the prefix of the specified address
*/
public Prefix(byte[] addr, int prefixLength) {
if (addr == null || addr.length != ADDRESS_LENGTH ||
prefixLength < 0 || prefixLength > ADDRESS_LENGTH * Byte.SIZE) {
throw new IllegalArgumentException();
}
address = canonicalizeAddress(addr, prefixLength);
this.prefixLength = prefixLength;
try {
inetAddress = InetAddress.getByAddress(address);
} catch (UnknownHostException e) {
throw new IllegalArgumentException("Couldn't parse IP address", e);
}
}
/**
* Class constructor, taking an address in String format and a prefix
* length. The address must be in dot-notation form (e.g. {@code 0.0.0.0}).
*
* @param strAddress a String representing the address
* @param prefixLength length of the prefix of the specified address
*/
public Prefix(String strAddress, int prefixLength) {
byte[] addr = null;
addr = InetAddresses.forString(strAddress).getAddress();
if (addr == null || addr.length != ADDRESS_LENGTH ||
prefixLength < 0 || prefixLength > ADDRESS_LENGTH * Byte.SIZE) {
throw new IllegalArgumentException();
}
address = canonicalizeAddress(addr, prefixLength);
this.prefixLength = prefixLength;
try {
inetAddress = InetAddress.getByAddress(address);
} catch (UnknownHostException e) {
throw new IllegalArgumentException("Couldn't parse IP address", e);
}
}
private byte[] canonicalizeAddress(byte[] addressValue,
int prefixLengthValue) {
byte[] result = new byte[addressValue.length];
if (prefixLengthValue == 0) {
for (int i = 0; i < ADDRESS_LENGTH; i++) {
result[i] = 0;
}
return result;
}
result = Arrays.copyOf(addressValue, addressValue.length);
//Set all bytes after the end of the prefix to 0
int lastByteIndex = (prefixLengthValue - 1) / Byte.SIZE;
for (int i = lastByteIndex; i < ADDRESS_LENGTH; i++) {
result[i] = 0;
}
byte lastByte = addressValue[lastByteIndex];
byte mask = 0;
byte msb = (byte) 0x80;
int lastBit = (prefixLengthValue - 1) % Byte.SIZE;
for (int i = 0; i < Byte.SIZE; i++) {
if (i <= lastBit) {
mask |= (msb >> i);
}
}
result[lastByteIndex] = (byte) (lastByte & mask);
return result;
}
/**
* Gets the length of the prefix of the address.
*
* @return the prefix length
*/
public int getPrefixLength() {
return prefixLength;
}
/**
* Gets the address.
*
* @return the address as a byte array
*/
public byte[] getAddress() {
return Arrays.copyOf(address, address.length);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Prefix)) {
return false;
}
Prefix otherPrefix = (Prefix) other;
return (Arrays.equals(address, otherPrefix.address)) &&
(prefixLength == otherPrefix.prefixLength);
}
@Override
public int hashCode() {
int hash = 17;
hash = 31 * hash + prefixLength;
hash = 31 * hash + Arrays.hashCode(address);
return hash;
}
@Override
public String toString() {
return inetAddress.getHostAddress() + "/" + prefixLength;
}
/**
* Print the prefix to a String showing the bits of the address.
*
* @return the bit-string of the prefix
*/
public String printAsBits() {
StringBuilder result = new StringBuilder();
for (int i = 0; i < address.length; i++) {
byte b = address[i];
for (int j = 0; j < Byte.SIZE; j++) {
byte mask = (byte) (0x80 >>> j);
result.append(((b & mask) == 0) ? "0" : "1");
if (i * Byte.SIZE + j == prefixLength - 1) {
return result.toString();
}
}
result.append(' ');
}
return result.substring(0, result.length() - 1);
}
}