initial import
Change-Id: Ief25aef0066ea96bd2c329ccef974c072b3a5a73
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
new file mode 100644
index 0000000..865fb79
--- /dev/null
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
@@ -0,0 +1,245 @@
+package org.projectfloodlight.openflow.types;
+
+import java.util.Arrays;
+
+import javax.annotation.Nonnull;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+import com.google.common.hash.PrimitiveSink;
+import com.google.common.primitives.UnsignedInts;
+
+
+
+/**
+ * Wrapper around an IPv4Address address
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class IPv4Address extends IPAddress<IPv4Address> {
+ static final int LENGTH = 4;
+ private final int rawValue;
+
+ private static final int NOT_A_CIDR_MASK = -1;
+ private static final int CIDR_MASK_CACHE_UNSET = -2;
+ // Must appear before the static IPv4Address constant assignments
+ private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
+
+ private final static int NONE_VAL = 0x0;
+ public final static IPv4Address NONE = new IPv4Address(NONE_VAL);
+
+ public static final IPv4Address NO_MASK = IPv4Address.of(0xFFFFFFFF);
+ public static final IPv4Address FULL_MASK = IPv4Address.of(0x00000000);
+
+ private IPv4Address(final int rawValue) {
+ this.rawValue = rawValue;
+ }
+
+ @Override
+ public IPVersion getIpVersion() {
+ return IPVersion.IPv4;
+ }
+
+ private int asCidrMaskLengthInternal() {
+ if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
+ // No lock required. We only write cidrMaskLengthCache once
+ int maskint = getInt();
+ if (maskint == 0) {
+ cidrMaskLengthCache = 0;
+ } else if (Integer.bitCount((~maskint) + 1) == 1) {
+ // IP represents a true CIDR prefix length
+ cidrMaskLengthCache = Integer.bitCount(maskint);
+ } else {
+ cidrMaskLengthCache = NOT_A_CIDR_MASK;
+ }
+ }
+ return cidrMaskLengthCache;
+ }
+
+ @Override
+ public boolean isCidrMask() {
+ return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
+ }
+
+ @Override
+ public int asCidrMaskLength() {
+ if (!isCidrMask()) {
+ throw new IllegalStateException("IP is not a valid CIDR prefix " +
+ "mask " + toString());
+ } else {
+ return asCidrMaskLengthInternal();
+ }
+ }
+
+ @Override
+ public boolean isBroadcast() {
+ return this.equals(NO_MASK);
+ }
+
+ @Override
+ public IPv4Address and(IPv4Address other) {
+ if (other == null) {
+ throw new NullPointerException("Other IP Address must not be null");
+ }
+ IPv4Address otherIp = (IPv4Address) other;
+ return IPv4Address.of(rawValue & otherIp.rawValue);
+ }
+
+ @Override
+ public IPv4Address or(IPv4Address other) {
+ if (other == null) {
+ throw new NullPointerException("Other IP Address must not be null");
+ }
+ IPv4Address otherIp = (IPv4Address) other;
+ return IPv4Address.of(rawValue | otherIp.rawValue);
+ }
+
+ @Override
+ public IPv4Address not() {
+ return IPv4Address.of(~rawValue);
+ }
+
+ public static IPv4Address of(final byte[] address) {
+ if (address == null) {
+ throw new NullPointerException("Address must not be null");
+ }
+ if (address.length != LENGTH) {
+ throw new IllegalArgumentException(
+ "Invalid byte array length for IPv4Address address: " + address.length);
+ }
+
+ int raw =
+ (address[0] & 0xFF) << 24 | (address[1] & 0xFF) << 16
+ | (address[2] & 0xFF) << 8 | (address[3] & 0xFF) << 0;
+ return IPv4Address.of(raw);
+ }
+
+ /** construct an IPv4Address from a 32-bit integer value.
+ *
+ * @param raw the IPAdress represented as a 32-bit integer
+ * @return the constructed IPv4Address
+ */
+ public static IPv4Address of(final int raw) {
+ if(raw == NONE_VAL)
+ return NONE;
+ return new IPv4Address(raw);
+ }
+
+ /** parse an IPv4Address from the canonical dotted-quad representation
+ * (1.2.3.4).
+ *
+ * @param string an IPv4 address in dotted-quad representation
+ * @return the parsed IPv4 address
+ * @throws NullPointerException if string is null
+ * @throws IllegalArgumentException if string is not a valid IPv4Address
+ */
+ @Nonnull
+ public static IPv4Address of(@Nonnull final String string) throws IllegalArgumentException {
+ if (string == null) {
+ throw new NullPointerException("String must not be null");
+ }
+ int start = 0;
+ int shift = 24;
+
+ int raw = 0;
+ while (shift >= 0) {
+ int end = string.indexOf('.', start);
+ if (end == start || !((shift > 0) ^ (end < 0)))
+ throw new IllegalArgumentException("IP Address not well formed: " + string);
+
+ String substr =
+ end > 0 ? string.substring(start, end) : string.substring(start);
+ int val = Integer.parseInt(substr);
+ if (val < 0 || val > 255)
+ throw new IllegalArgumentException("IP Address not well formed: " + string);
+
+ raw |= val << shift;
+
+ shift -= 8;
+ start = end + 1;
+ }
+ return IPv4Address.of(raw);
+ }
+
+ public int getInt() {
+ return rawValue;
+ }
+
+ private volatile byte[] bytesCache = null;
+
+ public byte[] getBytes() {
+ if (bytesCache == null) {
+ synchronized (this) {
+ if (bytesCache == null) {
+ bytesCache =
+ new byte[] { (byte) ((rawValue >>> 24) & 0xFF),
+ (byte) ((rawValue >>> 16) & 0xFF),
+ (byte) ((rawValue >>> 8) & 0xFF),
+ (byte) ((rawValue >>> 0) & 0xFF) };
+ }
+ }
+ }
+ return Arrays.copyOf(bytesCache, bytesCache.length);
+ }
+
+ @Override
+ public int getLength() {
+ return LENGTH;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder res = new StringBuilder();
+ res.append((rawValue >> 24) & 0xFF).append('.');
+ res.append((rawValue >> 16) & 0xFF).append('.');
+ res.append((rawValue >> 8) & 0xFF).append('.');
+ res.append((rawValue >> 0) & 0xFF);
+ return res.toString();
+ }
+
+ public void write4Bytes(ChannelBuffer c) {
+ c.writeInt(rawValue);
+ }
+
+ public static IPv4Address read4Bytes(ChannelBuffer c) {
+ return IPv4Address.of(c.readInt());
+ }
+
+ @Override
+ public IPv4Address applyMask(IPv4Address mask) {
+ return and(mask);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + rawValue;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ IPv4Address other = (IPv4Address) obj;
+ if (rawValue != other.rawValue)
+ return false;
+ return true;
+ }
+
+ @Override
+ public int compareTo(IPv4Address o) {
+ return UnsignedInts.compare(rawValue, o.rawValue);
+ }
+
+ @Override
+ public void putTo(PrimitiveSink sink) {
+ sink.putInt(rawValue);
+ }
+
+}