Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
index aea6e06..fb594e4 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
@@ -148,9 +148,9 @@
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
                         .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchTcpDst((short) BgpConstants.BGP_PORT)
                         .build();
 
@@ -171,9 +171,9 @@
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
                         .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchTcpSrc((short) BgpConstants.BGP_PORT)
                         .build();
 
@@ -191,9 +191,9 @@
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
                         .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchTcpDst((short) BgpConstants.BGP_PORT)
                         .build();
 
@@ -211,9 +211,9 @@
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
                         .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchTcpSrc((short) BgpConstants.BGP_PORT)
                         .build();
 
@@ -281,9 +281,9 @@
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_ICMP)
                         .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .build();
 
                 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
@@ -301,9 +301,9 @@
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_ICMP)
                         .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
-                                IpAddress.MAX_INET_MASK))
+                                IpPrefix.MAX_INET_MASK_LENGTH))
                         .build();
 
                 PointToPointIntent reversedIntent =
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/RouteEntry.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/RouteEntry.java
index a54c5f2..1b45ac5 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/RouteEntry.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/RouteEntry.java
@@ -75,7 +75,7 @@
         StringBuilder result = new StringBuilder(ip4Prefix.prefixLength());
         long value = ip4Prefix.toInt();
         for (int i = 0; i < ip4Prefix.prefixLength(); i++) {
-            long mask = 1 << (IpAddress.MAX_INET_MASK - 1 - i);
+            long mask = 1 << (IpPrefix.MAX_INET_MASK_LENGTH - 1 - i);
             result.append(((value & mask) == 0) ? "0" : "1");
         }
         return result.toString();
diff --git a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/bgp/TestBgpPeerChannelHandler.java b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/bgp/TestBgpPeerChannelHandler.java
index a946c48..ca4ccb7 100644
--- a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/bgp/TestBgpPeerChannelHandler.java
+++ b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/bgp/TestBgpPeerChannelHandler.java
@@ -190,12 +190,12 @@
 
             IpAddress address = prefix.toIpAddress();
             long value = address.toInt() & 0xffffffffL;
-            for (int i = 0; i < IpAddress.INET_LEN; i++) {
+            for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
                 if (prefixBytelen-- == 0) {
                     break;
                 }
                 long nextByte =
-                    (value >> ((IpAddress.INET_LEN - i - 1) * 8)) & 0xff;
+                    (value >> ((IpAddress.INET_BYTE_LENGTH - i - 1) * 8)) & 0xff;
                 message.writeByte((int) nextByte);
             }
         }
diff --git a/core/net/src/main/java/org/onlab/onos/net/host/impl/HostMonitor.java b/core/net/src/main/java/org/onlab/onos/net/host/impl/HostMonitor.java
index cfe4749..4b12931 100644
--- a/core/net/src/main/java/org/onlab/onos/net/host/impl/HostMonitor.java
+++ b/core/net/src/main/java/org/onlab/onos/net/host/impl/HostMonitor.java
@@ -46,7 +46,6 @@
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.util.Timer;
 
@@ -212,7 +211,7 @@
         arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
            .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
            .setProtocolType(ARP.PROTO_TYPE_IP)
-           .setProtocolAddressLength((byte) IpPrefix.INET_LEN)
+           .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH)
            .setOpCode(ARP.OP_REQUEST);
 
         arp.setSenderHardwareAddress(sourceMac.getAddress())
diff --git a/core/net/src/main/java/org/onlab/onos/net/proxyarp/impl/ProxyArpManager.java b/core/net/src/main/java/org/onlab/onos/net/proxyarp/impl/ProxyArpManager.java
index 47e0cff..953e88a 100644
--- a/core/net/src/main/java/org/onlab/onos/net/proxyarp/impl/ProxyArpManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/proxyarp/impl/ProxyArpManager.java
@@ -56,7 +56,6 @@
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.slf4j.Logger;
@@ -368,7 +367,7 @@
         arp.setProtocolType(ARP.PROTO_TYPE_IP);
         arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
 
-        arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN);
+        arp.setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH);
         arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
         arp.setSenderHardwareAddress(srcMac.getAddress());
         arp.setTargetHardwareAddress(request.getSourceMACAddress());
diff --git a/core/net/src/test/java/org/onlab/onos/net/proxyarp/impl/ProxyArpManagerTest.java b/core/net/src/test/java/org/onlab/onos/net/proxyarp/impl/ProxyArpManagerTest.java
index 6eca77c..f720535 100644
--- a/core/net/src/test/java/org/onlab/onos/net/proxyarp/impl/ProxyArpManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/proxyarp/impl/ProxyArpManagerTest.java
@@ -534,7 +534,7 @@
         arp.setProtocolType(ARP.PROTO_TYPE_IP);
         arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
 
-        arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN);
+        arp.setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH);
         arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
         arp.setSenderHardwareAddress(srcMac.getAddress());
 
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/topology/impl/DistributedTopologyStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/topology/impl/DistributedTopologyStore.java
index 3878c79..cc42c88 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/topology/impl/DistributedTopologyStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/topology/impl/DistributedTopologyStore.java
@@ -17,6 +17,7 @@
 
 import static org.slf4j.LoggerFactory.getLogger;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -26,11 +27,13 @@
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.onos.event.Event;
 import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.Device;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.Link;
 import org.onlab.onos.net.Path;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.net.topology.ClusterId;
+import org.onlab.onos.net.topology.DefaultGraphDescription;
 import org.onlab.onos.net.topology.GraphDescription;
 import org.onlab.onos.net.topology.LinkWeight;
 import org.onlab.onos.net.topology.Topology;
@@ -55,7 +58,11 @@
 
     private final Logger log = getLogger(getClass());
 
-    private volatile DefaultTopology current;
+    private volatile DefaultTopology current =
+            new DefaultTopology(ProviderId.NONE,
+                    new DefaultGraphDescription(0L,
+                            Collections.<Device>emptyList(),
+                            Collections.<Link>emptyList()));
 
     @Activate
     public void activate() {
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
index 2a2111c..2ccb9a6 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
@@ -171,7 +171,8 @@
                     builder.setIpDst(IpPrefix.valueOf(di.getInt(),
                             di.asCidrMaskLength()));
                 } else {
-                    builder.setIpDst(IpPrefix.valueOf(di.getInt()));
+                    builder.setIpDst(IpPrefix.valueOf(di.getInt(),
+                                        IpPrefix.MAX_INET_MASK_LENGTH));
                 }
                 break;
             case SET_NW_SRC:
@@ -181,7 +182,8 @@
                     builder.setIpSrc(IpPrefix.valueOf(si.getInt(),
                             si.asCidrMaskLength()));
                 } else {
-                    builder.setIpSrc(IpPrefix.valueOf(si.getInt()));
+                    builder.setIpSrc(IpPrefix.valueOf(si.getInt(),
+                                        IpPrefix.MAX_INET_MASK_LENGTH));
                 }
                 break;
             case EXPERIMENTER:
@@ -256,7 +258,7 @@
                 } else {
                     dip = IpPrefix.valueOf(
                             match.get(MatchField.IPV4_DST).getInt(),
-                            IpPrefix.MAX_INET_MASK);
+                            IpPrefix.MAX_INET_MASK_LENGTH);
                 }
 
                 builder.matchIPDst(dip);
@@ -272,7 +274,7 @@
                 } else {
                     sip = IpPrefix.valueOf(
                             match.get(MatchField.IPV4_SRC).getInt(),
-                            IpPrefix.MAX_INET_MASK);
+                            IpPrefix.MAX_INET_MASK_LENGTH);
                 }
 
                 builder.matchIPSrc(sip);
diff --git a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
index e454a04..9dd97c3 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
@@ -15,147 +15,76 @@
  */
 package org.onlab.packet;
 
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 
-
-
 /**
  * A class representing an IPv4 address.
- * <p/>
- * TODO this class is a clone of IpPrefix and still needs to be modified to
- * look more like an IpAddress.
  */
 public final class IpAddress implements Comparable<IpAddress> {
-
-    // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
-
-    //IP Versions
+    // IP Versions
     public enum Version { INET, INET6 };
 
-    //lengths of address, in bytes
-    public static final int INET_LEN = 4;
-    public static final int INET6_LEN = 16;
+    // 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;
 
-    //maximum CIDR value
-    public static final int MAX_INET_MASK = 32;
-    //no mask (no network), e.g. a simple address
-    public static final int DEFAULT_MASK = 0;
+    private final Version version;
+    private final byte[] octets;
 
     /**
-     * Default value indicating an unspecified address.
+     * Constructor for given IP address version and address octets.
+     *
+     * @param ver the IP address version
+     * @param octets the IP address octets
      */
-    static final byte[] ANY = new byte [] {0, 0, 0, 0};
-
-    protected Version version;
-
-    protected byte[] octets;
-    protected int netmask;
-
-    private IpAddress(Version ver, byte[] octets, int netmask) {
-        this.version = ver;
-        this.octets = Arrays.copyOf(octets, INET_LEN);
-        this.netmask = netmask;
-    }
-
     private IpAddress(Version ver, byte[] octets) {
         this.version = ver;
-        this.octets = Arrays.copyOf(octets, INET_LEN);
-        this.netmask = DEFAULT_MASK;
+        this.octets = Arrays.copyOf(octets, INET_BYTE_LENGTH);
     }
 
     /**
      * Converts a byte array into an IP address.
      *
-     * @param address a byte array
+     * @param address 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 [] address) {
+    public static IpAddress valueOf(byte[] address) {
         return new IpAddress(Version.INET, address);
     }
 
     /**
-     * Converts a byte array into an IP address.
-     *
-     * @param address a byte array
-     * @param netmask the CIDR value subnet mask
-     * @return an IP address
-     */
-    public static IpAddress valueOf(byte [] address, int netmask) {
-        return new IpAddress(Version.INET, address, netmask);
-    }
-
-    /**
-     * Helper to convert an integer into a byte array.
-     *
-     * @param address the integer to convert
-     * @return a byte array
-     */
-    private static byte [] bytes(int address) {
-        byte [] bytes = new byte [INET_LEN];
-        for (int i = 0; i < INET_LEN; i++) {
-            bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
-        }
-
-        return bytes;
-    }
-
-    /**
      * Converts an integer into an IPv4 address.
      *
-     * @param address an integer representing an IP value
+     * @param address an integer representing an IPv4 value
      * @return an IP address
      */
     public static IpAddress valueOf(int address) {
-        return new IpAddress(Version.INET, bytes(address));
+        byte[] bytes =
+            ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(address).array();
+        return new IpAddress(Version.INET, bytes);
     }
 
     /**
-     * Converts an integer into an IPv4 address.
+     * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address.
      *
-     * @param address an integer representing an IP value
-     * @param netmask the CIDR value subnet mask
-     * @return an IP address
-     */
-    public static IpAddress valueOf(int address, int netmask) {
-        return new IpAddress(Version.INET, bytes(address), netmask);
-    }
-
-    /**
-     * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
-     * string can also be in CIDR (slash) notation. If the netmask is omitted,
-     * it will be set to DEFAULT_MASK (0).
-     *
-     * @param address a IP address in string form, e.g. "10.0.0.1", "10.0.0.1/24"
+     * @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 [] parts = address.split("\\/");
-        if (parts.length > 2) {
-            throw new IllegalArgumentException("Malformed IP address string; "
-                    + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
-        }
-
-        int mask = DEFAULT_MASK;
-        if (parts.length == 2) {
-            mask = Integer.parseInt(parts[1]);
-            if (mask > MAX_INET_MASK) {
-                throw new IllegalArgumentException(
-                        "Value of subnet mask cannot exceed "
-                                + MAX_INET_MASK);
-            }
-        }
-
-        final String [] net = parts[0].split("\\.");
-        if (net.length != INET_LEN) {
+        final String[] net = address.split("\\.");
+        if (net.length != INET_BYTE_LENGTH) {
             throw new IllegalArgumentException("Malformed IP address string; "
                     + "Address must have four decimal values separated by dots (.)");
         }
-        final byte [] bytes = new byte[INET_LEN];
-        for (int i = 0; i < INET_LEN; i++) {
+        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, mask);
+        return new IpAddress(Version.INET, bytes);
     }
 
     /**
@@ -173,16 +102,7 @@
      * @return a byte array
      */
     public byte[] toOctets() {
-        return Arrays.copyOf(this.octets, INET_LEN);
-    }
-
-    /**
-     * Returns the IP address prefix length.
-     *
-     * @return prefix length
-     */
-    public int prefixLength() {
-        return netmask;
+        return Arrays.copyOf(this.octets, INET_BYTE_LENGTH);
     }
 
     /**
@@ -191,110 +111,8 @@
      * @return the IP address's value as an integer
      */
     public int toInt() {
-        int val = 0;
-        for (int i = 0; i < octets.length; i++) {
-          val <<= 8;
-          val |= octets[i] & 0xff;
-        }
-        return val;
-    }
-
-    /**
-     * Converts the IP address to a /32 IP prefix.
-     *
-     * @return the new IP prefix
-     */
-    public IpPrefix toPrefix() {
-        return IpPrefix.valueOf(octets, MAX_INET_MASK);
-    }
-
-    /**
-     * Helper for computing the mask value from CIDR.
-     *
-     * @return an integer bitmask
-     */
-    private int mask() {
-        int shift = MAX_INET_MASK - this.netmask;
-        return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
-    }
-
-    /**
-     * Returns the subnet mask in IpAddress form. The netmask value for
-     * the returned IpAddress is 0, as the address itself is a mask.
-     *
-     * @return the subnet mask
-     */
-    public IpAddress netmask() {
-        return new IpAddress(Version.INET, bytes(mask()));
-    }
-
-    /**
-     * Returns the network portion of this address as an IpAddress.
-     * The netmask of the returned IpAddress is the current mask. If this
-     * address doesn't have a mask, this returns an all-0 IpAddress.
-     *
-     * @return the network address or null
-     */
-    public IpAddress network() {
-        if (netmask == DEFAULT_MASK) {
-            return new IpAddress(version, ANY, DEFAULT_MASK);
-        }
-
-        byte [] net = new byte [4];
-        byte [] mask = bytes(mask());
-        for (int i = 0; i < INET_LEN; i++) {
-            net[i] = (byte) (octets[i] & mask[i]);
-        }
-        return new IpAddress(version, net, netmask);
-    }
-
-    /**
-     * Returns the host portion of the IPAddress, as an IPAddress.
-     * The netmask of the returned IpAddress is the current mask. If this
-     * address doesn't have a mask, this returns a copy of the current
-     * address.
-     *
-     * @return the host address
-     */
-    public IpAddress host() {
-        if (netmask == DEFAULT_MASK) {
-            new IpAddress(version, octets, netmask);
-        }
-
-        byte [] host = new byte [INET_LEN];
-        byte [] mask = bytes(mask());
-        for (int i = 0; i < INET_LEN; i++) {
-            host[i] = (byte) (octets[i] & ~mask[i]);
-        }
-        return new IpAddress(version, host, netmask);
-    }
-
-    public boolean isMasked() {
-        return mask() != 0;
-    }
-
-    /**
-     * Determines whether a given address is contained within this IpAddress'
-     * network.
-     *
-     * @param other another IP address that could be contained in this network
-     * @return true if the other IP address is contained in this address'
-     * network, otherwise false
-     */
-    public boolean contains(IpAddress other) {
-        if (this.netmask <= other.netmask) {
-            // Special case where they're both /32 addresses
-            if (this.netmask == MAX_INET_MASK) {
-                return Arrays.equals(octets, other.octets);
-            }
-
-            // Mask the other address with our network mask
-            IpAddress otherMasked =
-                    IpAddress.valueOf(other.octets, netmask).network();
-
-            return network().equals(otherMasked);
-        }
-        return false;
+        ByteBuffer bb = ByteBuffer.wrap(octets);
+        return bb.getInt();
     }
 
     @Override
@@ -308,7 +126,6 @@
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + netmask;
         result = prime * result + Arrays.hashCode(octets);
         result = prime * result + ((version == null) ? 0 : version.hashCode());
         return result;
@@ -326,9 +143,6 @@
             return false;
         }
         IpAddress other = (IpAddress) obj;
-        if (netmask != other.netmask) {
-            return false;
-        }
         if (!Arrays.equals(octets, other.octets)) {
             return false;
         }
@@ -341,8 +155,7 @@
     @Override
     /*
      * (non-Javadoc)
-     * format is "x.x.x.x" for non-masked (netmask 0) addresses,
-     * and "x.x.x.x/y" for masked addresses.
+     * format is "x.x.x.x" for IPv4 addresses.
      *
      * @see java.lang.Object#toString()
      */
@@ -354,11 +167,6 @@
             }
             builder.append(String.format("%d", b & 0xff));
         }
-        if (netmask != DEFAULT_MASK) {
-            builder.append("/");
-            builder.append(String.format("%d", netmask));
-        }
         return builder.toString();
     }
-
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java b/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java
index 1a91568..e864125 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java
@@ -26,48 +26,37 @@
 
     // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
 
-    //IP Versions
+    // IP Versions: IPv4 and IPv6
     public enum Version { INET, INET6 };
 
-    //lengths of address, in bytes
-    public static final int INET_LEN = 4;
-    public static final int INET6_LEN = 16;
+    // 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;
 
-    //maximum CIDR value
-    public static final int MAX_INET_MASK = 32;
     //no mask (no network), e.g. a simple address
-    public static final int DEFAULT_MASK = 0;
+    private static final int DEFAULT_MASK = 0;
 
     /**
      * Default value indicating an unspecified address.
      */
-    static final byte[] ANY = new byte [] {0, 0, 0, 0};
+    private static final byte[] ANY = new byte[] {0, 0, 0, 0};
 
-    protected Version version;
-
-    protected byte[] octets;
-    protected int netmask;
-
-    private IpPrefix(Version ver, byte[] octets, int netmask) {
-        this.version = ver;
-        this.octets = Arrays.copyOf(octets, INET_LEN);
-        this.netmask = netmask;
-    }
-
-    private IpPrefix(Version ver, byte[] octets) {
-        this.version = ver;
-        this.octets = Arrays.copyOf(octets, INET_LEN);
-        this.netmask = DEFAULT_MASK;
-    }
+    private final Version version;
+    private final byte[] octets;
+    private final int netmask;
 
     /**
-     * Converts a byte array into an IP address.
+     * Constructor for given IP address version, prefix address octets,
+     * and network mask length.
      *
-     * @param address a byte array
-     * @return an IP address
+     * @param ver the IP address version
+     * @param octets the IP prefix address octets
+     * @param netmask the network mask length
      */
-    public static IpPrefix valueOf(byte [] address) {
-        return new IpPrefix(Version.INET, address);
+    private IpPrefix(Version ver, byte[] octets, int netmask) {
+        this.version = ver;
+        this.octets = Arrays.copyOf(octets, IpAddress.INET_BYTE_LENGTH);
+        this.netmask = netmask;
     }
 
     /**
@@ -77,7 +66,7 @@
      * @param netmask the CIDR value subnet mask
      * @return an IP address
      */
-    public static IpPrefix valueOf(byte [] address, int netmask) {
+    public static IpPrefix valueOf(byte[] address, int netmask) {
         return new IpPrefix(Version.INET, address, netmask);
     }
 
@@ -87,10 +76,11 @@
      * @param address the integer to convert
      * @return a byte array
      */
-    private static byte [] bytes(int address) {
-        byte [] bytes = new byte [INET_LEN];
-        for (int i = 0; i < INET_LEN; i++) {
-            bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
+    private static byte[] bytes(int address) {
+        byte[] bytes = new byte [IpAddress.INET_BYTE_LENGTH];
+        for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
+            bytes[i] = (byte) ((address >> (IpAddress.INET_BYTE_LENGTH
+                                            - (i + 1)) * 8) & 0xff);
         }
 
         return bytes;
@@ -100,16 +90,6 @@
      * Converts an integer into an IPv4 address.
      *
      * @param address an integer representing an IP value
-     * @return an IP address
-     */
-    public static IpPrefix valueOf(int address) {
-        return new IpPrefix(Version.INET, bytes(address));
-    }
-
-    /**
-     * Converts an integer into an IPv4 address.
-     *
-     * @param address an integer representing an IP value
      * @param netmask the CIDR value subnet mask
      * @return an IP address
      */
@@ -127,7 +107,7 @@
      */
     public static IpPrefix valueOf(String address) {
 
-        final String [] parts = address.split("\\/");
+        final String[] parts = address.split("\\/");
         if (parts.length > 2) {
             throw new IllegalArgumentException("Malformed IP address string; "
                     + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
@@ -136,20 +116,20 @@
         int mask = DEFAULT_MASK;
         if (parts.length == 2) {
             mask = Integer.parseInt(parts[1]);
-            if (mask > MAX_INET_MASK) {
+            if (mask > MAX_INET_MASK_LENGTH) {
                 throw new IllegalArgumentException(
                         "Value of subnet mask cannot exceed "
-                                + MAX_INET_MASK);
+                                + MAX_INET_MASK_LENGTH);
             }
         }
 
-        final String [] net = parts[0].split("\\.");
-        if (net.length != INET_LEN) {
+        final String[] net = parts[0].split("\\.");
+        if (net.length != IpAddress.INET_BYTE_LENGTH) {
             throw new IllegalArgumentException("Malformed IP address string; "
                     + "Address must have four decimal values separated by dots (.)");
         }
-        final byte [] bytes = new byte[INET_LEN];
-        for (int i = 0; i < INET_LEN; i++) {
+        final byte[] bytes = new byte[IpAddress.INET_BYTE_LENGTH];
+        for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
             bytes[i] = (byte) Short.parseShort(net[i], 10);
         }
         return new IpPrefix(Version.INET, bytes, mask);
@@ -170,7 +150,7 @@
      * @return a byte array
      */
     public byte[] toOctets() {
-        return Arrays.copyOf(this.octets, INET_LEN);
+        return Arrays.copyOf(this.octets, IpAddress.INET_BYTE_LENGTH);
     }
 
     /**
@@ -202,18 +182,17 @@
      * @return an integer bitmask
      */
     private int mask() {
-        int shift = MAX_INET_MASK - this.netmask;
+        int shift = MAX_INET_MASK_LENGTH - this.netmask;
         return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
     }
 
     /**
-     * Returns the subnet mask in IpAddress form. The netmask value for
-     * the returned IpAddress is 0, as the address itself is a mask.
+     * Returns the subnet mask in IpAddress form.
      *
-     * @return the subnet mask
+     * @return the subnet mask as an IpAddress
      */
-    public IpPrefix netmask() {
-        return new IpPrefix(Version.INET, bytes(mask()));
+    public IpAddress netmask() {
+        return IpAddress.valueOf(mask());
     }
 
     /**
@@ -228,9 +207,9 @@
             return new IpPrefix(version, ANY, DEFAULT_MASK);
         }
 
-        byte [] net = new byte [4];
-        byte [] mask = bytes(mask());
-        for (int i = 0; i < INET_LEN; i++) {
+        byte[] net = new byte [4];
+        byte[] mask = bytes(mask());
+        for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
             net[i] = (byte) (octets[i] & mask[i]);
         }
         return new IpPrefix(version, net, netmask);
@@ -249,9 +228,9 @@
             new IpPrefix(version, octets, netmask);
         }
 
-        byte [] host = new byte [INET_LEN];
-        byte [] mask = bytes(mask());
-        for (int i = 0; i < INET_LEN; i++) {
+        byte[] host = new byte [IpAddress.INET_BYTE_LENGTH];
+        byte[] mask = bytes(mask());
+        for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
             host[i] = (byte) (octets[i] & ~mask[i]);
         }
         return new IpPrefix(version, host, netmask);
@@ -283,7 +262,7 @@
     public boolean contains(IpPrefix other) {
         if (this.netmask <= other.netmask) {
             // Special case where they're both /32 addresses
-            if (this.netmask == MAX_INET_MASK) {
+            if (this.netmask == MAX_INET_MASK_LENGTH) {
                 return Arrays.equals(octets, other.octets);
             }
 
@@ -302,7 +281,7 @@
         IpPrefix meMasked = network();
 
         IpPrefix otherMasked =
-                IpPrefix.valueOf(address.octets, netmask).network();
+            IpPrefix.valueOf(address.toOctets(), netmask).network();
 
         return Arrays.equals(meMasked.octets, otherMasked.octets);
     }
@@ -364,5 +343,4 @@
         }
         return builder.toString();
     }
-
 }
diff --git a/utils/misc/src/test/java/org/onlab/packet/IpPrefixTest.java b/utils/misc/src/test/java/org/onlab/packet/IpPrefixTest.java
index 66471b3..90ebafd 100644
--- a/utils/misc/src/test/java/org/onlab/packet/IpPrefixTest.java
+++ b/utils/misc/src/test/java/org/onlab/packet/IpPrefixTest.java
@@ -32,15 +32,15 @@
     private static final byte [] BYTES2 = new byte [] {0xa, 0x0, 0x0, 0xb};
     private static final int INTVAL1 = 167772170;
     private static final int INTVAL2 = 167772171;
-    private static final String STRVAL = "10.0.0.12";
-    private static final int MASK = 16;
+    private static final String STRVAL = "10.0.0.12/16";
+    private static final int MASK_LENGTH = 16;
 
     @Test
     public void testEquality() {
-        IpPrefix ip1 = IpPrefix.valueOf(BYTES1);
-        IpPrefix ip2 = IpPrefix.valueOf(INTVAL1);
-        IpPrefix ip3 = IpPrefix.valueOf(BYTES2);
-        IpPrefix ip4 = IpPrefix.valueOf(INTVAL2);
+        IpPrefix ip1 = IpPrefix.valueOf(BYTES1, IpPrefix.MAX_INET_MASK_LENGTH);
+        IpPrefix ip2 = IpPrefix.valueOf(INTVAL1, IpPrefix.MAX_INET_MASK_LENGTH);
+        IpPrefix ip3 = IpPrefix.valueOf(BYTES2, IpPrefix.MAX_INET_MASK_LENGTH);
+        IpPrefix ip4 = IpPrefix.valueOf(INTVAL2, IpPrefix.MAX_INET_MASK_LENGTH);
         IpPrefix ip5 = IpPrefix.valueOf(STRVAL);
 
         new EqualsTester().addEqualityGroup(ip1, ip2)
@@ -49,21 +49,21 @@
         .testEquals();
 
         // string conversions
-        IpPrefix ip6 = IpPrefix.valueOf(BYTES1, MASK);
+        IpPrefix ip6 = IpPrefix.valueOf(BYTES1, MASK_LENGTH);
         IpPrefix ip7 = IpPrefix.valueOf("10.0.0.10/16");
-        IpPrefix ip8 = IpPrefix.valueOf(new byte [] {0xa, 0x0, 0x0, 0xc});
+        IpPrefix ip8 = IpPrefix.valueOf(new byte [] {0xa, 0x0, 0x0, 0xc}, 16);
         assertEquals("incorrect address conversion", ip6, ip7);
         assertEquals("incorrect address conversion", ip5, ip8);
     }
 
     @Test
     public void basics() {
-        IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK);
+        IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK_LENGTH);
         final byte [] bytes = new byte [] {0xa, 0x0, 0x0, 0xa};
 
         //check fields
         assertEquals("incorrect IP Version", Version.INET, ip1.version());
-        assertEquals("incorrect netmask", 16, ip1.netmask);
+        assertEquals("incorrect netmask", 16, ip1.prefixLength());
         assertTrue("faulty toOctets()", Arrays.equals(bytes, ip1.toOctets()));
         assertEquals("faulty toInt()", INTVAL1, ip1.toInt());
         assertEquals("faulty toString()", "10.0.0.10/16", ip1.toString());
@@ -72,7 +72,7 @@
     @Test
     public void netmasks() {
         // masked
-        IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK);
+        IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK_LENGTH);
 
         IpPrefix host = IpPrefix.valueOf("0.0.0.10/16");
         IpPrefix network = IpPrefix.valueOf("10.0.0.0/16");
@@ -80,14 +80,6 @@
         assertEquals("incorrect network address", network, ip1.network());
         assertEquals("incorrect netmask", "255.255.0.0", ip1.netmask().toString());
 
-        //unmasked
-        IpPrefix ip2 = IpPrefix.valueOf(BYTES1);
-        IpPrefix umhost = IpPrefix.valueOf("10.0.0.10/0");
-        IpPrefix umnet = IpPrefix.valueOf("0.0.0.0/0");
-        assertEquals("incorrect host address", umhost, ip2.host());
-        assertEquals("incorrect host address", umnet, ip2.network());
-        assertTrue("incorrect netmask",
-                Arrays.equals(IpPrefix.ANY, ip2.netmask().toOctets()));
     }
 
     @Test