fixing loxi output
upgrade to 0.3.8
agrregate pom for of-lib

Change-Id: Ie75d75b708c30934bbca235e68c50de656d84ad4
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java b/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
index f103230..78e6075 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
@@ -232,6 +232,9 @@
     public final static MatchField<U16> BSN_TCP_FLAGS =
             new MatchField<U16>("bsn_tcp_flags", MatchFields.BSN_TCP_FLAGS);
 
+    public final static MatchField<ClassId> BSN_VLAN_XLATE_PORT_GROUP_ID =
+            new MatchField<ClassId>("bsn_vlan_xlate_port_group_id", MatchFields.BSN_VLAN_XLATE_PORT_GROUP_ID);
+
     public String getName() {
         return name;
     }
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java b/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
index 354a528..863634e 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
@@ -56,4 +56,5 @@
     BSN_UDF6,
     BSN_UDF7,
     BSN_TCP_FLAGS,
+    BSN_VLAN_XLATE_PORT_GROUP_ID,
 }
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/HashValue.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/HashValue.java
index 1dd55d5..3030e3e 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/HashValue.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/HashValue.java
@@ -17,6 +17,23 @@
      */
     int prefixBits(int numBits);
 
+    /** perform an arithmetic addition of this value and other. Wraps around on
+     * overflow of the defined word size.
+     *
+     * @param other
+     * @return this + other
+     */
+    H add(H other);
+
+    /**
+     * arithmetically substract the given 'other' value from this value.
+     * around on overflow.
+     *
+     * @param other
+     * @return this - other
+     */
+    H subtract(H other);
+
     /** @return the bitwise inverse of this value */
     H inverse();
 
@@ -29,26 +46,57 @@
     /** xor this value with another value value of the same type */
     H xor(H other);
 
-    /** calculate a combined hash value of this hash value (the <b>Key</b>) and the hash value
-     *  specified as a parameter (the <b>Value</b>).
-     *  <p>
-     *  The value is constructed as follows:
-     *  <ul>
-     *   <li>the first keyBits bits are taken only from the Key
-     *   <li>the other bits are taken from key xor value.
-     *  </ul>
-     *  The overall result looks like this:
-     *  <pre>
-     *  MSB                      LSB
-     *   +---------+--------------+
-     *   | key     | key ^ value  |
-     *   +---------+--------------+
-     *   |-keyBits-|
-     *  </pre>
+    /** create and return a builder */
+    Builder<H> builder();
+
+    /** a mutator for HashValues. Allows perfomring a series of
+     *  operations on a hashv value without the associated cost of object
+     *  reallocation.
      *
-     * @param value - hash value to be compared with this value (the key)
-     * @param keyBits number of prefix bits that are just taken from key
-     * @return the combined value.
+     * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+     *
+     * @param <H> - the hashvalue
      */
-    H combineWithValue(H value, int keyBits);
+    public interface Builder<H> {
+        /** perform an arithmetic addition of this value and other. Wraps around on
+         * overflow of the defined word size.
+         *
+         * @param other
+         * @return this mutator
+         */
+        Builder<H> add(H other);
+
+        /**
+         * arithmetically substract the given 'other' value from the value stored in this mutator.
+         * around on overflow.
+         *
+         * @param other
+         * @return this mutator
+         */
+        Builder<H> subtract(H other);
+
+        /** bitwise invert the value stored in this mutator
+         *
+         * @return this mutator
+         */
+        Builder<H> invert();
+
+        /** or the value stored in this mutator with another value value of the same type
+        * @return this mutator
+        */
+        Builder<H> or(H other);
+
+        /** and the value stored in this mutator with another value value of the same type
+        * @return this mutator
+        */
+        Builder<H> and(H other);
+
+        /** xor the value stored in this mutator with another value value of the same type
+        * @return this mutator
+        */
+        Builder<H> xor(H other);
+
+        /** @return the hash value */
+        public H build();
+    }
 }
\ No newline at end of file
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
index 5e4e818..cee9ad1 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
@@ -10,6 +10,11 @@
 
 public abstract class IPAddress<F extends IPAddress<F>> implements OFValueType<F> {
 
+    /**
+     * Returns the Internet Protocol (IP) version of this object
+     *
+     * @return  the Internet Protocol (IP) version of this object
+     */
     public abstract IPVersion getIpVersion();
 
     /**
@@ -55,6 +60,52 @@
      */
     public abstract F not();
 
+    /**
+     * Returns an {@code IPAddressWithMask<F>} object that represents this
+     * IP address masked by the given IP address mask.
+     *
+     * @param mask  the {@code F} object that represents the mask
+     * @return      an {@code IPAddressWithMask<F>} object that represents this
+     *              IP address masked by the given mask
+     * @throws NullPointerException  if the given mask was {@code null}
+     */
+    @Nonnull
+    public abstract IPAddressWithMask<F> withMask(@Nonnull final F mask);
+
+    /**
+     * Returns an {@code IPAddressWithMask<F>} object that represents this
+     * IP address masked by the CIDR subnet mask of the given prefix length.
+     *
+     * @param cidrMaskLength  the prefix length of the CIDR subnet mask
+     *                        (i.e. the number of leading one-bits),
+     *                        where <code>
+     *                        0 <= cidrMaskLength <= (F.getLength() * 8)
+     *                        </code>
+     * @return                an {@code IPAddressWithMask<F>} object that
+     *                        represents this IP address masked by the CIDR
+     *                        subnet mask of the given prefix length
+     * @throws IllegalArgumentException  if the given prefix length was invalid
+     * @see #ofCidrMaskLength(int)
+     */
+    @Nonnull
+    public abstract IPAddressWithMask<F> withMaskOfLength(
+            final int cidrMaskLength);
+
+    /**
+     * Returns the raw IP address of this {@code IPAddress} object. The result
+     * is in network byte order: the highest order byte of the address is in
+     * {@code getBytes()[0]}.
+     * <p>
+     * Similar to {@link InetAddress#getAddress()}
+     *
+     * @return  the raw IP address of this object
+     * @see InetAddress#getAddress()
+     */
+    public abstract byte[] getBytes();
+
+    @Override
+    public abstract String toString();
+
     @Override
     public abstract boolean equals(Object other);
 
@@ -88,14 +139,26 @@
      * @throws NullPointerException if address is null
      */
     @Nonnull
-    public static IPAddress<?> fromInetAddress(@Nonnull InetAddress address) {
+    public static IPAddress<?> of(@Nonnull InetAddress address) {
         Preconditions.checkNotNull(address, "address must not be null");
-        byte [] bytes = address.getAddress();
         if(address instanceof Inet4Address)
-            return IPv4Address.of(bytes);
+            return IPv4Address.of((Inet4Address) address);
         else if (address instanceof Inet6Address)
-            return IPv6Address.of(bytes);
+            return IPv6Address.of((Inet6Address) address);
         else
             return IPAddress.of(address.getHostAddress());
     }
+
+    /**
+     * Factory function for InetAddress values.
+     * @param address the InetAddress you wish to parse into an IPAddress object.
+     * @return the IPAddress object.
+     * @throws NullPointerException if address is null
+     * @deprecated  replaced by {@link #of(InetAddress)}
+     */
+    @Deprecated
+    @Nonnull
+    public static IPAddress<?> fromInetAddress(@Nonnull InetAddress address) {
+        return of(address);
+    }
 }
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
index ba7eb93..7cd8099 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
@@ -1,5 +1,7 @@
 package org.projectfloodlight.openflow.types;
 
+import com.google.common.base.Preconditions;
+
 
 public abstract class IPAddressWithMask<F extends IPAddress<F>> extends Masked<F> {
 
@@ -8,6 +10,8 @@
     }
 
     public abstract IPVersion getIpVersion();
+    
+    public abstract boolean contains(IPAddress<?> ip);
 
     public F getSubnetBroadcastAddress() {
         if (!mask.isCidrMask()) {
@@ -22,9 +26,8 @@
     }
 
     public static IPAddressWithMask<?> of(String ip) {
-        if (ip == null) {
-            throw new NullPointerException("String ip must not be null");
-        }
+        Preconditions.checkNotNull(ip, "string ip must not be null");
+
         if (ip.indexOf('.') != -1)
             return IPv4AddressWithMask.of(ip);
         else if (ip.indexOf(':') != -1)
@@ -49,5 +52,4 @@
 
         return res.toString();
     }
-
 }
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
index 865fb79..3a1b15e 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
@@ -1,11 +1,14 @@
 package org.projectfloodlight.openflow.types;
 
+import java.net.Inet4Address;
+import java.net.InetAddress;
 import java.util.Arrays;
 
 import javax.annotation.Nonnull;
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.base.Preconditions;
 import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
@@ -78,19 +81,17 @@
 
     @Override
     public IPv4Address and(IPv4Address other) {
-        if (other == null) {
-            throw new NullPointerException("Other IP Address must not be null");
-        }
-        IPv4Address otherIp = (IPv4Address) other;
+        Preconditions.checkNotNull(other, "other must not be null");
+
+        IPv4Address otherIp = 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;
+        Preconditions.checkNotNull(other, "other must not be null");
+
+        IPv4Address otherIp = other;
         return IPv4Address.of(rawValue | otherIp.rawValue);
     }
 
@@ -99,13 +100,30 @@
         return IPv4Address.of(~rawValue);
     }
 
-    public static IPv4Address of(final byte[] address) {
-        if (address == null) {
-            throw new NullPointerException("Address must not be null");
-        }
+    /**
+     * Returns an {@code IPv4Address} object that represents the given
+     * IP address. The argument is in network byte order: the highest
+     * order byte of the address is in {@code address[0]}.
+     * <p>
+     * The address byte array must be 4 bytes long (32 bits long).
+     * <p>
+     * Similar to {@link InetAddress#getByAddress(byte[])}.
+     *
+     * @param address  the raw IP address in network byte order
+     * @return         an {@code IPv4Address} object that represents the given
+     *                 raw IP address
+     * @throws NullPointerException      if the given address was {@code null}
+     * @throws IllegalArgumentException  if the given address was of an invalid
+     *                                   byte array length
+     * @see InetAddress#getByAddress(byte[])
+     */
+    @Nonnull
+    public static IPv4Address of(@Nonnull final byte[] address) {
+        Preconditions.checkNotNull(address, "address must not be null");
+
         if (address.length != LENGTH) {
             throw new IllegalArgumentException(
-                    "Invalid byte array length for IPv4Address address: " + address.length);
+                    "Invalid byte array length for IPv4 address: " + address.length);
         }
 
         int raw =
@@ -114,30 +132,37 @@
         return IPv4Address.of(raw);
     }
 
-    /** construct an IPv4Address from a 32-bit integer value.
+    /**
+     * Returns an {@code IPv4Address} object that represents the given
+     * IP address.
      *
-     * @param raw the IPAdress represented as a 32-bit integer
-     * @return the constructed IPv4Address
+     * @param raw  the raw IP address represented as a 32-bit integer
+     * @return     an {@code IPv4Address} object that represents the given
+     *             raw IP address
      */
+    @Nonnull
     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).
+    /**
+     * Returns an {@code IPv4Address} object that represents the given
+     * IP address. The argument is in the canonical quad-dotted notation.
+     * For example, {@code 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
+     * @param string  the IP address in the canonical quad-dotted notation
+     * @return        an {@code IPv4Address} object that represents the given
+     *                IP address
+     * @throws NullPointerException      if the given string was {@code null}
+     * @throws IllegalArgumentException  if the given string was not a valid
+     *                                   IPv4 address
      */
     @Nonnull
     public static IPv4Address of(@Nonnull final String string) throws IllegalArgumentException {
-        if (string == null) {
-            throw new NullPointerException("String must not be null");
-        }
+        Preconditions.checkNotNull(string, "string must not be null");
+
         int start = 0;
         int shift = 24;
 
@@ -161,12 +186,90 @@
         return IPv4Address.of(raw);
     }
 
+    /**
+     * Returns an {@code IPv4Address} object that represents the given
+     * IP address. The argument is given as an {@code Inet4Address} object.
+     *
+     * @param address  the IP address as an {@code Inet4Address} object
+     * @return         an {@code IPv4Address} object that represents the
+     *                 given IP address
+     * @throws NullPointerException  if the given {@code Inet4Address} was
+     *                               {@code null}
+     */
+    @Nonnull
+    public static IPv4Address of(@Nonnull final Inet4Address address) {
+        Preconditions.checkNotNull(address, "address must not be null");
+        return IPv4Address.of(address.getAddress());
+    }
+
+    /**
+     * Returns an {@code IPv4Address} object that represents the
+     * CIDR subnet mask of the given prefix length.
+     *
+     * @param cidrMaskLength  the prefix length of the CIDR subnet mask
+     *                        (i.e. the number of leading one-bits),
+     *                        where {@code 0 <= cidrMaskLength <= 32}
+     * @return                an {@code IPv4Address} object that represents the
+     *                        CIDR subnet mask of the given prefix length
+     * @throws IllegalArgumentException  if the given prefix length was invalid
+     */
+    @Nonnull
+    public static IPv4Address ofCidrMaskLength(final int cidrMaskLength) {
+        Preconditions.checkArgument(
+                cidrMaskLength >= 0 && cidrMaskLength <= 32,
+                "Invalid IPv4 CIDR mask length: %s", cidrMaskLength);
+
+        if (cidrMaskLength == 32) {
+            return IPv4Address.NO_MASK;
+        } else if (cidrMaskLength == 0) {
+            return IPv4Address.FULL_MASK;
+        } else {
+            int mask = (-1) << (32 - cidrMaskLength);
+            return IPv4Address.of(mask);
+        }
+    }
+
+    /**
+     * Returns an {@code IPv4AddressWithMask} object that represents this
+     * IP address masked by the given IP address mask.
+     *
+     * @param mask  the {@code IPv4Address} object that represents the mask
+     * @return      an {@code IPv4AddressWithMask} object that represents this
+     *              IP address masked by the given mask
+     * @throws NullPointerException  if the given mask was {@code null}
+     */
+    @Nonnull
+    @Override
+    public IPv4AddressWithMask withMask(@Nonnull final IPv4Address mask) {
+        return IPv4AddressWithMask.of(this, mask);
+    }
+
+    /**
+     * Returns an {@code IPv4AddressWithMask} object that represents this
+     * IP address masked by the CIDR subnet mask of the given prefix length.
+     *
+     * @param cidrMaskLength  the prefix length of the CIDR subnet mask
+     *                        (i.e. the number of leading one-bits),
+     *                        where {@code 0 <= cidrMaskLength <= 32}
+     * @return                an {@code IPv4AddressWithMask} object that
+     *                        represents this IP address masked by the CIDR
+     *                        subnet mask of the given prefix length
+     * @throws IllegalArgumentException  if the given prefix length was invalid
+     * @see #ofCidrMaskLength(int)
+     */
+    @Nonnull
+    @Override
+    public IPv4AddressWithMask withMaskOfLength(final int cidrMaskLength) {
+        return this.withMask(IPv4Address.ofCidrMaskLength(cidrMaskLength));
+    }
+
     public int getInt() {
         return rawValue;
     }
 
     private volatile byte[] bytesCache = null;
 
+    @Override
     public byte[] getBytes() {
         if (bytesCache == null) {
             synchronized (this) {
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4AddressWithMask.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4AddressWithMask.java
index 9b60c6a..b6dc1b9 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4AddressWithMask.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv4AddressWithMask.java
@@ -1,5 +1,9 @@
 package org.projectfloodlight.openflow.types;
 
+import javax.annotation.Nonnull;
+
+import com.google.common.base.Preconditions;
+
 
 public class IPv4AddressWithMask extends IPAddressWithMask<IPv4Address> {
     public final static IPv4AddressWithMask NONE = of(IPv4Address.NONE, IPv4Address.NONE);
@@ -17,27 +21,77 @@
         return IPVersion.IPv4;
     }
 
-    public static IPv4AddressWithMask of(int rawValue, int rawMask) {
+    /**
+     * Returns an {@code IPv4AddressWithMask} object that represents the given
+     * raw IP address masked by the given raw IP address mask.
+     *
+     * @param rawValue  the raw IP address to be masked
+     * @param rawMask   the raw IP address mask
+     * @return          an {@code IPv4AddressWithMask} object that represents
+     *                  the given raw IP address masked by the given raw IP
+     *                  address mask
+     * @deprecated      replaced by {@link IPv4Address#of(int)} and
+     *                  {@link IPv4Address#withMask(IPv4Address), e.g. <code>
+     *                  IPv4Address.of(int).withMask(IPv4Address.of(int))
+     *                  </code>
+     */
+    @Nonnull
+    @Deprecated
+    public static IPv4AddressWithMask of(final int rawValue, final int rawMask) {
         return new IPv4AddressWithMask(rawValue, rawMask);
     }
 
-    public static IPv4AddressWithMask of(IPv4Address value, IPv4Address mask) {
-        if (value == null) {
-            throw new NullPointerException("Value must not be null");
-        }
-        if (mask == null) {
-            throw new NullPointerException("Mask must not be null");
-        }
+    /**
+     * Returns an {@code IPv4AddressWithMask} object that represents the given
+     * IP address masked by the given IP address mask. Both arguments are given
+     * as {@code IPv4Address} objects.
+     *
+     * @param value  the IP address to be masked
+     * @param mask   the IP address mask
+     * @return       an {@code IPv4AddressWithMask} object that represents
+     *               the given IP address masked by the given IP address mask
+     * @throws NullPointerException  if any of the given {@code IPv4Address}
+     *                               objects were {@code null}
+     */
+    @Nonnull
+    public static IPv4AddressWithMask of(
+            @Nonnull final IPv4Address value,
+            @Nonnull final IPv4Address mask) {
+        Preconditions.checkNotNull(value, "value must not be null");
+        Preconditions.checkNotNull(mask, "mask must not be null");
+
         return new IPv4AddressWithMask(value, mask);
     }
 
-    public static IPv4AddressWithMask of(final String string) {
-        if (string == null) {
-            throw new NullPointerException("String must not be null");
-        }
+    /**
+     * Returns an {@code IPv4AddressWithMask} object that corresponds to
+     * the given string in CIDR notation or other acceptable notations.
+     * <p>
+     * The following notations are accepted.
+     * <table><tr>
+     * <th>Notation</th><th>Example</th><th>Notes</th>
+     * </tr><tr>
+     * <td>IPv4 address only</td><td>{@code 1.2.3.4}</td><td>The subnet mask of
+     * prefix length 32 (i.e. {@code 255.255.255.255}) is assumed.</td>
+     * </tr><tr>
+     * <td>IPv4 address/mask</td><td>{@code 1.2.3.4/255.255.255.0}</td>
+     * </tr><tr>
+     * <td>CIDR notation</td><td>{@code 1.2.3.4/24}</td>
+     * </tr></table>
+     *
+     * @param string  the string in acceptable notations
+     * @return        an {@code IPv4AddressWithMask} object that corresponds to
+     *                the given string in acceptable notations
+     * @throws NullPointerException      if the given string was {@code null}
+     * @throws IllegalArgumentException  if the given string was malformed
+     */
+    @Nonnull
+    public static IPv4AddressWithMask of(@Nonnull final String string) {
+        Preconditions.checkNotNull(string, "string must not be null");
+
         int slashPos;
         String ip = string;
-        int maskBits = 32;
+        int cidrMaskLength = 32;
         IPv4Address maskAddress = null;
 
         // Read mask suffix
@@ -52,14 +106,11 @@
                     maskAddress = IPv4Address.of(suffix);
                 } else {
                     // CIDR Suffix
-                    maskBits = Integer.parseInt(suffix);
+                    cidrMaskLength = Integer.parseInt(suffix);
                 }
             } catch (NumberFormatException e) {
                 throw new IllegalArgumentException("IP Address not well formed: " + string);
             }
-            if (maskBits < 0 || maskBits > 32) {
-                throw new IllegalArgumentException("IP Address not well formed: " + string);
-            }
         }
 
         // Read IP
@@ -68,17 +119,21 @@
         if (maskAddress != null) {
             // Full address mask
             return IPv4AddressWithMask.of(ipv4, maskAddress);
-        } else if (maskBits == 32) {
-            // No mask
-            return IPv4AddressWithMask.of(ipv4, IPv4Address.NO_MASK);
-        } else if (maskBits == 0) {
-            // No mask
-            return IPv4AddressWithMask.of(ipv4, IPv4Address.FULL_MASK);
         } else {
-            // With mask
-            int mask = (-1) << (32 - maskBits);
-            return IPv4AddressWithMask.of(ipv4, IPv4Address.of(mask));
+            return IPv4AddressWithMask.of(
+                    ipv4, IPv4Address.ofCidrMaskLength(cidrMaskLength));
         }
     }
 
+    @Override
+    public boolean contains(IPAddress<?> ip) {
+        Preconditions.checkNotNull(ip, "ip must not be null");
+
+        if(ip.getIpVersion() == IPVersion.IPv4) {
+            IPv4Address ipv4 = (IPv4Address) ip;
+            return this.matches(ipv4);
+        }
+
+        return false;
+    }
 }
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
index 83fb31a..471d0fb 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
@@ -1,5 +1,7 @@
 package org.projectfloodlight.openflow.types;
 
+import java.net.Inet6Address;
+import java.net.InetAddress;
 import java.util.Arrays;
 import java.util.regex.Pattern;
 
@@ -8,6 +10,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.base.Preconditions;
 import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Longs;
 
@@ -102,19 +105,17 @@
 
     @Override
     public IPv6Address and(IPv6Address other) {
-        if (other == null) {
-            throw new NullPointerException("Other IP Address must not be null");
-        }
-        IPv6Address otherIp = (IPv6Address) other;
+        Preconditions.checkNotNull(other, "other must not be null");
+
+        IPv6Address otherIp = other;
         return IPv6Address.of((raw1 & otherIp.raw1), (raw2 & otherIp.raw2));
     }
 
     @Override
     public IPv6Address or(IPv6Address other) {
-        if (other == null) {
-            throw new NullPointerException("Other IP Address must not be null");
-        }
-        IPv6Address otherIp = (IPv6Address) other;
+        Preconditions.checkNotNull(other, "other must not be null");
+
+        IPv6Address otherIp = other;
         return IPv6Address.of((raw1 | otherIp.raw1), (raw2 | otherIp.raw2));
     }
 
@@ -123,10 +124,27 @@
         return IPv6Address.of(~raw1, ~raw2);
     }
 
-    public static IPv6Address of(final byte[] address) {
-        if (address == null) {
-            throw new NullPointerException("Address must not be null");
-        }
+    /**
+     * Returns an {@code IPv6Address} object that represents the given
+     * IP address. The argument is in network byte order: the highest
+     * order byte of the address is in {@code address[0]}.
+     * <p>
+     * The address byte array must be 16 bytes long (128 bits long).
+     * <p>
+     * Similar to {@link InetAddress#getByAddress(byte[])}.
+     *
+     * @param address  the raw IP address in network byte order
+     * @return         an {@code IPv6Address} object that represents the given
+     *                 raw IP address
+     * @throws NullPointerException      if the given address was {@code null}
+     * @throws IllegalArgumentException  if the given address was of an invalid
+     *                                   byte array length
+     * @see InetAddress#getByAddress(byte[])
+     */
+    @Nonnull
+    public static IPv6Address of(@Nonnull final byte[] address) {
+        Preconditions.checkNotNull(address, "address must not be null");
+
         if (address.length != LENGTH) {
             throw new IllegalArgumentException(
                     "Invalid byte array length for IPv6 address: " + address.length);
@@ -171,25 +189,30 @@
 
     private final static Pattern colonPattern = Pattern.compile(":");
 
-    /** parse an IPv6Address from its conventional string representation.
-     *  <p>
-     *  Expects up to 8 groups of 16-bit hex words seperated by colons
-     *  (e.g., 2001:db8:85a3:8d3:1319:8a2e:370:7348).
-     *  <p>
-     *  Supports zero compression (e.g., 2001:db8::7348).
-     *  Does <b>not</b> currently support embedding a dotted-quad IPv4 address
-     *  into the IPv6 address (e.g., 2001:db8::192.168.0.1).
+    /**
+     * Returns an {@code IPv6Address} object that represents the given
+     * IP address. The argument is in the conventional string representation
+     * of IPv6 addresses.
+     * <p>
+     * Expects up to 8 groups of 16-bit hex words seperated by colons
+     * (e.g., 2001:db8:85a3:8d3:1319:8a2e:370:7348).
+     * <p>
+     * Supports zero compression (e.g., 2001:db8::7348).
+     * Does <b>not</b> currently support embedding a dotted-quad IPv4 address
+     * into the IPv6 address (e.g., 2001:db8::192.168.0.1).
      *
-     * @param string a string representation of an IPv6 address
-     * @return the parsed IPv6 address
-     * @throws NullPointerException if string is null
-     * @throws IllegalArgumentException if string is not a valid IPv6Address
+     * @param string  the IP address in the conventional string representation
+     *                of IPv6 addresses
+     * @return        an {@code IPv6Address} object that represents the given
+     *                IP address
+     * @throws NullPointerException      if the given string was {@code null}
+     * @throws IllegalArgumentException  if the given string was not a valid
+     *                                   IPv6 address
      */
     @Nonnull
     public static IPv6Address of(@Nonnull final String string) throws IllegalArgumentException {
-        if (string == null) {
-            throw new NullPointerException("String must not be null");
-        }
+        Preconditions.checkNotNull(string, "string must not be null");
+
         IPv6Builder builder = new IPv6Builder();
         String[] parts = colonPattern.split(string, -1);
 
@@ -242,19 +265,104 @@
         return builder.getIPv6();
     }
 
-    /** construct an IPv6 adress from two 64 bit integers representing the first and
-     *  second 8-byte blocks of the address.
+    /**
+     * Returns an {@code IPv6Address} object that represents the given
+     * IP address. The arguments are the two 64-bit integers representing
+     * the first (higher-order) and second (lower-order) 64-bit blocks
+     * of the IP address.
      *
-     * @param raw1 - the first 8 byte block of the address
-     * @param raw2 - the second 8 byte block of the address
-     * @return the constructed IPv6Address
+     * @param raw1  the first (higher-order) 64-bit block of the IP address
+     * @param raw2  the second (lower-order) 64-bit block of the IP address
+     * @return      an {@code IPv6Address} object that represents the given
+     *              raw IP address
      */
+    @Nonnull
     public static IPv6Address of(final long raw1, final long raw2) {
         if(raw1==NONE_VAL1 && raw2 == NONE_VAL2)
             return NONE;
         return new IPv6Address(raw1, raw2);
     }
 
+    /**
+     * Returns an {@code IPv6Address} object that represents the given
+     * IP address. The argument is given as an {@code Inet6Address} object.
+     *
+     * @param address  the IP address as an {@code Inet6Address} object
+     * @return         an {@code IPv6Address} object that represents the
+     *                 given IP address
+     * @throws NullPointerException  if the given {@code Inet6Address} was
+     *                               {@code null}
+     */
+    @Nonnull
+    public static IPv6Address of(@Nonnull final Inet6Address address) {
+        Preconditions.checkNotNull(address, "address must not be null");
+        return IPv6Address.of(address.getAddress());
+    }
+
+    /**
+     * Returns an {@code IPv6Address} object that represents the
+     * CIDR subnet mask of the given prefix length.
+     *
+     * @param cidrMaskLength  the prefix length of the CIDR subnet mask
+     *                        (i.e. the number of leading one-bits),
+     *                        where {@code 0 <= cidrMaskLength <= 128}
+     * @return                an {@code IPv6Address} object that represents the
+     *                        CIDR subnet mask of the given prefix length
+     * @throws IllegalArgumentException  if the given prefix length was invalid
+     */
+    @Nonnull
+    public static IPv6Address ofCidrMaskLength(final int cidrMaskLength) {
+        Preconditions.checkArgument(
+                cidrMaskLength >= 0 && cidrMaskLength <= 128,
+                "Invalid IPv6 CIDR mask length: %s", cidrMaskLength);
+
+        if (cidrMaskLength == 128) {
+            return IPv6Address.NO_MASK;
+        } else if (cidrMaskLength == 0) {
+            return IPv6Address.FULL_MASK;
+        } else {
+            int shift1 = Math.min(cidrMaskLength, 64);
+            long raw1 = shift1 == 0 ? 0 : -1L << (64 - shift1);
+            int shift2 = Math.max(cidrMaskLength - 64, 0);
+            long raw2 = shift2 == 0 ? 0 : -1L << (64 - shift2);
+            return IPv6Address.of(raw1, raw2);
+        }
+    }
+
+    /**
+     * Returns an {@code IPv6AddressWithMask} object that represents this
+     * IP address masked by the given IP address mask.
+     *
+     * @param mask  the {@code IPv6Address} object that represents the mask
+     * @return      an {@code IPv6AddressWithMask} object that represents this
+     *              IP address masked by the given mask
+     * @throws NullPointerException  if the given mask was {@code null}
+     */
+    @Nonnull
+    @Override
+    public IPv6AddressWithMask withMask(@Nonnull final IPv6Address mask) {
+        return IPv6AddressWithMask.of(this, mask);
+    }
+
+    /**
+     * Returns an {@code IPv6AddressWithMask} object that represents this
+     * IP address masked by the CIDR subnet mask of the given prefix length.
+     *
+     * @param cidrMaskLength  the prefix length of the CIDR subnet mask
+     *                        (i.e. the number of leading one-bits),
+     *                        where {@code 0 <= cidrMaskLength <= 128}
+     * @return                an {@code IPv6AddressWithMask} object that
+     *                        represents this IP address masked by the CIDR
+     *                        subnet mask of the given prefix length
+     * @throws IllegalArgumentException  if the given prefix length was invalid
+     * @see #ofCidrMaskLength(int)
+     */
+    @Nonnull
+    @Override
+    public IPv6AddressWithMask withMaskOfLength(final int cidrMaskLength) {
+        return this.withMask(IPv6Address.ofCidrMaskLength(cidrMaskLength));
+    }
+
     private volatile byte[] bytesCache = null;
 
     public byte[] getBytes() {
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv6AddressWithMask.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv6AddressWithMask.java
index 7259c7f..ee34923 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv6AddressWithMask.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/IPv6AddressWithMask.java
@@ -1,7 +1,6 @@
 package org.projectfloodlight.openflow.types;
 
-import java.math.BigInteger;
-import java.util.Arrays;
+import com.google.common.base.Preconditions;
 
 public class IPv6AddressWithMask extends IPAddressWithMask<IPv6Address> {
     public final static IPv6AddressWithMask NONE = of(IPv6Address.NONE, IPv6Address.NONE);
@@ -16,23 +15,17 @@
     }
 
     public static IPv6AddressWithMask of(IPv6Address value, IPv6Address mask) {
-        if (value == null) {
-            throw new NullPointerException("Value must not be null");
-        }
-        if (mask == null) {
-            throw new NullPointerException("Mask must not be null");
-        }
+        Preconditions.checkNotNull(value, "value must not be null");
+        Preconditions.checkNotNull(mask, "mask must not be null");
         return new IPv6AddressWithMask(value, mask);
     }
 
-
     public static IPv6AddressWithMask of(final String string) {
-        if (string == null) {
-            throw new NullPointerException("String must not be null");
-        }
+        Preconditions.checkNotNull(string, "string must not be null");
+
         int slashPos;
         String ip = string;
-        int maskBits = 128;
+        int cidrMaskLength = 128;
         IPv6Address maskAddress = null;
 
         // Read mask suffix
@@ -47,14 +40,11 @@
                     maskAddress = IPv6Address.of(suffix);
                 } else {
                     // CIDR Suffix
-                    maskBits = Integer.parseInt(suffix);
+                    cidrMaskLength = Integer.parseInt(suffix);
                 }
             } catch (NumberFormatException e) {
                 throw new IllegalArgumentException("IPv6 Address not well formed: " + string);
             }
-            if (maskBits < 0 || maskBits > 128) {
-                throw new IllegalArgumentException("IPv6 Address not well formed: " + string);
-            }
         }
 
         // Read IP
@@ -63,30 +53,21 @@
         if (maskAddress != null) {
             // Full address mask
             return IPv6AddressWithMask.of(ipv6, maskAddress);
-        } else if (maskBits == 128) {
-            // No mask
-            return IPv6AddressWithMask.of(ipv6, IPv6Address.NO_MASK);
-        } else if (maskBits == 0) {
-            // Entirely masked out
-            return IPv6AddressWithMask.of(ipv6, IPv6Address.FULL_MASK);
-        }else {
-            // With mask
-            BigInteger mask = BigInteger.ONE.negate().shiftLeft(128 - maskBits);
-            byte[] maskBytesTemp = mask.toByteArray();
-            byte[] maskBytes;
-            if (maskBytesTemp.length < 16) {
-                maskBytes = new byte[16];
-                System.arraycopy(maskBytesTemp, 0, maskBytes, 16 - maskBytesTemp.length, maskBytesTemp.length);
-                Arrays.fill(maskBytes, 0, 16 - maskBytesTemp.length, (byte)(0xFF));
-            } else if (maskBytesTemp.length > 16) {
-                maskBytes = new byte[16];
-                System.arraycopy(maskBytesTemp, 0, maskBytes, 0, maskBytes.length);
-            } else {
-                maskBytes = maskBytesTemp;
-            }
-            return IPv6AddressWithMask.of(ipv6, IPv6Address.of(maskBytes));
+        } else {
+            return IPv6AddressWithMask.of(ipv6,
+                    IPv6Address.ofCidrMaskLength(cidrMaskLength));
         }
     }
 
+    @Override
+    public boolean contains(IPAddress<?> ip) {
+        Preconditions.checkNotNull(ip, "ip must not be null");
 
+        if(ip.getIpVersion() == IPVersion.IPv6) {
+            IPv6Address ipv6 = (IPv6Address) ip;
+            return this.matches(ipv6);
+        }
+
+        return false;
+    }
 }
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/U128.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/U128.java
index 35ef846..ddf4faa 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/U128.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/U128.java
@@ -123,15 +123,100 @@
     }
 
     @Override
+    public U128 add(U128 other) {
+        long newRaw2 = this.raw2 + other.raw2;
+        long newRaw1 = this.raw1 + other.raw1;
+        if(UnsignedLongs.compare(newRaw2, this.raw2) < 0) {
+            // raw2 overflow
+            newRaw1+=1;
+        }
+        return U128.of(newRaw1, newRaw2);
+    }
+
+    @Override
+    public U128 subtract(U128 other) {
+        long newRaw2 = this.raw2 - other.raw2;
+        long newRaw1 = this.raw1 - other.raw1;
+        if(UnsignedLongs.compare(this.raw2, other.raw2) < 0) {
+            newRaw1 -= 1;
+        }
+        return U128.of(newRaw1, newRaw2);
+    }
+    @Override
     public int prefixBits(int numBits) {
         return HashValueUtils.prefixBits(this.raw1, numBits);
     }
 
     @Override
-    public U128 combineWithValue(U128 value, int keyBits) {
-        return U128.of(
-                HashValueUtils.combineWithValue(this.raw1, value.raw1, Math.min(64, keyBits)),
-                HashValueUtils.combineWithValue(this.raw2, value.raw2, Math.max(0,keyBits-64))
-        );
+    public HashValue.Builder<U128> builder() {
+        return new U128Builder(raw1, raw2);
     }
+
+    static class U128Builder implements HashValue.Builder<U128> {
+        private long raw1, raw2;
+
+        public U128Builder(long raw1, long raw2) {
+            this.raw1 = raw1;
+            this.raw2 = raw2;
+        }
+
+        @Override
+        public Builder<U128> add(U128 other) {
+            raw2 += other.raw2;
+            raw1 += other.raw1;
+            if(UnsignedLongs.compare(raw2, other.raw2) < 0) {
+                // raw2 overflow
+                raw1+=1;
+            }
+            return this;
+        }
+
+        @Override
+        public Builder<U128> subtract(
+                U128 other) {
+            if(UnsignedLongs.compare(this.raw2, other.raw2) >= 0) {
+                raw2 -= other.raw2;
+                raw1 -= other.raw1;
+            } else {
+                // raw2 overflow
+                raw2 -= other.raw2;
+                raw1 = this.raw1 - other.raw1 - 1;
+            }
+            return this;
+        }
+
+        @Override
+        public Builder<U128> invert() {
+            raw1 = ~raw1;
+            raw2 = ~raw2;
+            return this;
+        }
+
+        @Override
+        public Builder<U128> or(U128 other) {
+            raw1 |= other.raw1;
+            raw2 |= other.raw2;
+            return this;
+        }
+
+        @Override
+        public Builder<U128> and(U128 other) {
+            raw1 &= other.raw1;
+            raw2 &= other.raw2;
+            return this;
+        }
+
+        @Override
+        public Builder<U128> xor(U128 other) {
+            raw1 ^= other.raw1;
+            raw2 ^= other.raw2;
+            return this;
+        }
+
+        @Override
+        public U128 build() {
+            return U128.of(raw1, raw2);
+        }
+    }
+
 }
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/types/U64.java b/of/lib/src/main/java/org/projectfloodlight/openflow/types/U64.java
index 1353b42..f15544f 100644
--- a/of/lib/src/main/java/org/projectfloodlight/openflow/types/U64.java
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/types/U64.java
@@ -151,6 +151,16 @@
         return U64.of(raw ^ other.raw);
     }
 
+    @Override
+    public U64 add(U64 other) {
+        return U64.of(this.raw + other.raw);
+    }
+
+    @Override
+    public U64 subtract(U64 other) {
+        return U64.of(this.raw - other.raw);
+    }
+
     /** return the "numBits" highest-order bits of the hash.
      *  @param numBits number of higest-order bits to return [0-32].
      *  @return a numberic value of the 0-32 highest-order bits.
@@ -160,11 +170,6 @@
         return HashValueUtils.prefixBits(raw, numBits);
     }
 
-    @Override
-    public U64 combineWithValue(U64 value, int keyBits) {
-        return U64.of(HashValueUtils.combineWithValue(this.raw, value.raw, keyBits));
-    }
-
     public final static Reader READER = new Reader();
 
     private static class Reader implements OFMessageReader<U64> {
@@ -174,5 +179,59 @@
         }
     }
 
+    @Override
+    public HashValue.Builder<U64> builder() {
+        return new U64Builder(raw);
+    }
+
+    static class U64Builder implements Builder<U64> {
+        long raw;
+
+        public U64Builder(long raw) {
+            this.raw = raw;
+        }
+
+        @Override
+        public Builder<U64> add(U64 other) {
+            raw += other.raw;
+            return this;
+        }
+
+        @Override
+        public Builder<U64> subtract(
+                U64 other) {
+            raw -= other.raw;
+            return this;
+        }
+
+        @Override
+        public Builder<U64> invert() {
+            raw = ~raw;
+            return this;
+        }
+
+        @Override
+        public Builder<U64> or(U64 other) {
+            raw |= other.raw;
+            return this;
+        }
+
+        @Override
+        public Builder<U64> and(U64 other) {
+            raw &= other.raw;
+            return this;
+        }
+
+        @Override
+        public Builder<U64> xor(U64 other) {
+            raw ^= other.raw;
+            return this;
+        }
+
+        @Override
+        public U64 build() {
+            return U64.of(raw);
+        }
+    }
 
 }
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
index 865df75..2ba4528 100644
--- a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
@@ -1,8 +1,12 @@
 package org.projectfloodlight.openflow.types;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.net.InetAddress;
 import java.net.UnknownHostException;
 
 import org.junit.Test;
@@ -29,7 +33,7 @@
             // expected
         }
         try {
-            IPAddress.of(null);
+            IPAddress.of((String) null);
             fail("Should have thrown NullPointerException");
         } catch (NullPointerException e) {
             assertNotNull(e.getMessage());
@@ -41,7 +45,7 @@
             assertNotNull(e.getMessage());
         }
         try {
-            IPAddress.of(null);
+            IPAddress.of((String) null);
             fail("Should have thrown NullPointerException");
         } catch (NullPointerException e) {
             assertNotNull(e.getMessage());
@@ -55,6 +59,29 @@
     }
 
     @Test
+    public void testOfString() {
+        IPAddress<?> ip0 = IPAddress.of("1.2.3.4");
+        IPAddress<?> ip1 = IPAddress.of("abcd::1234");
+        assertTrue(ip0 instanceof IPv4Address);
+        assertTrue(ip1 instanceof IPv6Address);
+        assertEquals(ip0, IPv4Address.of("1.2.3.4"));
+        assertEquals(ip1, IPv6Address.of("abcd::1234"));
+    }
+
+    @Test
+    public void testOfInetAddress() throws Exception {
+        InetAddress ia0 = InetAddress.getByName("192.168.1.123");
+        InetAddress ia1 = InetAddress.getByName("fd00::4321");
+        IPAddress<?> ip0 = IPAddress.of(ia0);
+        IPAddress<?> ip1 = IPAddress.of(ia1);
+        assertTrue(ip0 instanceof IPv4Address);
+        assertTrue(ip1 instanceof IPv6Address);
+        assertEquals(ip0, IPv4Address.of(ia0));
+        assertEquals(ip1, IPv6Address.of(ia1));
+    }
+
+    @SuppressWarnings("deprecation")
+    @Test
     public void testFromInetAddressException() throws UnknownHostException {
         try {
             IPAddress.fromInetAddress(null);
@@ -64,4 +91,43 @@
         }
     }
 
+    @Test
+    public void testContains() {
+
+        // Test IPv4 Mask
+        IPAddressWithMask<?> mask = IPAddressWithMask.of("1.2.3.4/24");
+
+        IPAddress<?> validIp = IPAddress.of("1.2.3.5");
+        assertTrue(mask.contains(validIp));
+
+        IPAddress<?> invalidIp = IPAddress.of("1.2.5.5");
+        assertFalse(mask.contains(invalidIp));
+
+        IPAddress<?> invalidIpv6 = IPAddress.of("10:10::ffff");
+        assertFalse(mask.contains(invalidIpv6));
+
+        // Test IPv6 Mask
+        mask = IPAddressWithMask.of("10:10::1/112");
+
+        validIp = IPAddress.of("10:10::f");
+        assertTrue(mask.contains(validIp));
+
+        invalidIp = IPAddress.of("11:10::f");
+        assertFalse(mask.contains(invalidIp));
+
+        IPAddress<?> invalidIpv4 = IPAddress.of("10.0.0.1");
+        assertFalse(mask.contains(invalidIpv4));
+    }
+
+    @Test 
+    public void testContainsException() {
+        try {
+            IPAddressWithMask<?> mask = IPAddressWithMask.of("1.2.3.4/24");
+            mask.contains(null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+    }
+
 }
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
index a57b42a..0716b50 100644
--- a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
@@ -9,6 +9,9 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
 import org.hamcrest.CoreMatchers;
 import org.jboss.netty.buffer.ChannelBuffers;
 import org.junit.Test;
@@ -224,6 +227,83 @@
     }
 
     @Test
+    public void testOfCidrMaskLength() {
+        for (int i = 0; i <= 32; i++) {
+            assertEquals(IPv4Address.ofCidrMaskLength(i).asCidrMaskLength(), i);
+        }
+
+        assertEquals(IPv4Address.ofCidrMaskLength(0).getInt(), 0x0000_0000);
+
+        assertEquals(IPv4Address.ofCidrMaskLength(1).getInt(), 0x8000_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(2).getInt(), 0xC000_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(3).getInt(), 0xE000_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(4).getInt(), 0xF000_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(5).getInt(), 0xF800_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(6).getInt(), 0xFC00_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(7).getInt(), 0xFE00_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(8).getInt(), 0xFF00_0000);
+
+        assertEquals(IPv4Address.ofCidrMaskLength(9).getInt(), 0xFF80_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(10).getInt(), 0xFFC0_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(11).getInt(), 0xFFE0_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(12).getInt(), 0xFFF0_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(13).getInt(), 0xFFF8_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(14).getInt(), 0xFFFC_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(15).getInt(), 0xFFFE_0000);
+        assertEquals(IPv4Address.ofCidrMaskLength(16).getInt(), 0xFFFF_0000);
+
+        assertEquals(IPv4Address.ofCidrMaskLength(17).getInt(), 0xFFFF_8000);
+        assertEquals(IPv4Address.ofCidrMaskLength(18).getInt(), 0xFFFF_C000);
+        assertEquals(IPv4Address.ofCidrMaskLength(19).getInt(), 0xFFFF_E000);
+        assertEquals(IPv4Address.ofCidrMaskLength(20).getInt(), 0xFFFF_F000);
+        assertEquals(IPv4Address.ofCidrMaskLength(21).getInt(), 0xFFFF_F800);
+        assertEquals(IPv4Address.ofCidrMaskLength(22).getInt(), 0xFFFF_FC00);
+        assertEquals(IPv4Address.ofCidrMaskLength(23).getInt(), 0xFFFF_FE00);
+        assertEquals(IPv4Address.ofCidrMaskLength(24).getInt(), 0xFFFF_FF00);
+
+        assertEquals(IPv4Address.ofCidrMaskLength(25).getInt(), 0xFFFF_FF80);
+        assertEquals(IPv4Address.ofCidrMaskLength(26).getInt(), 0xFFFF_FFC0);
+        assertEquals(IPv4Address.ofCidrMaskLength(27).getInt(), 0xFFFF_FFE0);
+        assertEquals(IPv4Address.ofCidrMaskLength(28).getInt(), 0xFFFF_FFF0);
+        assertEquals(IPv4Address.ofCidrMaskLength(29).getInt(), 0xFFFF_FFF8);
+        assertEquals(IPv4Address.ofCidrMaskLength(30).getInt(), 0xFFFF_FFFC);
+        assertEquals(IPv4Address.ofCidrMaskLength(31).getInt(), 0xFFFF_FFFE);
+        assertEquals(IPv4Address.ofCidrMaskLength(32).getInt(), 0xFFFF_FFFF);
+    }
+
+    @Test
+    public void testWithMask() throws Exception {
+        // Sanity tests for the withMask*() syntactic sugars
+
+        IPv4Address original = IPv4Address.of("192.168.1.101");
+        IPv4Address expectedValue = IPv4Address.of("192.168.1.0");
+        IPv4Address expectedMask = IPv4Address.of("255.255.255.0");
+
+        IPv4AddressWithMask v;
+
+        v = original.withMask(IPv4Address.of(new byte[] {-1, -1, -1, 0}));
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+
+        v = original.withMask(IPv4Address.of(0xFFFF_FF00));
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+
+        v = original.withMask(IPv4Address.of("255.255.255.0"));
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+
+        Inet4Address i4a = (Inet4Address) InetAddress.getByName("255.255.255.0");
+        v = original.withMask(IPv4Address.of(i4a));
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+
+        v = original.withMaskOfLength(24);
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+    }
+
+    @Test
     public void testReadFrom() throws OFParseError {
         for(int i=0; i < testAddresses.length; i++ ) {
             IPv4Address ip = IPv4Address.read4Bytes(ChannelBuffers.copiedBuffer(testAddresses[i]));
@@ -367,5 +447,17 @@
         } catch (IllegalArgumentException e) {
             assertNotNull(e.getMessage());
         }
+        try {
+            IPv4Address.ofCidrMaskLength(-1);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            IPv4Address.ofCidrMaskLength(33);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            assertNotNull(e.getMessage());
+        }
     }
 }
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
index 6963c21..a397c2a 100644
--- a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
@@ -198,6 +198,79 @@
         }
     }
 
+    private static void testOfCidrMaskLengthHelper(
+            int cidrMaskLength, String ipStr) throws UnknownHostException {
+        byte[] ba0 = IPv6Address.ofCidrMaskLength(cidrMaskLength).getBytes();
+        byte[] ba1 = Inet6Address.getByName(ipStr).getAddress();
+        assertArrayEquals(ba0, ba1);
+    }
+
+    @Test
+    public void testOfCidrMaskLength() throws UnknownHostException {
+        for (int i = 0; i <= 128; i++) {
+            assertTrue(IPv6Address.ofCidrMaskLength(i).isCidrMask());
+            assertEquals(IPv6Address.ofCidrMaskLength(i).asCidrMaskLength(), i);
+        }
+        testOfCidrMaskLengthHelper(0, "::");
+        testOfCidrMaskLengthHelper(1, "8000::");
+        testOfCidrMaskLengthHelper(2, "c000::");
+        testOfCidrMaskLengthHelper(8, "ff00::");
+        testOfCidrMaskLengthHelper(16, "ffff::");
+        testOfCidrMaskLengthHelper(17, "ffff:8000::");
+        testOfCidrMaskLengthHelper(31, "ffff:fffe::");
+        testOfCidrMaskLengthHelper(32, "ffff:ffff::");
+        testOfCidrMaskLengthHelper(33, "ffff:ffff:8000::");
+        testOfCidrMaskLengthHelper(46, "ffff:ffff:fffc::");
+        testOfCidrMaskLengthHelper(48, "ffff:ffff:ffff::");
+        testOfCidrMaskLengthHelper(55, "ffff:ffff:ffff:fe00::");
+        testOfCidrMaskLengthHelper(56, "ffff:ffff:ffff:ff00::");
+        testOfCidrMaskLengthHelper(59, "ffff:ffff:ffff:ffe0::");
+        testOfCidrMaskLengthHelper(63, "ffff:ffff:ffff:fffe::");
+        testOfCidrMaskLengthHelper(64, "ffff:ffff:ffff:ffff::");
+        testOfCidrMaskLengthHelper(65, "ffff:ffff:ffff:ffff:8000::");
+        testOfCidrMaskLengthHelper(67, "ffff:ffff:ffff:ffff:e000::");
+        testOfCidrMaskLengthHelper(100, "ffff:ffff:ffff:ffff:ffff:ffff:f000::");
+        testOfCidrMaskLengthHelper(101, "ffff:ffff:ffff:ffff:ffff:ffff:f800::");
+        testOfCidrMaskLengthHelper(126, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc");
+        testOfCidrMaskLengthHelper(127, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe");
+        testOfCidrMaskLengthHelper(128, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+    }
+
+    @Test
+    public void testWithMask() throws Exception {
+        // Sanity tests for the withMask*() syntactic sugars
+
+        IPv6Address original = IPv6Address.of("fd12:3456:ABCD:7890::1");
+        IPv6Address expectedValue = IPv6Address.of("fd12:3456:ABCD::");
+        IPv6Address expectedMask = IPv6Address.of("ffff:ffff:ffff::");
+
+        IPv6AddressWithMask v;
+
+        v = original.withMask(IPv6Address.of(new byte[] {
+                -1, -1, -1, -1, -1, -1, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0 }));
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+
+        v = original.withMask(IPv6Address.of(
+                0xFFFF_FFFF_FFFF_0000L, 0x0000_0000_0000_0000L));
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+
+        v = original.withMask(IPv6Address.of("ffff:ffff:ffff::"));
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+
+        Inet6Address i6a = (Inet6Address) InetAddress.getByName("ffff:ffff:ffff::");
+        v = original.withMask(IPv6Address.of(i6a));
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+
+        v = original.withMaskOfLength(48);
+        assertEquals(v.getValue(), expectedValue);
+        assertEquals(v.getMask(), expectedMask);
+    }
+
     @Test
     public void testReadFrom() throws OFParseError, UnknownHostException {
         for(int i=0; i < testStrings.length; i++ ) {
@@ -313,5 +386,17 @@
         } catch (IllegalArgumentException e) {
             assertNotNull(e.getMessage());
         }
+        try {
+            IPv6Address.ofCidrMaskLength(-1);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            IPv6Address.ofCidrMaskLength(129);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            assertNotNull(e.getMessage());
+        }
     }
 }
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/U128Test.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/U128Test.java
index fb5cd23..81d9d7f 100644
--- a/of/lib/src/test/java/org/projectfloodlight/openflow/types/U128Test.java
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/U128Test.java
@@ -9,7 +9,12 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.text.MessageFormat;
+
 import org.hamcrest.Matchers;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.hash.HashCode;
@@ -17,6 +22,9 @@
 import com.google.common.hash.Hashing;
 
 public class U128Test {
+    private Triple[] triples;
+
+
     @Test
     public void testPositiveRaws() {
         assertThat(U128.of(0, 0).getMsb(), equalTo(0L));
@@ -27,6 +35,22 @@
     }
 
     @Test
+    public void testReadBytes() {
+        ChannelBuffer empty = ChannelBuffers.wrappedBuffer(new byte[16]);
+        U128 uEmpty = U128.read16Bytes(empty);
+        assertThat(uEmpty.getMsb(), equalTo(0L));
+        assertThat(uEmpty.getLsb(), equalTo(0L));
+
+        ChannelBuffer value = ChannelBuffers.wrappedBuffer(
+                new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88,
+                        (byte) 0x99, (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd,
+                        (byte) 0xee, (byte) 0xff, 0x11 });
+        U128 uValue = U128.read16Bytes(value);
+        assertThat(uValue.getMsb(), equalTo(0x1122334455667788L));
+        assertThat(uValue.getLsb(), equalTo(0x99aabbccddeeff11L));
+    }
+
+    @Test
     public void testPutTo() {
         U128 h         = U128.of(0x1234_5678_90ab_cdefL,0xdeafbeefdeadbeefL);
         U128 hSame     = U128.of(0x1234_5678_90ab_cdefL,0xdeafbeefdeadbeefL);
@@ -123,6 +147,80 @@
         }
     }
 
+    public static class Triple {
+        U128 a, b, c;
+
+        public Triple(U128 a, U128 b, U128 c) {
+            this.a = a;
+            this.b = b;
+            this.c = c;
+        }
+
+        public static Triple of(U128 a, U128 b, U128 c) {
+            return new Triple(a, b, c);
+        }
+
+        public String msg(String string) {
+            return MessageFormat.format(string, a,b,c);
+        }
+    }
+
+    @Before
+    public void setup() {
+        U128 u0_0 = U128.of(0, 0);
+        U128 u0_1 = U128.of(0, 1);
+        U128 u1_0 = U128.of(1, 0);
+        U128 u1_1 = U128.of(1, 1);
+
+        U128 u0_2 = U128.of(0, 2);
+        U128 u2_0 = U128.of(2, 0);
+
+        U128 u0_f = U128.of(0, -1L);
+        U128 uf_0 = U128.of(-1L, 0);
+
+        triples = new Triple[] {
+              Triple.of(u0_0, u0_0, u0_0),
+              Triple.of(u0_0, u0_1, u0_1),
+              Triple.of(u0_0, u1_0, u1_0),
+              Triple.of(u0_1, u1_0, u1_1),
+
+              Triple.of(u0_1, u0_1, u0_2),
+              Triple.of(u1_0, u1_0, u2_0),
+
+              Triple.of(u0_1, u0_f, u1_0),
+
+              Triple.of(u0_1, u0_f, u1_0),
+              Triple.of(u0_f, u0_f, U128.of(1, 0xffff_ffff_ffff_fffeL)),
+              Triple.of(uf_0, u0_f, U128.of(-1, -1)),
+              Triple.of(uf_0, u1_0, U128.ZERO),
+
+              Triple.of(U128.of(0x1234_5678_9abc_def1L, 0x1234_5678_9abc_def1L),
+                        U128.of(0xedcb_a987_6543_210eL, 0xedcb_a987_6543_210fL),
+                        U128.ZERO)
+        };
+    }
+
+    @Test
+    public void testAddSubtract() {
+        for(Triple t: triples) {
+            assertThat(t.msg("{0} + {1} = {2}"), t.a.add(t.b), equalTo(t.c));
+            assertThat(t.msg("{1} + {0} = {2}"), t.b.add(t.a), equalTo(t.c));
+
+            assertThat(t.msg("{2} - {0} = {1}"), t.c.subtract(t.a), equalTo(t.b));
+            assertThat(t.msg("{2} - {1} = {0}"), t.c.subtract(t.b), equalTo(t.a));
+        }
+    }
+
+    @Test
+    public void testAddSubtractBuilder() {
+        for(Triple t: triples) {
+            assertThat(t.msg("{0} + {1} = {2}"), t.a.builder().add(t.b).build(), equalTo(t.c));
+            assertThat(t.msg("{1} + {0} = {2}"), t.b.builder().add(t.a).build(), equalTo(t.c));
+
+            assertThat(t.msg("{2} - {0} = {1}"), t.c.builder().subtract(t.a).build(), equalTo(t.b));
+            assertThat(t.msg("{2} - {1} = {0}"), t.c.builder().subtract(t.b).build(), equalTo(t.a));
+        }
+    }
 
     @Test
     public void testCompare() {
@@ -163,20 +261,25 @@
     }
 
     @Test
-    public void testCombine() {
-        long key = 0x1234567890abcdefL;
-        long val = 0xdeafbeefdeadbeefL;
-        U128 hkey = U128.of(key, key*2);
-        U128 hVal = U128.of(val, val/2);
+    public void testBitwiseOperators() {
+        U128 one =   U128.of(0x5, 0x8);
+        U128 two = U128.of(0x7, 0x3);
 
-        assertThat(hkey.combineWithValue(hVal, 0), equalTo(hkey.xor(hVal)));
-        assertThat(hkey.combineWithValue(hVal, 64), equalTo(U128.of(hkey.getMsb(), hkey.getLsb() ^ hVal.getLsb())));
-        assertThat(hkey.combineWithValue(hVal, 128), equalTo(hkey));
+        assertThat(one.inverse(), equalTo(U128.of(0xfffffffffffffffaL, 0xfffffffffffffff7L)));
+        assertThat(one.and(two), equalTo(U128.of(0x5L, 0x0L)));
+        assertThat(one.or(two), equalTo(U128.of(0x7L, 0xbL)));
+        assertThat(one.xor(two), equalTo(U128.of(0x2L, 0xbL)));
+    }
 
-        long mask8 = 0xFF00_0000_0000_0000L;
+    @Test
+    public void testBitwiseOperatorsBuilder() {
+        U128 one =   U128.of(0x5, 0x8);
+        U128 two = U128.of(0x7, 0x3);
 
-        assertThat(hkey.combineWithValue(hVal, 8), equalTo(U128.of(hkey.getMsb() & mask8 |  hkey.getMsb() ^ hVal.getMsb() & ~mask8,
-                                                                   hkey.getLsb() ^ hVal.getLsb() )));
+        assertThat(one.builder().invert().build(), equalTo(U128.of(0xfffffffffffffffaL, 0xfffffffffffffff7L)));
+        assertThat(one.builder().and(two).build(), equalTo(U128.of(0x5L, 0x0L)));
+        assertThat(one.builder().or(two).build(), equalTo(U128.of(0x7L, 0xbL)));
+        assertThat(one.builder().xor(two).build(), equalTo(U128.of(0x2L, 0xbL)));
     }
 
 }
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/U64Test.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/U64Test.java
index b0cca23..4066bf8 100644
--- a/of/lib/src/test/java/org/projectfloodlight/openflow/types/U64Test.java
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/U64Test.java
@@ -9,11 +9,15 @@
 import static org.junit.Assert.fail;
 
 import java.math.BigInteger;
+import java.text.MessageFormat;
 
+import org.junit.Before;
 import org.junit.Test;
 
 public class U64Test {
 
+    private Triple[] triples;
+
     @Test
     public void testPositiveRaws() {
         for(long positive: new long[] { 0, 1, 100, Long.MAX_VALUE }) {
@@ -24,10 +28,10 @@
 
     @Test
     public void testNegativeRaws() {
-        long minus_1 = 0xFFFF_FFFF_FFFF_FFFFL;
-        assertEquals(minus_1, U64.ofRaw(minus_1).getValue());
-        assertEquals(new BigInteger("FFFF_FFFF_FFFF_FFFF".replace("_", ""), 16),  U64.ofRaw(minus_1).getBigInteger());
-        assertEquals(new BigInteger("18446744073709551615"),  U64.ofRaw(minus_1).getBigInteger());
+        long minu1 = 0xFFFF_FFFF_FFFF_FFFFL;
+        assertEquals(minu1, U64.ofRaw(minu1).getValue());
+        assertEquals(new BigInteger("FFFF_FFFF_FFFF_FFFF".replace("_", ""), 16),  U64.ofRaw(minu1).getBigInteger());
+        assertEquals(new BigInteger("18446744073709551615"),  U64.ofRaw(minu1).getBigInteger());
     }
 
     @Test
@@ -62,24 +66,6 @@
     }
 
     @Test
-    public void testCombine() {
-        long key = 0x1234567890abcdefL;
-        long val = 0xdeafbeefdeadbeefL;
-        U64 hkey = U64.of(key);
-        U64 hVal = U64.of(val);
-
-        assertThat(hkey.combineWithValue(hVal, 0), equalTo(hkey.xor(hVal)));
-        assertThat(hkey.combineWithValue(hVal, 64), equalTo(hkey));
-        long mask32 = 0x00000000FFFFFFFFL;
-        assertThat(hkey.combineWithValue(hVal, 32),
-                equalTo(U64.of(key & ~mask32| (key ^ val) & mask32)));
-
-        long tenMask = 0x003FFFFFFFFFFFFFL;
-        assertThat(hkey.combineWithValue(hVal, 10),
-                equalTo(U64.of(key & ~tenMask | (key ^ val) & tenMask)));
-    }
-
-    @Test
     public void testKeyBits() {
         U64 zeroU = U64.of(0);
         assertThat(zeroU.prefixBits(0), equalTo(0));
@@ -105,6 +91,76 @@
         checkInvalidKeyBitSize(signedBitU, 64);
     }
 
+    public static class Triple {
+        U64 a, b, c;
+
+        public Triple(U64 a, U64 b, U64 c) {
+            this.a = a;
+            this.b = b;
+            this.c = c;
+        }
+
+        public static Triple of(U64 a, U64 b, U64 c) {
+            return new Triple(a, b, c);
+        }
+
+        public String msg(String string) {
+            return MessageFormat.format(string, a,b,c);
+        }
+    }
+
+    @Before
+    public void setup() {
+        U64 u0 = U64.of(0);
+        U64 u1 = U64.of(1);
+
+        U64 u2 = U64.of(2);
+        U64 u7f = U64.of(0x7fff_ffff_ffff_ffffL);
+        U64 u8 = U64.of(0x8000_0000_0000_0000L);
+
+        U64 uf = U64.of(-1L);
+
+        triples = new Triple[] {
+              Triple.of(u0, u0, u0),
+              Triple.of(u0, u1, u1),
+
+              Triple.of(u1, u1, u2),
+
+              Triple.of(u1, uf, u0),
+
+              Triple.of(uf, uf, U64.of(0xffff_ffff_ffff_fffeL)),
+              Triple.of(u0, uf, uf),
+
+              Triple.of(u7f, u1, u8),
+
+              Triple.of(U64.of(0x1234_5678_9abc_def1L),
+                        U64.of(0xedcb_a987_6543_210fL),
+                        U64.ZERO)
+        };
+    }
+
+    @Test
+    public void testAddSubtract() {
+        for(Triple t: triples) {
+            assertThat(t.msg("{0} + {1} = {2}"), t.a.add(t.b), equalTo(t.c));
+            assertThat(t.msg("{1} + {0} = {2}"), t.b.add(t.a), equalTo(t.c));
+
+            assertThat(t.msg("{2} - {0} = {1}"), t.c.subtract(t.a), equalTo(t.b));
+            assertThat(t.msg("{2} - {1} = {0}"), t.c.subtract(t.b), equalTo(t.a));
+        }
+    }
+
+    @Test
+    public void testAddSubtractBuilder() {
+        for(Triple t: triples) {
+            assertThat(t.msg("{0} + {1} = {2}"), t.a.builder().add(t.b).build(), equalTo(t.c));
+            assertThat(t.msg("{1} + {0} = {2}"), t.b.builder().add(t.a).build(), equalTo(t.c));
+
+            assertThat(t.msg("{2} - {0} = {1}"), t.c.builder().subtract(t.a).build(), equalTo(t.b));
+            assertThat(t.msg("{2} - {1} = {0}"), t.c.builder().subtract(t.b).build(), equalTo(t.a));
+        }
+    }
+
     private void
             checkInvalidKeyBitSize(U64 u, int prefixBit) {
         try {
@@ -115,4 +171,25 @@
         }
     }
 
+    @Test
+    public void testBitwiseOperators() {
+        U64 notPi = U64.of(0x3141_5926_5358_9793L);
+        U64 notE =  U64.of(0x2718_2818_8459_4523L);
+
+        assertThat(notPi.inverse(), equalTo(U64.of(0xcebe_a6d9_aca7_686cL)));
+        assertThat(notPi.and(notE), equalTo(U64.of(0x2100_0800_0058_0503L)));
+        assertThat(notPi.or(notE),  equalTo(U64.of(0x3759_793e_d759_d7b3L)));
+        assertThat(notPi.xor(notE), equalTo(U64.of(0x1659_713e_d701_d2b0L)));
+    }
+
+    @Test
+    public void testBitwiseOperatorsBuilder() {
+        U64 notPi = U64.of(0x3141_5926_5358_9793L);
+        U64 notE =  U64.of(0x2718_2818_8459_4523L);
+
+        assertThat(notPi.builder().invert().build(), equalTo(U64.of(0xcebe_a6d9_aca7_686cL)));
+        assertThat(notPi.builder().and(notE).build(), equalTo(U64.of(0x2100_0800_0058_0503L)));
+        assertThat(notPi.builder().or(notE).build(),  equalTo(U64.of(0x3759_793e_d759_d7b3L)));
+        assertThat(notPi.builder().xor(notE).build(), equalTo(U64.of(0x1659_713e_d701_d2b0L)));
+    }
 }