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/cluster/impl/MastershipManager.java b/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
index 6180ada..0989867 100644
--- a/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
+++ b/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
@@ -269,10 +269,6 @@
 
         @Override
         public void notify(MastershipEvent event) {
-            if (clusterService.getLocalNode().id().equals(event.roleInfo().master())) {
-                log.info("ignoring locally-generated event {}", event);
-               // return;
-            }
             log.info("dispatching mastership event {}", event);
             eventDispatcher.post(event);
         }
diff --git a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
index 2441e88..e163dc5 100644
--- a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
@@ -432,7 +432,6 @@
                     if (!isReachable(device)) {
                         log.warn("Device {} has disconnected after this event", did);
                         mastershipService.relinquishMastership(did);
-                        applyRole(did, MastershipRole.STANDBY);
                         return;
                     }
                     //flag the device as online. Is there a better way to do this?
@@ -448,6 +447,7 @@
                 if (!isReachable(getDevice(did))) {
                     log.warn("Device {} has disconnected after this event", did);
                     mastershipService.relinquishMastership(did);
+                    return;
                 }
                 applyRole(did, MastershipRole.STANDBY);
             }
@@ -455,19 +455,21 @@
 
         // checks for duplicate event, returning true if one is found.
         private boolean checkDuplicate(RoleInfo roleInfo, int term) {
-            synchronized (eventCache) {
-                if (eventCache.get(term).contains(roleInfo)) {
-                    log.info("duplicate event detected; ignoring");
-                    return true;
-                } else {
-                    eventCache.put(term, roleInfo);
-                    // purge by-term oldest entries to keep the cache size under limit
-                    if (eventCache.size() > cacheSize) {
-                        eventCache.removeAll(term - cacheSize);
-                    }
-                    return false;
-                }
-            }
+            // turning off duplicate check
+            return false;
+//            synchronized (eventCache) {
+//                if (eventCache.get(term).contains(roleInfo)) {
+//                    log.info("duplicate event detected; ignoring");
+//                    return true;
+//                } else {
+//                    eventCache.put(term, roleInfo);
+//                    // purge by-term oldest entries to keep the cache size under limit
+//                    if (eventCache.size() > cacheSize) {
+//                        eventCache.removeAll(term - cacheSize);
+//                    }
+//                    return false;
+//                }
+//            }
         }
 
     }
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/mastership/impl/DistributedMastershipStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
index d1917d6..07120fd 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
@@ -358,6 +358,7 @@
 
         @Override
         public void entryAdded(EntryEvent<DeviceId, RoleValue> event) {
+            entryUpdated(event);
         }
 
         @Override
@@ -366,7 +367,6 @@
 
         @Override
         public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) {
-            // this subsumes entryAdded event
             notifyDelegate(new MastershipEvent(
                     MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
         }
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/lldp/src/main/java/org/onlab/onos/provider/lldp/impl/LLDPLinkProvider.java b/providers/lldp/src/main/java/org/onlab/onos/provider/lldp/impl/LLDPLinkProvider.java
index 50dceb3..24336aa 100644
--- a/providers/lldp/src/main/java/org/onlab/onos/provider/lldp/impl/LLDPLinkProvider.java
+++ b/providers/lldp/src/main/java/org/onlab/onos/provider/lldp/impl/LLDPLinkProvider.java
@@ -145,7 +145,7 @@
                     break;
                 case PORT_ADDED:
                 case PORT_UPDATED:
-                    if (event.port().isEnabled()) {
+                    if (port.isEnabled()) {
                         ld = discoverers.get(device.id());
                         if (ld == null) {
                             return;
@@ -155,6 +155,7 @@
                             ld.addPort(port);
                         }
                     } else {
+                        log.debug("Port down {}", port);
                         ConnectPoint point = new ConnectPoint(device.id(),
                                                               port.number());
                         providerService.linksVanished(point);
diff --git a/providers/lldp/src/main/java/org/onlab/onos/provider/lldp/impl/LinkDiscovery.java b/providers/lldp/src/main/java/org/onlab/onos/provider/lldp/impl/LinkDiscovery.java
index dd72420..07485c0 100644
--- a/providers/lldp/src/main/java/org/onlab/onos/provider/lldp/impl/LinkDiscovery.java
+++ b/providers/lldp/src/main/java/org/onlab/onos/provider/lldp/impl/LinkDiscovery.java
@@ -68,6 +68,7 @@
     // send 1 probe every probeRate milliseconds
     private final long probeRate;
     private final Set<Long> slowPorts;
+    // ports, known to have incoming links
     private final Set<Long> fastPorts;
     // number of unacknowledged probes per port
     private final Map<Long, AtomicInteger> portProbeCount;
@@ -125,6 +126,7 @@
             log.info("Using BDDP to discover network");
         }
 
+        this.isStopped = true;
         start();
         this.log.debug("Started discovery manager for switch {}",
                        device.id());
@@ -140,7 +142,10 @@
     public void addPort(final Port port) {
         this.log.debug("Sending init probe to port {}@{}",
                        port.number().toLong(), device.id());
-        sendProbes(port.number().toLong());
+        boolean isMaster = mastershipService.getLocalRole(device.id()) == MASTER;
+        if (isMaster) {
+            sendProbes(port.number().toLong());
+        }
         synchronized (this) {
             this.slowPorts.add(port.number().toLong());
         }
@@ -233,6 +238,13 @@
      */
     @Override
     public void run(final Timeout t) {
+        boolean isMaster = mastershipService.getLocalRole(device.id()) == MASTER;
+        if (!isMaster) {
+            // reschedule timer
+            timeout = Timer.getTimer().newTimeout(this, this.probeRate, MILLISECONDS);
+            return;
+        }
+
         this.log.trace("Sending probes from {}", device.id());
         synchronized (this) {
             final Iterator<Long> fastIterator = this.fastPorts.iterator();
@@ -245,6 +257,7 @@
                     sendProbes(portNumber);
 
                 } else {
+                    // Link down, demote to slowPorts
                     // Update fast and slow ports
                     fastIterator.remove();
                     this.slowPorts.add(portNumber);
@@ -274,8 +287,12 @@
     }
 
     public void start() {
-        timeout = Timer.getTimer().newTimeout(this, 0, MILLISECONDS);
-        isStopped = false;
+        if (isStopped) {
+            timeout = Timer.getTimer().newTimeout(this, 0, MILLISECONDS);
+            isStopped = false;
+        } else {
+            log.warn("LinkDiscovery started multiple times?");
+        }
     }
 
     /**
@@ -317,8 +334,8 @@
     }
 
     private void sendProbes(Long portNumber) {
-        boolean isMaster = mastershipService.getLocalRole(device.id()) == MASTER;
-        if (isMaster && device.type() != Device.Type.ROADM) {
+        // TODO: should have suppression port configuration, not by type
+        if (device.type() != Device.Type.ROADM) {
             log.debug("Sending probes out to {}@{}", portNumber, device.id());
             OutboundPacket pkt = this.createOutBoundLLDP(portNumber);
             pktService.emit(pkt);
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/tools/dev/bash_profile b/tools/dev/bash_profile
index b2f61f2..8d4a784 100644
--- a/tools/dev/bash_profile
+++ b/tools/dev/bash_profile
@@ -8,7 +8,7 @@
 # Setup some environmental context for developers
 if [ -z "${JAVA_HOME}" ]; then
     if [ -x /usr/libexec/java_home ]; then
-        export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
+        export JAVA_HOME=$(/usr/libexec/java_home -v 1.7)
     elif [ -d /usr/lib/jvm/java-7-openjdk-amd64 ]; then
         export JAVA_HOME="/usr/lib/jvm/java-7-openjdk-amd64"
     fi
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java b/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java
index b32cbba..e3b5246 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java
@@ -101,20 +101,6 @@
         return this.address.toString() + "/" + this.prefixLen;
     }
 
-    /**
-     * Compares the value of two Ip4Prefix objects.
-     * <p/>
-     * Note the value of the IPv4 address is compared directly between the
-     * objects, and must match exactly for the objects to be considered equal.
-     * This may result in objects which represent the same IP prefix being
-     * classified as unequal, because the unsignificant bits of the address
-     * field don't match (the bits to the right of the prefix length).
-     * <p/>
-     * TODO Change this behavior so that objects that represent the same prefix
-     * are classified as equal according to this equals method.
-     *
-     * @see Object#equals(Object)
-     */
     @Override
     public boolean equals(Object other) {
         if (other == this) {
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java b/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java
index 9603b68..5422ae1 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java
@@ -101,20 +101,6 @@
         return this.address.toString() + "/" + this.prefixLen;
     }
 
-    /**
-     * Compares the value of two Ip6Prefix objects.
-     * <p/>
-     * Note the value of the IPv6 address is compared directly between the
-     * objects, and must match exactly for the objects to be considered equal.
-     * This may result in objects which represent the same IP prefix being
-     * classified as unequal, because the unsignificant bits of the address
-     * field don't match (the bits to the right of the prefix length).
-     * <p/>
-     * TODO Change this behavior so that objects that represent the same prefix
-     * are classified as equal according to this equals method.
-     *
-     * @see Object#equals(Object)
-     */
     @Override
     public boolean equals(Object other) {
         if (other == this) {
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..eead723 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,112 @@
  */
 package org.onlab.packet;
 
+import java.nio.ByteBuffer;
 import java.util.Arrays;
-
-
+import java.util.Objects;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * A class representing an IPv4 address.
- * <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 value the IP address value stored in network byte order
+     * (i.e., the most significant byte first)
+     * @param value the IP address value
      */
-    static final byte[] ANY = new byte [] {0, 0, 0, 0};
+    private IpAddress(Version version, byte[] value) {
+        checkNotNull(value);
 
-    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;
+        this.version = version;
+        this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH);
     }
 
-    private IpAddress(Version ver, byte[] octets) {
-        this.version = ver;
-        this.octets = Arrays.copyOf(octets, INET_LEN);
-        this.netmask = DEFAULT_MASK;
+    /**
+     * Converts an integer into an IPv4 address.
+     *
+     * @param value an integer representing an IPv4 value
+     * @return an IP address
+     */
+    public static IpAddress valueOf(int value) {
+        byte[] bytes =
+            ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array();
+        return new IpAddress(Version.INET, bytes);
     }
 
     /**
      * Converts a byte array into an IP address.
      *
-     * @param address a byte array
+     * @param value the IP address value stored in network byte order
+     * (i.e., the most significant byte first)
      * @return an IP address
      */
-    public static IpAddress valueOf(byte [] address) {
-        return new IpAddress(Version.INET, address);
+    public static IpAddress valueOf(byte[] value) {
+        return new IpAddress(Version.INET, value);
     }
 
     /**
-     * Converts a byte array into an IP address.
+     * Converts a byte array and a given offset from the beginning of the
+     * array into an IP address.
+     * <p/>
+     * The IP address is stored in network byte order (i.e., the most
+     * significant byte first).
      *
-     * @param address a byte array
-     * @param netmask the CIDR value subnet mask
+     * @param value the value to use
+     * @param offset the offset in bytes from the beginning of the byte array
      * @return an IP address
      */
-    public static IpAddress valueOf(byte [] 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);
+    public static IpAddress valueOf(byte[] value, int offset) {
+        // Verify the arguments
+        if ((offset < 0) || (offset + INET_BYTE_LENGTH > value.length)) {
+            String msg;
+            if (value.length < INET_BYTE_LENGTH) {
+                msg = "Invalid IPv4 address array: array length: " +
+                    value.length + ". Must be at least " + INET_BYTE_LENGTH;
+            } else {
+                msg = "Invalid IPv4 address array: array offset: " +
+                    offset + ". Must be in the interval [0, " +
+                    (value.length - INET_BYTE_LENGTH) + "]";
+            }
+            throw new IllegalArgumentException(msg);
         }
 
-        return bytes;
+        byte[] bc = Arrays.copyOfRange(value, offset, value.length);
+        return IpAddress.valueOf(bc);
     }
 
     /**
-     * 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
-     * @return an IP address
-     */
-    public static IpAddress valueOf(int address) {
-        return new IpAddress(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
-     */
-    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\"");
+        final String[] net = address.split("\\.");
+        if (net.length != INET_BYTE_LENGTH) {
+            String msg = "Malformed IPv4 address string; " +
+                "Address must have four decimal values separated by dots (.)";
+            throw new IllegalArgumentException(msg);
         }
-
-        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) {
-            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 +138,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 +147,50 @@
      * @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;
+        ByteBuffer bb = ByteBuffer.wrap(octets);
+        return bb.getInt();
     }
 
     /**
-     * Converts the IP address to a /32 IP prefix.
+     * Creates an IP network mask prefix.
      *
-     * @return the new IP prefix
+     * @param prefixLen the length of the mask prefix. Must be in the interval
+     * [0, 32] for IPv4
+     * @return a new IP address that contains a mask prefix of the
+     * specified length
      */
-    public IpPrefix toPrefix() {
-        return IpPrefix.valueOf(octets, MAX_INET_MASK);
+    public static IpAddress makeMaskPrefix(int prefixLen) {
+        // Verify the prefix length
+        if ((prefixLen < 0) || (prefixLen > INET_BIT_LENGTH)) {
+            final String msg = "Invalid IPv4 prefix length: " + prefixLen +
+                ". Must be in the interval [0, 32].";
+            throw new IllegalArgumentException(msg);
+        }
+
+        long v = (0xffffffffL << (INET_BIT_LENGTH - prefixLen)) & 0xffffffffL;
+        return IpAddress.valueOf((int) v);
     }
 
     /**
-     * Helper for computing the mask value from CIDR.
+     * Creates an IP address by masking it with a network mask of given
+     * mask length.
      *
-     * @return an integer bitmask
+     * @param addr the address to mask
+     * @param prefixLen the length of the mask prefix. Must be in the interval
+     * [0, 32] for IPv4
+     * @return a new IP address that is masked with a mask prefix of the
+     * specified length
      */
-    private int mask() {
-        int shift = MAX_INET_MASK - this.netmask;
-        return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
-    }
+    public static IpAddress makeMaskedAddress(final IpAddress addr,
+                                              int prefixLen) {
+        IpAddress mask = IpAddress.makeMaskPrefix(prefixLen);
+        byte[] net = new byte[INET_BYTE_LENGTH];
 
-    /**
-     * 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);
+        // Mask each byte
+        for (int i = 0; i < INET_BYTE_LENGTH; i++) {
+            net[i] = (byte) (addr.octets[i] & mask.octets[i]);
         }
-
-        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;
+        return IpAddress.valueOf(net);
     }
 
     @Override
@@ -306,43 +202,26 @@
 
     @Override
     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;
+        return Objects.hash(version, octets);
     }
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj) {
+        if (obj == this) {
             return true;
         }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
+        if ((obj == null) || (getClass() != obj.getClass())) {
             return false;
         }
         IpAddress other = (IpAddress) obj;
-        if (netmask != other.netmask) {
-            return false;
-        }
-        if (!Arrays.equals(octets, other.octets)) {
-            return false;
-        }
-        if (version != other.version) {
-            return false;
-        }
-        return true;
+        return (version == other.version) &&
+            Arrays.equals(octets, other.octets);
     }
 
     @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 +233,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
diff --git a/utils/netty/src/main/java/org/onlab/netty/NettyMessagingService.java b/utils/netty/src/main/java/org/onlab/netty/NettyMessagingService.java
index 9fe62db..54b02de 100644
--- a/utils/netty/src/main/java/org/onlab/netty/NettyMessagingService.java
+++ b/utils/netty/src/main/java/org/onlab/netty/NettyMessagingService.java
@@ -20,6 +20,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicLong;
 
 import io.netty.bootstrap.Bootstrap;
@@ -27,6 +28,7 @@
 import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInitializer;
@@ -49,6 +51,8 @@
 
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.RemovalListener;
+import com.google.common.cache.RemovalNotification;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
 
@@ -64,8 +68,13 @@
     private final AtomicLong messageIdGenerator = new AtomicLong(0);
     private final Cache<Long, SettableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder()
             .maximumSize(100000)
-            // TODO: Once the entry expires, notify blocking threads (if any).
-            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .expireAfterWrite(10, TimeUnit.SECONDS)
+            .removalListener(new RemovalListener<Long, SettableFuture<byte[]>>() {
+                @Override
+                public void onRemoval(RemovalNotification<Long, SettableFuture<byte[]>> entry) {
+                    entry.getValue().setException(new TimeoutException("Timedout waiting for reply"));
+                }
+            })
             .build();
     private final GenericKeyedObjectPool<Endpoint, Channel> channels
             = new GenericKeyedObjectPool<Endpoint, Channel>(new OnosCommunicationChannelFactory());
@@ -153,9 +162,12 @@
             } finally {
                 channels.returnObject(ep, channel);
             }
+        } catch (IOException e) {
+            throw e;
         } catch (Exception e) {
-            throw new IOException("Failed to send message to " + ep.toString(), e);
+            throw new IOException(e);
         }
+
     }
 
     @Override
@@ -172,7 +184,7 @@
             .build();
         try {
             sendAsync(ep, message);
-        } catch (IOException e) {
+        } catch (Exception e) {
             responseFutures.invalidate(messageId);
             throw e;
         }
@@ -277,7 +289,7 @@
 
         @Override
         public void run() {
-            channel.writeAndFlush(message, channel.voidPromise());
+            channel.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
         }
     }