| /* |
| * 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.nio.ByteBuffer; |
| import java.util.Arrays; |
| import java.util.Objects; |
| import static com.google.common.base.Preconditions.checkNotNull; |
| |
| /** |
| * A class representing an IPv4 address. |
| */ |
| public final class IpAddress implements Comparable<IpAddress> { |
| // IP Versions |
| public enum Version { INET, INET6 }; |
| |
| // lengths of address, in bytes |
| public static final int INET_BYTE_LENGTH = 4; |
| public static final int INET_BIT_LENGTH = INET_BYTE_LENGTH * Byte.SIZE; |
| public static final int INET6_BYTE_LENGTH = 16; |
| public static final int INET6_BIT_LENGTH = INET6_BYTE_LENGTH * Byte.SIZE; |
| |
| private final Version version; |
| private final byte[] octets; |
| |
| /** |
| * 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) |
| * @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); |
| } |
| |
| /** |
| * Converts an integer into an IPv4 address. |
| * |
| * @param value an integer representing an IPv4 value |
| * @return an IP address |
| */ |
| public static IpAddress valueOf(int value) { |
| byte[] bytes = |
| ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array(); |
| return new IpAddress(Version.INET, bytes); |
| } |
| |
| /** |
| * Converts a byte array into an IP address. |
| * |
| * @param value the IP address value stored in network byte order |
| * (i.e., the most significant byte first) |
| * @return an IP address |
| */ |
| public static IpAddress valueOf(byte[] value) { |
| return new IpAddress(Version.INET, value); |
| } |
| |
| /** |
| * Converts a byte array and a given offset from the beginning of the |
| * array into an IP address. |
| * <p/> |
| * The IP address is stored in network byte order (i.e., the most |
| * significant byte first). |
| * |
| * @param value the value to use |
| * @param offset the offset in bytes from the beginning of the byte array |
| * @return an IP address |
| */ |
| public static IpAddress valueOf(byte[] value, int offset) { |
| // Verify the arguments |
| if ((offset < 0) || (offset + INET_BYTE_LENGTH > value.length)) { |
| String msg; |
| if (value.length < INET_BYTE_LENGTH) { |
| msg = "Invalid IPv4 address array: array length: " + |
| value.length + ". Must be at least " + INET_BYTE_LENGTH; |
| } else { |
| msg = "Invalid IPv4 address array: array offset: " + |
| offset + ". Must be in the interval [0, " + |
| (value.length - INET_BYTE_LENGTH) + "]"; |
| } |
| throw new IllegalArgumentException(msg); |
| } |
| |
| byte[] bc = Arrays.copyOfRange(value, offset, value.length); |
| return IpAddress.valueOf(bc); |
| } |
| |
| /** |
| * 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". |
| * @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; " + |
| "Address must have four decimal values separated by dots (.)"; |
| throw new IllegalArgumentException(msg); |
| } |
| final byte[] bytes = new byte[INET_BYTE_LENGTH]; |
| for (int i = 0; i < INET_BYTE_LENGTH; i++) { |
| bytes[i] = (byte) Short.parseShort(net[i], 10); |
| } |
| return new IpAddress(Version.INET, bytes); |
| } |
| |
| /** |
| * Returns the IP version of this address. |
| * |
| * @return the version |
| */ |
| public Version version() { |
| return this.version; |
| } |
| |
| /** |
| * Returns the IP address as a byte array. |
| * |
| * @return a byte array |
| */ |
| public byte[] toOctets() { |
| return Arrays.copyOf(this.octets, INET_BYTE_LENGTH); |
| } |
| |
| /** |
| * Returns the integral value of this IP address. |
| * |
| * @return the IP address's value as an integer |
| */ |
| public int toInt() { |
| ByteBuffer bb = ByteBuffer.wrap(octets); |
| return bb.getInt(); |
| } |
| |
| /** |
| * Creates an IP network mask prefix. |
| * |
| * @param prefixLen 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) { |
| // Verify the prefix length |
| if ((prefixLen < 0) || (prefixLen > INET_BIT_LENGTH)) { |
| final String msg = "Invalid IPv4 prefix length: " + prefixLen + |
| ". Must be in the interval [0, 32]."; |
| throw new IllegalArgumentException(msg); |
| } |
| |
| long v = (0xffffffffL << (INET_BIT_LENGTH - prefixLen)) & 0xffffffffL; |
| return IpAddress.valueOf((int) v); |
| } |
| |
| /** |
| * Creates an IP 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] 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); |
| byte[] net = new byte[INET_BYTE_LENGTH]; |
| |
| // Mask each byte |
| for (int i = 0; i < INET_BYTE_LENGTH; i++) { |
| net[i] = (byte) (addr.octets[i] & mask.octets[i]); |
| } |
| return IpAddress.valueOf(net); |
| } |
| |
| @Override |
| public int compareTo(IpAddress o) { |
| Long lv = ((long) this.toInt()) & 0xffffffffL; |
| Long rv = ((long) o.toInt()) & 0xffffffffL; |
| return lv.compareTo(rv); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(version, Arrays.hashCode(octets)); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj == this) { |
| return true; |
| } |
| if ((obj == null) || (getClass() != obj.getClass())) { |
| return false; |
| } |
| IpAddress other = (IpAddress) obj; |
| return (version == other.version) && |
| Arrays.equals(octets, other.octets); |
| } |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * format is "x.x.x.x" for IPv4 addresses. |
| * |
| * @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)); |
| } |
| return builder.toString(); |
| } |
| } |