Work toward common IP address classes.

 * Updated classes PortAddresses (in core/api) and Interface (in sdnip)
   to use class InterfaceIpAddress instead of IpPrefix
 * Updated corresponding unit tests and relevant code
 * Minor refactoring inside ProxyArpManager to simplify some of the
   logic and usage related to PortAddresses. Also, renamed
   method findOutsidePortInSubnet() to findPortInSubnet() and updated
   its implementation to reflect better its usage.
diff --git a/apps/config/src/main/java/org/onlab/onos/config/NetworkConfigReader.java b/apps/config/src/main/java/org/onlab/onos/config/NetworkConfigReader.java
index 8b1e1ce..a99fb53 100644
--- a/apps/config/src/main/java/org/onlab/onos/config/NetworkConfigReader.java
+++ b/apps/config/src/main/java/org/onlab/onos/config/NetworkConfigReader.java
@@ -35,8 +35,11 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.PortNumber;
 import org.onlab.onos.net.host.HostAdminService;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
+import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.MacAddress;
 import org.slf4j.Logger;
 
@@ -72,12 +75,25 @@
                         DeviceId.deviceId(dpidToUri(entry.getDpid())),
                         PortNumber.portNumber(entry.getPortNumber()));
 
-                Set<IpPrefix> ipAddresses = new HashSet<IpPrefix>();
+                Set<InterfaceIpAddress> interfaceIpAddresses = new HashSet<>();
 
                 for (String strIp : entry.getIpAddresses()) {
+                    // Get the IP address and the subnet mask length
                     try {
-                        IpPrefix address = IpPrefix.valueOf(strIp);
-                        ipAddresses.add(address);
+                        String[] splits = strIp.split("/");
+                        if (splits.length != 2) {
+                            throw new IllegalArgumentException("Invalid IP address and prefix length format");
+                        }
+                        //
+                        // TODO: For now we need Ip4Prefix to mask-out the
+                        // subnet address.
+                        //
+                        Ip4Prefix subnet4 = new Ip4Prefix(strIp);
+                        IpPrefix subnet = IpPrefix.valueOf(subnet4.toString());
+                        IpAddress addr = IpAddress.valueOf(splits[0]);
+                        InterfaceIpAddress ia =
+                            new InterfaceIpAddress(addr, subnet);
+                        interfaceIpAddresses.add(ia);
                     } catch (IllegalArgumentException e) {
                         log.warn("Bad format for IP address in config: {}", strIp);
                     }
@@ -94,7 +110,7 @@
                 }
 
                 PortAddresses addresses = new PortAddresses(cp,
-                        ipAddresses, macAddress);
+                        interfaceIpAddresses, macAddress);
 
                 hostAdminService.bindAddressesToPort(addresses);
             }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostToInterfaceAdaptor.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostToInterfaceAdaptor.java
index 5dc2d1f..a02ce27 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostToInterfaceAdaptor.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostToInterfaceAdaptor.java
@@ -24,10 +24,10 @@
 
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.sdnip.config.Interface;
 import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
 
 import com.google.common.collect.Sets;
 
@@ -59,7 +59,7 @@
         PortAddresses portAddresses =
                 hostService.getAddressBindingsForPort(connectPoint);
 
-        if (!portAddresses.ips().isEmpty()) {
+        if (!portAddresses.ipAddresses().isEmpty()) {
             return new Interface(portAddresses);
         }
 
@@ -71,8 +71,8 @@
         checkNotNull(ipAddress);
 
         for (PortAddresses portAddresses : hostService.getAddressBindings()) {
-            for (IpPrefix p : portAddresses.ips()) {
-                if (p.contains(ipAddress)) {
+            for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
+                if (ia.subnetAddress().contains(ipAddress)) {
                     return new Interface(portAddresses);
                 }
             }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/Interface.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/Interface.java
index 52c4cde..829cffa 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/Interface.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/Interface.java
@@ -22,8 +22,8 @@
 import java.util.Set;
 
 import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
-import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 
 import com.google.common.base.MoreObjects;
@@ -35,21 +35,22 @@
  */
 public class Interface {
     private final ConnectPoint connectPoint;
-    private final Set<IpPrefix> ipAddresses;
+    private final Set<InterfaceIpAddress> ipAddresses;
     private final MacAddress macAddress;
 
     /**
-     * Creates an Interface based on a connection point, a set of IP addresses
-     * and a MAC address.
+     * Creates an Interface based on a connection point, a set of interface
+     * IP addresses, and a MAC address.
      *
      * @param connectPoint the connect point this interface is mapped to
-     * @param prefixAddress the IP addresses for the interface
+     * @param ipAddresses the IP addresses for the interface
      * @param macAddress the MAC address of the interface
      */
-    public Interface(ConnectPoint connectPoint, Set<IpPrefix> prefixAddress,
+    public Interface(ConnectPoint connectPoint,
+                     Set<InterfaceIpAddress> ipAddresses,
                      MacAddress macAddress) {
         this.connectPoint = connectPoint;
-        this.ipAddresses = Sets.newHashSet(prefixAddress);
+        this.ipAddresses = Sets.newHashSet(ipAddresses);
         this.macAddress = macAddress;
     }
 
@@ -60,7 +61,7 @@
      */
     public Interface(PortAddresses portAddresses) {
         connectPoint = portAddresses.connectPoint();
-        ipAddresses = Sets.newHashSet(portAddresses.ips());
+        ipAddresses = Sets.newHashSet(portAddresses.ipAddresses());
         macAddress = portAddresses.mac();
     }
 
@@ -76,9 +77,9 @@
     /**
      * Retrieves the set of IP addresses that are assigned to the interface.
      *
-     * @return the set of IP addresses
+     * @return the set of interface IP addresses
      */
-   public Set<IpPrefix> ips() {
+   public Set<InterfaceIpAddress> ipAddresses() {
         return ipAddresses;
     }
 
diff --git a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/HostToInterfaceAdaptorTest.java b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/HostToInterfaceAdaptorTest.java
index e9a8420..a42cd87 100644
--- a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/HostToInterfaceAdaptorTest.java
+++ b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/HostToInterfaceAdaptorTest.java
@@ -35,6 +35,7 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.PortNumber;
 import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.sdnip.config.Interface;
 import org.onlab.packet.IpAddress;
@@ -76,20 +77,33 @@
         portAddresses = Sets.newHashSet();
         interfaces = Maps.newHashMap();
 
+        InterfaceIpAddress ia11 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.1.1"),
+                                   IpPrefix.valueOf("192.168.1.0/24"));
         createPortAddressesAndInterface(CP1,
-                Sets.newHashSet(IpPrefix.valueOf("192.168.1.1/24")),
+                Sets.newHashSet(ia11),
                 MacAddress.valueOf("00:00:00:00:00:01"));
 
         // Two addresses in the same subnet
+        InterfaceIpAddress ia21 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.2.1"),
+                                   IpPrefix.valueOf("192.168.2.0/24"));
+        InterfaceIpAddress ia22 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.2.2"),
+                                   IpPrefix.valueOf("192.168.2.0/24"));
         createPortAddressesAndInterface(CP2,
-                Sets.newHashSet(IpPrefix.valueOf("192.168.2.1/24"),
-                        IpPrefix.valueOf("192.168.2.2/24")),
+                Sets.newHashSet(ia21, ia22),
                 MacAddress.valueOf("00:00:00:00:00:02"));
 
         // Two addresses in different subnets
+        InterfaceIpAddress ia31 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.3.1"),
+                                   IpPrefix.valueOf("192.168.3.0/24"));
+        InterfaceIpAddress ia41 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.4.1"),
+                                   IpPrefix.valueOf("192.168.4.0/24"));
         createPortAddressesAndInterface(CP3,
-                Sets.newHashSet(IpPrefix.valueOf("192.168.3.1/24"),
-                        IpPrefix.valueOf("192.168.4.1/24")),
+                Sets.newHashSet(ia31, ia41),
                 MacAddress.valueOf("00:00:00:00:00:03"));
 
         expect(hostService.getAddressBindings()).andReturn(portAddresses).anyTimes();
@@ -104,16 +118,17 @@
      * places them in the correct global data stores.
      *
      * @param cp the connect point
-     * @param ips the set of IP addresses
+     * @param ipAddresses the set of interface IP addresses
      * @param mac the MAC address
      */
     private void createPortAddressesAndInterface(
-            ConnectPoint cp, Set<IpPrefix> ips, MacAddress mac) {
-        PortAddresses pa = new PortAddresses(cp, ips, mac);
+            ConnectPoint cp, Set<InterfaceIpAddress> ipAddresses,
+            MacAddress mac) {
+        PortAddresses pa = new PortAddresses(cp, ipAddresses, mac);
         portAddresses.add(pa);
         expect(hostService.getAddressBindingsForPort(cp)).andReturn(pa).anyTimes();
 
-        Interface intf = new Interface(cp, ips, mac);
+        Interface intf = new Interface(cp, ipAddresses, mac);
         interfaces.put(cp, intf);
     }
 
diff --git a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/PeerConnectivityManagerTest.java b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/PeerConnectivityManagerTest.java
index e3e4896..832989f 100644
--- a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/PeerConnectivityManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/PeerConnectivityManagerTest.java
@@ -31,6 +31,7 @@
 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.onos.sdnip.bgp.BgpConstants;
@@ -175,14 +176,20 @@
         configuredInterfaces = new HashMap<>();
 
         String interfaceSw1Eth1 = "s1-eth1";
+        InterfaceIpAddress ia1 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.10.1"),
+                                   IpPrefix.valueOf("192.168.10.0/24"));
         Interface intfsw1eth1 = new Interface(s1Eth1,
-                Collections.singleton(IpPrefix.valueOf("192.168.10.0/24")),
+                Collections.singleton(ia1),
                 MacAddress.valueOf("00:00:00:00:00:01"));
 
         configuredInterfaces.put(interfaceSw1Eth1, intfsw1eth1);
         String interfaceSw2Eth1 = "s2-eth1";
+        InterfaceIpAddress ia2 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.20.2"),
+                                   IpPrefix.valueOf("192.168.20.0/24"));
         Interface intfsw2eth1 = new Interface(s2Eth1,
-                Collections.singleton(IpPrefix.valueOf("192.168.20.0/24")),
+                Collections.singleton(ia2),
                 MacAddress.valueOf("00:00:00:00:00:02"));
         configuredInterfaces.put(interfaceSw2Eth1, intfsw2eth1);
 
diff --git a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/RouterTest.java b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/RouterTest.java
index add4f79..6d77a2c 100644
--- a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/RouterTest.java
+++ b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/RouterTest.java
@@ -51,6 +51,7 @@
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.host.HostListener;
 import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
 import org.onlab.onos.net.provider.ProviderId;
@@ -150,22 +151,31 @@
 
         Set<Interface> interfaces = Sets.newHashSet();
 
+        InterfaceIpAddress ia1 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.10.101"),
+                                   IpPrefix.valueOf("192.168.10.0/24"));
         Interface sw1Eth1 = new Interface(SW1_ETH1,
-                Sets.newHashSet(IpPrefix.valueOf("192.168.10.101/24")),
+                Sets.newHashSet(ia1),
                 MacAddress.valueOf("00:00:00:00:00:01"));
 
         expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
         interfaces.add(sw1Eth1);
 
+        InterfaceIpAddress ia2 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"),
+                                   IpPrefix.valueOf("192.168.20.0/24"));
         Interface sw2Eth1 = new Interface(SW2_ETH1,
-                Sets.newHashSet(IpPrefix.valueOf("192.168.20.101/24")),
+                Sets.newHashSet(ia2),
                 MacAddress.valueOf("00:00:00:00:00:02"));
 
         expect(interfaceService.getInterface(SW2_ETH1)).andReturn(sw2Eth1).anyTimes();
         interfaces.add(sw2Eth1);
 
+        InterfaceIpAddress ia3 =
+            new InterfaceIpAddress(IpAddress.valueOf("192.168.30.101"),
+                                   IpPrefix.valueOf("192.168.30.0/24"));
         Interface sw3Eth1 = new Interface(SW3_ETH1,
-                Sets.newHashSet(IpPrefix.valueOf("192.168.30.101/24")),
+                Sets.newHashSet(ia3),
                 MacAddress.valueOf("00:00:00:00:00:03"));
 
         expect(interfaceService.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
diff --git a/core/api/src/main/java/org/onlab/onos/net/host/PortAddresses.java b/core/api/src/main/java/org/onlab/onos/net/host/PortAddresses.java
index 4804daf..b6d1239 100644
--- a/core/api/src/main/java/org/onlab/onos/net/host/PortAddresses.java
+++ b/core/api/src/main/java/org/onlab/onos/net/host/PortAddresses.java
@@ -6,7 +6,6 @@
 import java.util.Set;
 
 import org.onlab.onos.net.ConnectPoint;
-import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 
 import com.google.common.base.MoreObjects;
@@ -17,24 +16,25 @@
 public class PortAddresses {
 
     private final ConnectPoint connectPoint;
-    // TODO: Should this be IpAddress or IpPrefix?
-    private final Set<IpPrefix> ipAddresses;
+    private final Set<InterfaceIpAddress> ipAddresses;
     private final MacAddress macAddress;
 
     /**
-     * Constructs a PortAddress object for the given connection point, with a
+     * Constructs a PortAddresses object for the given connection point, with a
      * set of IP addresses and a MAC address.
      * <p/>
      * Both address parameters are optional and can be set to null.
      *
      * @param connectPoint the connection point these addresses are for
-     * @param ips a set of IP addresses
+     * @param ipAddresses a set of interface IP addresses
      * @param mac a MAC address
      */
     public PortAddresses(ConnectPoint connectPoint,
-            Set<IpPrefix> ips, MacAddress mac) {
+            Set<InterfaceIpAddress> ipAddresses, MacAddress mac) {
         this.connectPoint = connectPoint;
-        this.ipAddresses = (ips == null) ? Collections.<IpPrefix>emptySet() : new HashSet<>(ips);
+        this.ipAddresses = (ipAddresses == null) ?
+            Collections.<InterfaceIpAddress>emptySet()
+            : new HashSet<>(ipAddresses);
         this.macAddress = mac;
     }
 
@@ -48,11 +48,11 @@
     }
 
     /**
-     * Returns the set of IP addresses.
+     * Returns the set of interface IP addresses.
      *
-     * @return the IP addresses
+     * @return the interface IP addresses
      */
-    public Set<IpPrefix> ips() {
+    public Set<InterfaceIpAddress> ipAddresses() {
         return ipAddresses;
     }
 
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 0b3b2cb..a624c07 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
@@ -22,6 +22,7 @@
 import org.onlab.onos.net.flow.instructions.Instruction;
 import org.onlab.onos.net.flow.instructions.Instructions;
 import org.onlab.onos.net.host.HostProvider;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.packet.DefaultOutboundPacket;
 import org.onlab.onos.net.packet.OutboundPacket;
@@ -161,12 +162,13 @@
         for (Device device : deviceService.getDevices()) {
             for (Port port : deviceService.getPorts(device.id())) {
                 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
-                PortAddresses addresses = hostManager.getAddressBindingsForPort(cp);
+                PortAddresses portAddresses =
+                    hostManager.getAddressBindingsForPort(cp);
 
-                for (IpPrefix prefix : addresses.ips()) {
-                    if (prefix.contains(targetIp)) {
+                for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
+                    if (ia.subnetAddress().contains(targetIp)) {
                         sendProbe(device.id(), port, targetIp,
-                                prefix.toIpAddress(), addresses.mac());
+                                  ia.ipAddress(), portAddresses.mac());
                     }
                 }
             }
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 81f42c8..735c109 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
@@ -5,7 +5,6 @@
 import static org.slf4j.LoggerFactory.getLogger;
 
 import java.nio.ByteBuffer;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -29,6 +28,7 @@
 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.link.LinkEvent;
 import org.onlab.onos.net.link.LinkListener;
@@ -114,35 +114,37 @@
         checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST);
         checkNotNull(inPort);
 
-        // If the source address matches one of our external addresses
-        // it could be a request from an internal host to an external
-        // address. Forward it over to the correct port.
-        IpAddress source = IpAddress.valueOf(arp.getSenderProtocolAddress());
-        PortAddresses sourceAddresses = findOutsidePortInSubnet(source);
-        if (sourceAddresses != null && !isOutsidePort(inPort)) {
-            for (IpPrefix subnet : sourceAddresses.ips()) {
-                if (subnet.toIpAddress().equals(source)) {
-                    sendTo(eth, sourceAddresses.connectPoint());
-                    return;
-                }
-            }
-        }
-
         // If the request came from outside the network, only reply if it was
         // for one of our external addresses.
         if (isOutsidePort(inPort)) {
-            IpAddress target = IpAddress.valueOf(arp.getTargetProtocolAddress());
-            PortAddresses addresses = hostService.getAddressBindingsForPort(inPort);
+            IpAddress target =
+                IpAddress.valueOf(arp.getTargetProtocolAddress());
+            PortAddresses addresses =
+                hostService.getAddressBindingsForPort(inPort);
 
-            for (IpPrefix interfaceAddress : addresses.ips()) {
-                if (interfaceAddress.toIpAddress().equals(target)) {
-                    Ethernet arpReply = buildArpReply(interfaceAddress,
-                            addresses.mac(), eth);
+            for (InterfaceIpAddress ia : addresses.ipAddresses()) {
+                if (ia.ipAddress().equals(target)) {
+                    Ethernet arpReply =
+                        buildArpReply(ia.ipAddress(), addresses.mac(), eth);
                     sendTo(arpReply, inPort);
                 }
             }
-
             return;
+        } else {
+            // If the source address matches one of our external addresses
+            // it could be a request from an internal host to an external
+            // address. Forward it over to the correct port.
+            IpAddress source =
+                IpAddress.valueOf(arp.getSenderProtocolAddress());
+            PortAddresses sourceAddresses = findPortInSubnet(source);
+            if (sourceAddresses != null) {
+                for (InterfaceIpAddress ia : sourceAddresses.ipAddresses()) {
+                    if (ia.ipAddress().equals(source)) {
+                        sendTo(eth, sourceAddresses.connectPoint());
+                        return;
+                    }
+                }
+            }
         }
 
         // Continue with normal proxy ARP case
@@ -168,8 +170,9 @@
         }
 
         // TODO find the correct IP address
-        Ethernet arpReply = buildArpReply(dst.ipAddresses().iterator().next(),
-                dst.mac(), eth);
+        IpAddress ipAddress =
+            dst.ipAddresses().iterator().next().toIpAddress();
+        Ethernet arpReply = buildArpReply(ipAddress, dst.mac(), eth);
         // TODO: check send status with host service.
         sendTo(arpReply, src.location());
     }
@@ -199,16 +202,14 @@
      * Finds the port with an address in the subnet of the target address, if
      * one exists.
      *
-     * @param target the target address to find a matching external port for
-     * @return a PortAddresses object containing the external addresses if one
-     * was found, otherwise null.
+     * @param target the target address to find a matching port for
+     * @return a PortAddresses object if one was found, otherwise null
      */
-    private PortAddresses findOutsidePortInSubnet(IpAddress target) {
+    private PortAddresses findPortInSubnet(IpAddress target) {
         for (PortAddresses addresses : hostService.getAddressBindings()) {
-            for (IpPrefix prefix : addresses.ips()) {
-                if (prefix.contains(target)) {
-                    return new PortAddresses(addresses.connectPoint(),
-                            Collections.singleton(prefix), addresses.mac());
+            for (InterfaceIpAddress ia : addresses.ipAddresses()) {
+                if (ia.subnetAddress().contains(target)) {
+                    return addresses;
                 }
             }
         }
@@ -223,7 +224,11 @@
      * @return true if the port is an outside-facing port, otherwise false
      */
     private boolean isOutsidePort(ConnectPoint port) {
-        return !hostService.getAddressBindingsForPort(port).ips().isEmpty();
+        //
+        // TODO: Is this sufficient to identify outside-facing ports: just
+        // having IP addresses on a port?
+        //
+        return !hostService.getAddressBindingsForPort(port).ipAddresses().isEmpty();
     }
 
     @Override
@@ -335,7 +340,7 @@
      * @param request the ARP request we got
      * @return an Ethernet frame containing the ARP reply
      */
-    private Ethernet buildArpReply(IpPrefix srcIp, MacAddress srcMac,
+    private Ethernet buildArpReply(IpAddress srcIp, MacAddress srcMac,
             Ethernet request) {
 
         Ethernet eth = new Ethernet();
diff --git a/core/net/src/test/java/org/onlab/onos/net/host/impl/HostManagerTest.java b/core/net/src/test/java/org/onlab/onos/net/host/impl/HostManagerTest.java
index 6864fd7..c20da19 100644
--- a/core/net/src/test/java/org/onlab/onos/net/host/impl/HostManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/host/impl/HostManagerTest.java
@@ -31,10 +31,12 @@
 import org.onlab.onos.net.host.HostProvider;
 import org.onlab.onos.net.host.HostProviderRegistry;
 import org.onlab.onos.net.host.HostProviderService;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.provider.AbstractProvider;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.store.trivial.impl.SimpleHostStore;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
@@ -68,9 +70,15 @@
     private static final ConnectPoint CP1 = new ConnectPoint(DID1, P1);
     private static final ConnectPoint CP2 = new ConnectPoint(DID2, P2);
 
-    private static final IpPrefix PREFIX1 = IpPrefix.valueOf("10.0.1.0/24");
-    private static final IpPrefix PREFIX2 = IpPrefix.valueOf("10.1.0.0/16");
-    private static final IpPrefix PREFIX3 = IpPrefix.valueOf("5.8.2.0/23");
+    private static final InterfaceIpAddress IA1 =
+        new InterfaceIpAddress(IpAddress.valueOf("10.1.1.1"),
+                               IpPrefix.valueOf("10.1.1.0/24"));
+    private static final InterfaceIpAddress IA2 =
+        new InterfaceIpAddress(IpAddress.valueOf("10.2.2.2"),
+                               IpPrefix.valueOf("10.2.0.0/16"));
+    private static final InterfaceIpAddress IA3 =
+        new InterfaceIpAddress(IpAddress.valueOf("10.3.3.3"),
+                               IpPrefix.valueOf("10.3.3.0/24"));
 
     private HostManager mgr;
 
@@ -207,23 +215,24 @@
 
     @Test
     public void bindAddressesToPort() {
-        PortAddresses add1 = new PortAddresses(CP1,
-                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+        PortAddresses add1 =
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
 
         mgr.bindAddressesToPort(add1);
         PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(add1.ips().equals(storedAddresses.ips()));
+        assertTrue(add1.ipAddresses().equals(storedAddresses.ipAddresses()));
         assertTrue(add1.mac().equals(storedAddresses.mac()));
 
         // Add some more addresses and check that they're added correctly
-        PortAddresses add2 = new PortAddresses(CP1, Sets.newHashSet(PREFIX3), null);
+        PortAddresses add2 =
+            new PortAddresses(CP1, Sets.newHashSet(IA3),  null);
 
         mgr.bindAddressesToPort(add2);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(storedAddresses.ips().equals(
-                Sets.newHashSet(PREFIX1, PREFIX2, PREFIX3)));
+        assertTrue(storedAddresses.ipAddresses().equals(
+                Sets.newHashSet(IA1, IA2, IA3)));
         assertTrue(storedAddresses.mac().equals(MAC1));
 
         PortAddresses add3 = new PortAddresses(CP1, null, MAC2);
@@ -231,29 +240,29 @@
         mgr.bindAddressesToPort(add3);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(storedAddresses.ips().equals(
-                Sets.newHashSet(PREFIX1, PREFIX2, PREFIX3)));
+        assertTrue(storedAddresses.ipAddresses().equals(
+                Sets.newHashSet(IA1, IA2, IA3)));
         assertTrue(storedAddresses.mac().equals(MAC2));
     }
 
     @Test
     public void unbindAddressesFromPort() {
-        PortAddresses add1 = new PortAddresses(CP1,
-                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+        PortAddresses add1 =
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
 
         mgr.bindAddressesToPort(add1);
         PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(storedAddresses.ips().size() == 2);
+        assertTrue(storedAddresses.ipAddresses().size() == 2);
         assertNotNull(storedAddresses.mac());
 
-        PortAddresses rem1 = new PortAddresses(CP1,
-                                               Sets.newHashSet(PREFIX1), null);
+        PortAddresses rem1 =
+            new PortAddresses(CP1, Sets.newHashSet(IA1), null);
 
         mgr.unbindAddressesFromPort(rem1);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(storedAddresses.ips().equals(Sets.newHashSet(PREFIX2)));
+        assertTrue(storedAddresses.ipAddresses().equals(Sets.newHashSet(IA2)));
         assertTrue(storedAddresses.mac().equals(MAC1));
 
         PortAddresses rem2 = new PortAddresses(CP1, null, MAC1);
@@ -261,47 +270,48 @@
         mgr.unbindAddressesFromPort(rem2);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(storedAddresses.ips().equals(Sets.newHashSet(PREFIX2)));
+        assertTrue(storedAddresses.ipAddresses().equals(Sets.newHashSet(IA2)));
         assertNull(storedAddresses.mac());
 
-        PortAddresses rem3 = new PortAddresses(CP1,
-                                               Sets.newHashSet(PREFIX2), MAC1);
+        PortAddresses rem3 =
+            new PortAddresses(CP1, Sets.newHashSet(IA2), MAC1);
 
         mgr.unbindAddressesFromPort(rem3);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(storedAddresses.ips().isEmpty());
+        assertTrue(storedAddresses.ipAddresses().isEmpty());
         assertNull(storedAddresses.mac());
     }
 
     @Test
     public void clearAddresses() {
-        PortAddresses add1 = new PortAddresses(CP1,
-                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+        PortAddresses add1 =
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
 
         mgr.bindAddressesToPort(add1);
         PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(storedAddresses.ips().size() == 2);
+        assertTrue(storedAddresses.ipAddresses().size() == 2);
         assertNotNull(storedAddresses.mac());
 
         mgr.clearAddresses(CP1);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
-        assertTrue(storedAddresses.ips().isEmpty());
+        assertTrue(storedAddresses.ipAddresses().isEmpty());
         assertNull(storedAddresses.mac());
     }
 
     @Test
     public void getAddressBindingsForPort() {
-        PortAddresses add1 = new PortAddresses(CP1,
-                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+        PortAddresses add1 =
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
 
         mgr.bindAddressesToPort(add1);
         PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
 
         assertTrue(storedAddresses.connectPoint().equals(CP1));
-        assertTrue(storedAddresses.ips().equals(Sets.newHashSet(PREFIX1, PREFIX2)));
+        assertTrue(storedAddresses.ipAddresses().equals(
+                        Sets.newHashSet(IA1, IA2)));
         assertTrue(storedAddresses.mac().equals(MAC1));
     }
 
@@ -311,8 +321,8 @@
 
         assertTrue(storedAddresses.isEmpty());
 
-        PortAddresses add1 = new PortAddresses(CP1,
-                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+        PortAddresses add1 =
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
 
         mgr.bindAddressesToPort(add1);
 
@@ -320,8 +330,8 @@
 
         assertTrue(storedAddresses.size() == 1);
 
-        PortAddresses add2 = new PortAddresses(CP2,
-                                               Sets.newHashSet(PREFIX3), MAC2);
+        PortAddresses add2 =
+            new PortAddresses(CP2, Sets.newHashSet(IA3), MAC2);
 
         mgr.bindAddressesToPort(add2);
 
diff --git a/core/net/src/test/java/org/onlab/onos/net/host/impl/HostMonitorTest.java b/core/net/src/test/java/org/onlab/onos/net/host/impl/HostMonitorTest.java
index 7fc6b8c..4b9d214 100644
--- a/core/net/src/test/java/org/onlab/onos/net/host/impl/HostMonitorTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/host/impl/HostMonitorTest.java
@@ -28,6 +28,7 @@
 import org.onlab.onos.net.flow.instructions.Instruction;
 import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
 import org.onlab.onos.net.host.HostProvider;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.packet.OutboundPacket;
 import org.onlab.onos.net.packet.PacketProcessor;
@@ -48,7 +49,10 @@
     private IpAddress targetIpAddress = IpAddress.valueOf("10.0.0.1");
     private IpPrefix targetIpPrefix = IpPrefix.valueOf(targetIpAddress.toOctets());
 
-    private IpPrefix sourcePrefix = IpPrefix.valueOf("10.0.0.99/24");
+    private static final IpAddress SOURCE_ADDR =
+        IpAddress.valueOf("10.0.0.99");
+    private static final InterfaceIpAddress IA1 =
+        new InterfaceIpAddress(SOURCE_ADDR, IpPrefix.valueOf("10.0.0.0/24"));
     private MacAddress sourceMac = MacAddress.valueOf(1L);
 
     private HostMonitor hostMonitor;
@@ -108,8 +112,8 @@
         deviceService.addDevice(device, Collections.singleton(port));
 
         ConnectPoint cp = new ConnectPoint(devId, portNum);
-        PortAddresses pa = new PortAddresses(cp, Collections.singleton(sourcePrefix),
-                sourceMac);
+        PortAddresses pa =
+            new PortAddresses(cp, Collections.singleton(IA1), sourceMac);
 
         expect(hostManager.getHostsByIp(targetIpPrefix))
                 .andReturn(Collections.<Host>emptySet()).anyTimes();
@@ -143,7 +147,8 @@
         Ethernet eth = new Ethernet();
         eth.deserialize(packet.data().array(), 0, packet.data().array().length);
         ARP arp = (ARP) eth.getPayload();
-        assertTrue(Arrays.equals(arp.getSenderProtocolAddress(), sourcePrefix.toOctets()));
+        assertTrue(Arrays.equals(arp.getSenderProtocolAddress(),
+                                 SOURCE_ADDR.toOctets()));
         assertTrue(Arrays.equals(arp.getSenderHardwareAddress(), sourceMac.toBytes()));
         assertTrue(Arrays.equals(arp.getTargetProtocolAddress(), targetIpPrefix.toOctets()));
     }
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 fa68761..76bf021 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
@@ -32,6 +32,7 @@
 import org.onlab.onos.net.flow.instructions.Instruction;
 import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
 import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.link.LinkListener;
 import org.onlab.onos.net.link.LinkService;
@@ -41,6 +42,7 @@
 import org.onlab.onos.net.provider.ProviderId;
 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;
@@ -186,10 +188,15 @@
 
         for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) {
             ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
-            IpPrefix prefix1 = IpPrefix.valueOf("10.0." + (2 * i - 1) + ".1/24");
-            IpPrefix prefix2 = IpPrefix.valueOf("10.0." + (2 * i) + ".1/24");
-            PortAddresses pa = new PortAddresses(cp,
-                    Sets.newHashSet(prefix1, prefix2), MacAddress.valueOf(i));
+            IpPrefix prefix1 = IpPrefix.valueOf("10.0." + (2 * i - 1) + ".0/24");
+            IpAddress addr1 = IpAddress.valueOf("10.0." + (2 * i - 1) + ".1");
+            IpPrefix prefix2 = IpPrefix.valueOf("10.0." + (2 * i) + ".0/24");
+            IpAddress addr2 = IpAddress.valueOf("10.0." + (2 * i) + ".1");
+            InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
+            InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
+            PortAddresses pa =
+                new PortAddresses(cp, Sets.newHashSet(ia1, ia2),
+                                  MacAddress.valueOf(i));
             addresses.add(pa);
 
             expect(hostService.getAddressBindingsForPort(cp))
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/GossipHostStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/GossipHostStore.java
index ee3fb45..e3e35bc 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/GossipHostStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/GossipHostStore.java
@@ -30,6 +30,7 @@
 import org.onlab.onos.net.host.HostEvent;
 import org.onlab.onos.net.host.HostStore;
 import org.onlab.onos.net.host.HostStoreDelegate;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.store.AbstractStore;
@@ -332,8 +333,9 @@
             if (existing == null) {
                 portAddresses.put(addresses.connectPoint(), addresses);
             } else {
-                Set<IpPrefix> union = Sets.union(existing.ips(), addresses.ips())
-                        .immutableCopy();
+                Set<InterfaceIpAddress> union =
+                    Sets.union(existing.ipAddresses(),
+                               addresses.ipAddresses()).immutableCopy();
 
                 MacAddress newMac = (addresses.mac() == null) ? existing.mac()
                         : addresses.mac();
@@ -351,8 +353,9 @@
         synchronized (portAddresses) {
             PortAddresses existing = portAddresses.get(addresses.connectPoint());
             if (existing != null) {
-                Set<IpPrefix> difference =
-                        Sets.difference(existing.ips(), addresses.ips()).immutableCopy();
+                Set<InterfaceIpAddress> difference =
+                    Sets.difference(existing.ipAddresses(),
+                                    addresses.ipAddresses()).immutableCopy();
 
                 // If they removed the existing mac, set the new mac to null.
                 // Otherwise, keep the existing mac.
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleHostStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleHostStore.java
index ee8570d..f28e656 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleHostStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleHostStore.java
@@ -19,6 +19,7 @@
 import org.onlab.onos.net.host.HostEvent;
 import org.onlab.onos.net.host.HostStore;
 import org.onlab.onos.net.host.HostStoreDelegate;
+import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.store.AbstractStore;
@@ -202,8 +203,9 @@
             if (existing == null) {
                 portAddresses.put(addresses.connectPoint(), addresses);
             } else {
-                Set<IpPrefix> union = Sets.union(existing.ips(), addresses.ips())
-                        .immutableCopy();
+                Set<InterfaceIpAddress> union =
+                    Sets.union(existing.ipAddresses(),
+                               addresses.ipAddresses()).immutableCopy();
 
                 MacAddress newMac = (addresses.mac() == null) ? existing.mac()
                         : addresses.mac();
@@ -221,8 +223,9 @@
         synchronized (portAddresses) {
             PortAddresses existing = portAddresses.get(addresses.connectPoint());
             if (existing != null) {
-                Set<IpPrefix> difference =
-                        Sets.difference(existing.ips(), addresses.ips()).immutableCopy();
+                Set<InterfaceIpAddress> difference =
+                        Sets.difference(existing.ipAddresses(),
+                                        addresses.ipAddresses()).immutableCopy();
 
                 // If they removed the existing mac, set the new mac to null.
                 // Otherwise, keep the existing mac.