Moved ProxyArp, SDN-IP and BgpRouter to use new config format.

The new config format is based on the new network configuration subsystem.

Includes a few config fixes to NetworkConfigLoader and InterfaceManager.

Change-Id: Id7f766736decb7afb6b63c2731d3baba9fc7c764
diff --git a/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigLoader.java b/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigLoader.java
index e66c81b..810ca6c 100644
--- a/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigLoader.java
+++ b/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigLoader.java
@@ -23,6 +23,7 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.net.config.Config;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigService;
@@ -49,11 +50,11 @@
 
     // FIXME: Add mutual exclusion to make sure this happens only once per startup.
 
-    private Map<InnerConfigPosition, ObjectNode> jsons = Maps.newHashMap();
+    private final Map<InnerConfigPosition, ObjectNode> jsons = Maps.newConcurrentMap();
 
     private final NetworkConfigListener configListener = new InnerConfigListener();
 
-    ObjectNode root;
+    private ObjectNode root;
 
     @Activate
     public void activate() {
@@ -101,24 +102,24 @@
      * Inner class that allows for tracking of JSON class configurations.
      */
     private final class InnerConfigPosition {
-        private String subjectKey, subject, classKey;
+        private final String subjectKey, subject, configKey;
 
-        private String getSubjectKey() {
+        private String subjectKey() {
             return subjectKey;
         }
 
-        private String getSubject() {
+        private String subject() {
             return subject;
         }
 
-        private String getClassKey() {
-            return classKey;
+        private String configKey() {
+            return configKey;
         }
 
-        private InnerConfigPosition(String subjectKey, String subject, String classKey) {
+        private InnerConfigPosition(String subjectKey, String subject, String configKey) {
             this.subjectKey = subjectKey;
             this.subject = subject;
-            this.classKey = classKey;
+            this.configKey = configKey;
         }
 
         @Override
@@ -128,15 +129,16 @@
             }
             if (obj instanceof InnerConfigPosition) {
                 final InnerConfigPosition that = (InnerConfigPosition) obj;
-                return Objects.equals(this.subjectKey, that.subjectKey) && Objects.equals(this.subject, that.subject)
-                        && Objects.equals(this.classKey, that.classKey);
+                return Objects.equals(this.subjectKey, that.subjectKey)
+                        && Objects.equals(this.subject, that.subject)
+                        && Objects.equals(this.configKey, that.configKey);
             }
             return false;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(subjectKey, subject, classKey);
+            return Objects.hash(subjectKey, subject, configKey);
         }
     }
 
@@ -174,38 +176,41 @@
     }
 
     /**
-     * Apply the configurations associated with all of the config classes that are imported and have not yet been
-     * applied.
+     * Apply the configurations associated with all of the config classes that
+     * are imported and have not yet been applied.
      */
-    protected void applyConfigurations() {
+    private void applyConfigurations() {
         Iterator<Map.Entry<InnerConfigPosition, ObjectNode>> iter = jsons.entrySet().iterator();
 
         Map.Entry<InnerConfigPosition, ObjectNode> entry;
         InnerConfigPosition key;
         ObjectNode node;
         String subjectKey;
-        String subject;
-        String classKey;
+        String subjectString;
+        String configKey;
 
         while (iter.hasNext()) {
             entry = iter.next();
             node = entry.getValue();
             key = entry.getKey();
-            subjectKey = key.getSubjectKey();
-            subject = key.getSubject();
-            classKey = key.getClassKey();
+            subjectKey = key.subjectKey();
+            subjectString = key.subject();
+            configKey = key.configKey();
+
+            Class<? extends Config> configClass =
+                    networkConfigService.getConfigClass(subjectKey, configKey);
             //Check that the config class has been imported
-            if (networkConfigService.getConfigClass(subjectKey, subject) != null) {
+            if (configClass != null) {
+
+                Object subject = networkConfigService.getSubjectFactory(subjectKey).
+                        createSubject(subjectString);
 
                 //Apply the configuration
-                networkConfigService.applyConfig(networkConfigService.getSubjectFactory(subjectKey).
-                                createSubject(subject),
-                        networkConfigService.getConfigClass(subjectKey, classKey), node);
+                networkConfigService.applyConfig(subject, configClass, node);
 
                 //Now that it has been applied the corresponding JSON entry is no longer needed
-                jsons.remove(key);
+                iter.remove();
             }
-
         }
     }
 
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
index fe369ae..99d401a 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
@@ -24,6 +24,7 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.core.Permission;
 import org.onosproject.net.config.NetworkConfigEvent;
@@ -86,6 +87,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected NetworkConfigService networkConfigService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected InterfaceService interfaceService;
+
     private HostMonitor monitor;
 
     @Activate
@@ -93,7 +97,7 @@
         store.setDelegate(delegate);
         eventDispatcher.addSink(HostEvent.class, listenerRegistry);
         networkConfigService.addListener(networkConfigListener);
-        monitor = new HostMonitor(deviceService, packetService, this);
+        monitor = new HostMonitor(packetService, this, interfaceService);
         monitor.start();
         log.info("Started");
     }
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
index 6dc71fc..fe25236 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
@@ -20,26 +20,23 @@
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.ICMP6;
-import org.onlab.packet.IpAddress;
 import org.onlab.packet.IPv6;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.onlab.packet.ndp.NeighborDiscoveryOptions;
 import org.onlab.packet.ndp.NeighborSolicitation;
 import org.onlab.util.Timer;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
-import org.onosproject.net.Port;
-import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.host.HostProvider;
 import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.host.PortAddresses;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketService;
@@ -63,9 +60,9 @@
  * </p>
  */
 public class HostMonitor implements TimerTask {
-    private DeviceService deviceService;
     private PacketService packetService;
     private HostManager hostManager;
+    private InterfaceService interfaceService;
 
     private final Set<IpAddress> monitoredAddresses;
 
@@ -80,20 +77,19 @@
     /**
      * Creates a new host monitor.
      *
-     * @param deviceService device service used to find edge ports
      * @param packetService packet service used to send packets on the data plane
      * @param hostManager host manager used to look up host information and
      * probe existing hosts
+     * @param interfaceService interface service for interface information
      */
-    public HostMonitor(DeviceService deviceService, PacketService packetService,
-            HostManager hostManager) {
+    public HostMonitor(PacketService packetService, HostManager hostManager,
+                       InterfaceService interfaceService) {
 
-        this.deviceService = deviceService;
         this.packetService = packetService;
         this.hostManager = hostManager;
+        this.interfaceService = interfaceService;
 
-        monitoredAddresses = Collections.newSetFromMap(
-                new ConcurrentHashMap<IpAddress, Boolean>());
+        monitoredAddresses = Collections.newSetFromMap(new ConcurrentHashMap<>());
         hostProviders = new ConcurrentHashMap<>();
     }
 
@@ -176,29 +172,21 @@
      * @param targetIp IP address to send the request for
      */
     private void sendArpNdpRequest(IpAddress targetIp) {
-        // Find ports with an IP address in the target's subnet and sent ARP/ND
-        // probes out those ports.
-        for (Device device : deviceService.getDevices()) {
-            for (Port port : deviceService.getPorts(device.id())) {
-                ConnectPoint cp = new ConnectPoint(device.id(), port.number());
-                Set<PortAddresses> portAddressSet =
-                    hostManager.getAddressBindingsForPort(cp);
+        Interface intf = interfaceService.getMatchingInterface(targetIp);
 
-                for (PortAddresses portAddresses : portAddressSet) {
-                    for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
-                        if (ia.subnetAddress().contains(targetIp)) {
-                            sendArpNdpProbe(device.id(), port, targetIp,
-                                            ia.ipAddress(),
-                                            portAddresses.mac(),
-                                            portAddresses.vlan());
-                        }
-                    }
-                }
+        if (intf == null) {
+            return;
+        }
+
+        for (InterfaceIpAddress ia : intf.ipAddresses()) {
+            if (ia.subnetAddress().contains(targetIp)) {
+                sendArpNdpProbe(intf.connectPoint(), targetIp, ia.ipAddress(),
+                        intf.mac(), intf.vlan());
             }
         }
     }
 
-    private void sendArpNdpProbe(DeviceId deviceId, Port port,
+    private void sendArpNdpProbe(ConnectPoint connectPoint,
                                  IpAddress targetIp,
                                  IpAddress sourceIp, MacAddress sourceMac,
                                  VlanId vlan) {
@@ -215,14 +203,14 @@
         }
 
         List<Instruction> instructions = new ArrayList<>();
-        instructions.add(Instructions.createOutput(port.number()));
+        instructions.add(Instructions.createOutput(connectPoint.port()));
 
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-            .setOutput(port.number())
+            .setOutput(connectPoint.port())
             .build();
 
         OutboundPacket outboundPacket =
-            new DefaultOutboundPacket(deviceId, treatment,
+            new DefaultOutboundPacket(connectPoint.deviceId(), treatment,
                                       ByteBuffer.wrap(probePacket.serialize()));
 
         packetService.emit(outboundPacket);
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
index 8fad769..06d0e9a 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
@@ -98,7 +98,7 @@
                 partialTree = true;
 
                 for (Link link : path.links()) {
-                    if (links.containsKey(link.src().deviceId())) {
+                    if (links.containsKey(link.dst().deviceId())) {
                         // We've already reached the existing tree with the first
                         // part of this path. Add the merging point with different
                         // incoming port, but don't add the remainder of the path
diff --git a/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java b/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java
index b5acde6..1a56d0e 100644
--- a/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java
+++ b/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java
@@ -34,6 +34,8 @@
 import org.onlab.packet.ndp.NeighborDiscoveryOptions;
 import org.onlab.packet.ndp.NeighborSolicitation;
 import org.onosproject.core.Permission;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Host;
 import org.onosproject.net.device.DeviceService;
@@ -41,8 +43,6 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.host.PortAddresses;
 import org.onosproject.net.link.LinkService;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.InboundPacket;
@@ -53,9 +53,7 @@
 import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
-import java.util.HashSet;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -95,17 +93,15 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ProxyArpStore store;
 
-    /**
-     * Listens to both device service and link service to determine
-     * whether a port is internal or external.
-     */
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected InterfaceService interfaceService;
+
     @Activate
     public void activate() {
         store.setDelegate(this::sendTo);
         log.info("Started");
     }
 
-
     @Deactivate
     public void deactivate() {
         store.setDelegate(null);
@@ -140,21 +136,18 @@
 
         VlanId vlan = vlanId(eth.getVlanID());
 
-        if (isOutsidePort(inPort)) {
+        if (hasIpAddress(inPort)) {
             // If the request came from outside the network, only reply if it was
             // for one of our external addresses.
-            Set<PortAddresses> addressSet =
-                    hostService.getAddressBindingsForPort(inPort);
 
-            for (PortAddresses addresses : addressSet) {
-                for (InterfaceIpAddress ia : addresses.ipAddresses()) {
-                    if (ia.ipAddress().equals(targetAddress)) {
-                        Ethernet arpReply =
-                                ARP.buildArpReply(targetAddress, addresses.mac(), eth);
-                        sendTo(arpReply, inPort);
-                    }
-                }
-            }
+            interfaceService.getInterfacesByPort(inPort)
+                    .stream()
+                    .filter(intf -> intf.ipAddresses()
+                            .stream()
+                            .anyMatch(ia -> ia.ipAddress().equals(targetAddress)))
+                    .forEach(intf -> buildAndSendArp(targetAddress, intf.mac(), eth, inPort));
+
+            // Stop here and don't proxy ARPs if the port has an IP address
             return;
         }
 
@@ -164,7 +157,7 @@
 
         Host dst = null;
         Host src = hostService.getHost(hostId(eth.getSourceMAC(),
-                                              vlanId(eth.getVlanID())));
+                vlanId(eth.getVlanID())));
 
         for (Host host : hosts) {
             if (host.vlan().equals(vlan)) {
@@ -175,8 +168,7 @@
 
         if (src != null && dst != null) {
             // We know the target host so we can respond
-            Ethernet arpReply = ARP.buildArpReply(targetAddress, dst.mac(), eth);
-            sendTo(arpReply, inPort);
+            buildAndSendArp(targetAddress, dst.mac(), eth, inPort);
             return;
         }
 
@@ -185,16 +177,14 @@
         // address. Forward it over to the correct port.
         Ip4Address source =
                 Ip4Address.valueOf(arp.getSenderProtocolAddress());
-        Set<PortAddresses> sourceAddresses = findPortsInSubnet(source);
+
         boolean matched = false;
-        for (PortAddresses pa : sourceAddresses) {
-            for (InterfaceIpAddress ia : pa.ipAddresses()) {
-                if (ia.ipAddress().equals(source) &&
-                        pa.vlan().equals(vlan)) {
-                    matched = true;
-                    sendTo(eth, pa.connectPoint());
-                    break;
-                }
+        Set<Interface> interfaces = interfaceService.getInterfacesByIp(source);
+        for (Interface intf : interfaces) {
+            if (intf.vlan().equals(vlan)) {
+                matched = true;
+                sendTo(eth, intf.connectPoint());
+                break;
             }
         }
 
@@ -202,10 +192,8 @@
             return;
         }
 
-        //
         // The request couldn't be resolved.
         // Flood the request on all ports except the incoming port.
-        //
         flood(eth, inPort);
     }
 
@@ -219,42 +207,14 @@
 
         // If the request came from outside the network, only reply if it was
         // for one of our external addresses.
-        if (isOutsidePort(inPort)) {
-            Set<PortAddresses> addressSet =
-                    hostService.getAddressBindingsForPort(inPort);
-
-            for (PortAddresses addresses : addressSet) {
-                for (InterfaceIpAddress ia : addresses.ipAddresses()) {
-                    if (ia.ipAddress().equals(targetAddress)) {
-                        Ethernet ndpReply =
-                                buildNdpReply(targetAddress, addresses.mac(), eth);
-                        sendTo(ndpReply, inPort);
-                    }
-                }
-            }
+        if (hasIpAddress(inPort)) {
+            interfaceService.getInterfacesByPort(inPort)
+                    .stream()
+                    .filter(intf -> intf.ipAddresses()
+                            .stream()
+                            .anyMatch(ia -> ia.ipAddress().equals(targetAddress)))
+                    .forEach(intf -> buildAndSendNdp(targetAddress, intf.mac(), eth, 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 ports.
-            Ip6Address source =
-                    Ip6Address.valueOf(ipv6.getSourceAddress());
-            Set<PortAddresses> sourceAddresses = findPortsInSubnet(source);
-            boolean matched = false;
-            for (PortAddresses pa : sourceAddresses) {
-                for (InterfaceIpAddress ia : pa.ipAddresses()) {
-                    if (ia.ipAddress().equals(source) &&
-                            pa.vlan().equals(vlan)) {
-                        matched = true;
-                        sendTo(eth, pa.connectPoint());
-                        break;
-                    }
-                }
-            }
-
-            if (matched) {
-                return;
-            }
         }
 
         // Continue with normal proxy ARP case
@@ -272,23 +232,49 @@
             }
         }
 
-        if (src == null || dst == null) {
-            //
-            // The request couldn't be resolved.
-            // Flood the request on all ports except the incoming ports.
-            //
-            flood(eth, inPort);
+        if (src != null || dst != null) {
+            // We know the target host so we can respond
+            buildAndSendNdp(targetAddress, dst.mac(), eth, inPort);
             return;
         }
 
-        //
-        // Reply on the port the request was received on
-        //
-        Ethernet ndpReply = buildNdpReply(targetAddress, dst.mac(), eth);
-        sendTo(ndpReply, 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.
+        Ip6Address source =
+                Ip6Address.valueOf(ipv6.getSourceAddress());
+
+        boolean matched = false;
+
+        Set<Interface> interfaces = interfaceService.getInterfacesByIp(source);
+        for (Interface intf : interfaces) {
+            if (intf.vlan().equals(vlan)) {
+                matched = true;
+                sendTo(eth, intf.connectPoint());
+                break;
+            }
+        }
+
+        if (matched) {
+            return;
+        }
+
+        // The request couldn't be resolved.
+        // Flood the request on all ports except the incoming ports.
+        flood(eth, inPort);
     }
     //TODO checkpoint
 
+    private void buildAndSendArp(Ip4Address srcIp, MacAddress srcMac,
+                                 Ethernet request, ConnectPoint port) {
+        sendTo(ARP.buildArpReply(srcIp, srcMac, request), port);
+    }
+
+    private void buildAndSendNdp(Ip6Address srcIp, MacAddress srcMac,
+                                 Ethernet request, ConnectPoint port) {
+        sendTo(buildNdpReply(srcIp, srcMac, request), port);
+    }
+
     /**
      * Outputs the given packet out the given port.
      *
@@ -314,30 +300,18 @@
     }
 
     /**
-     * Finds ports with an address in the subnet of the target address.
-     *
-     * @param target the target address to find a matching port for
-     * @return a set of PortAddresses describing ports in the subnet
-     */
-    private Set<PortAddresses> findPortsInSubnet(IpAddress target) {
-        Set<PortAddresses> result = new HashSet<>();
-        for (PortAddresses addresses : hostService.getAddressBindings()) {
-            result.addAll(addresses.ipAddresses().stream().filter(ia -> ia.subnetAddress().contains(target)).
-                    map(ia -> addresses).collect(Collectors.toList()));
-        }
-        return result;
-    }
-
-    /**
-     * Returns whether the given port is an outside-facing port with an IP
-     * address configured.
+     * Returns whether the given port has any IP addresses configured or not.
      *
      * @param port the port to check
-     * @return true if the port is an outside-facing port, otherwise false
+     * @return true if the port has at least one IP address configured,
+     * otherwise false
      */
-    private boolean isOutsidePort(ConnectPoint port) {
-        // TODO: Is this sufficient to identify outside-facing ports: just having IP addresses on a port?
-        return !hostService.getAddressBindingsForPort(port).isEmpty();
+    private boolean hasIpAddress(ConnectPoint port) {
+        return interfaceService.getInterfacesByPort(port)
+                .stream()
+                .map(intf -> intf.ipAddresses())
+                .findAny()
+                .isPresent();
     }
 
     @Override
@@ -418,7 +392,7 @@
         ByteBuffer buf = ByteBuffer.wrap(request.serialize());
 
         for (ConnectPoint connectPoint : edgeService.getEdgePoints()) {
-            if (isOutsidePort(connectPoint) || connectPoint.equals(inPort)) {
+            if (hasIpAddress(connectPoint) || connectPoint.equals(inPort)) {
                 continue;
             }
 
@@ -427,7 +401,6 @@
             packetService.emit(new DefaultOutboundPacket(connectPoint.deviceId(),
                                                          builder.build(), buf));
         }
-
     }
 
     /**
diff --git a/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java b/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
index 90cf6b4..d6ff473 100644
--- a/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
+++ b/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
@@ -26,6 +26,8 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
@@ -94,7 +96,7 @@
         expectLastCall().once();
         replay(hostProvider);
 
-        hostMonitor = new HostMonitor(null, null, hostManager);
+        hostMonitor = new HostMonitor(null, hostManager, null);
 
         hostMonitor.registerHostProvider(hostProvider);
         hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
@@ -129,16 +131,20 @@
                 new PortAddresses(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE);
 
         expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
-                .andReturn(Collections.<Host>emptySet()).anyTimes();
-        expect(hostManager.getAddressBindingsForPort(cp))
-                .andReturn(Collections.singleton(pa)).anyTimes();
+                .andReturn(Collections.emptySet()).anyTimes();
         replay(hostManager);
 
+        InterfaceService interfaceService = createMock(InterfaceService.class);
+        expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR))
+                .andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE))
+                .anyTimes();
+        replay(interfaceService);
+
         TestPacketService packetService = new TestPacketService();
 
 
         // Run the test
-        hostMonitor = new HostMonitor(deviceService, packetService, hostManager);
+        hostMonitor = new HostMonitor(packetService, hostManager, interfaceService);
 
         hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
         hostMonitor.run(null);
@@ -197,16 +203,20 @@
                                   VlanId.vlanId(vlan));
 
         expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
-                .andReturn(Collections.<Host>emptySet()).anyTimes();
-        expect(hostManager.getAddressBindingsForPort(cp))
-                .andReturn(Collections.singleton(pa)).anyTimes();
+                .andReturn(Collections.emptySet()).anyTimes();
         replay(hostManager);
 
+        InterfaceService interfaceService = createMock(InterfaceService.class);
+        expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR))
+                .andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.vlanId(vlan)))
+                .anyTimes();
+        replay(interfaceService);
+
         TestPacketService packetService = new TestPacketService();
 
 
         // Run the test
-        hostMonitor = new HostMonitor(deviceService, packetService, hostManager);
+        hostMonitor = new HostMonitor(packetService, hostManager, interfaceService);
 
         hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
         hostMonitor.run(null);
diff --git a/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java b/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
index e96602b..3978c48 100644
--- a/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
@@ -23,8 +23,11 @@
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultHost;
 import org.onosproject.net.Device;
@@ -44,7 +47,6 @@
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.host.PortAddresses;
 import org.onosproject.net.link.LinkListener;
 import org.onosproject.net.link.LinkService;
 import org.onosproject.net.packet.DefaultOutboundPacket;
@@ -57,12 +59,17 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.*;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Tests for the {@link ProxyArpManager} class.
@@ -104,6 +111,7 @@
     private DeviceService deviceService;
     private LinkService linkService;
     private HostService hostService;
+    private InterfaceService interfaceService;
 
     @Before
     public void setUp() throws Exception {
@@ -119,6 +127,9 @@
         hostService = createMock(HostService.class);
         proxyArp.hostService = hostService;
 
+        interfaceService = createMock(InterfaceService.class);
+        proxyArp.interfaceService = interfaceService;
+
         createTopology();
         proxyArp.deviceService = deviceService;
         proxyArp.linkService = linkService;
@@ -207,7 +218,7 @@
     }
 
     private void addAddressBindings() {
-        Set<PortAddresses> addresses = Sets.newHashSet();
+        Set<Interface> interfaces = Sets.newHashSet();
 
         for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) {
             ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
@@ -219,29 +230,28 @@
             Ip4Address addr2 = Ip4Address.valueOf("10.0." + (2 * i) + ".1");
             InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
             InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
-            PortAddresses pa1 =
-                    new PortAddresses(cp, Sets.newHashSet(ia1),
-                            MacAddress.valueOf(2 * i - 1),
-                            VlanId.vlanId((short) 1));
-            PortAddresses pa2 =
-                    new PortAddresses(cp, Sets.newHashSet(ia2),
-                            MacAddress.valueOf(2 * i),
-                            VlanId.NONE);
+            Interface intf1 = new Interface(cp, Sets.newHashSet(ia1),
+                    MacAddress.valueOf(2 * i - 1),
+                    VlanId.vlanId((short) 1));
+            Interface intf2 = new Interface(cp, Sets.newHashSet(ia2),
+                    MacAddress.valueOf(2 * i),
+                    VlanId.NONE);
 
-            addresses.add(pa1);
-            addresses.add(pa2);
+            interfaces.add(intf1);
+            interfaces.add(intf2);
 
-            expect(hostService.getAddressBindingsForPort(cp))
-                    .andReturn(Sets.newHashSet(pa1, pa2)).anyTimes();
+            expect(interfaceService.getInterfacesByPort(cp))
+                    .andReturn(Sets.newHashSet(intf1, intf2)).anyTimes();
         }
 
-        expect(hostService.getAddressBindings()).andReturn(addresses).anyTimes();
+        expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
 
         for (int i = 1; i <= NUM_FLOOD_PORTS; i++) {
             ConnectPoint cp = new ConnectPoint(getDeviceId(i + NUM_ADDRESS_PORTS),
                     P1);
-            expect(hostService.getAddressBindingsForPort(cp))
-                    .andReturn(Collections.<PortAddresses>emptySet()).anyTimes();
+
+            expect(interfaceService.getInterfacesByPort(cp))
+                    .andReturn(Collections.emptySet()).anyTimes();
         }
     }
 
@@ -254,6 +264,7 @@
     public void testNotKnown() {
         expect(hostService.getHostsByIp(IP1)).andReturn(Collections.<Host>emptySet());
         replay(hostService);
+        replay(interfaceService);
 
         assertFalse(proxyArp.isKnown(IP1));
     }
@@ -271,6 +282,7 @@
         expect(hostService.getHostsByIp(IP1))
                 .andReturn(Sets.newHashSet(host1, host2));
         replay(hostService);
+        replay(interfaceService);
 
         assertTrue(proxyArp.isKnown(IP1));
     }
@@ -296,6 +308,7 @@
         expect(hostService.getHost(HID2)).andReturn(requestor);
 
         replay(hostService);
+        replay(interfaceService);
 
         Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
 
@@ -319,11 +332,14 @@
                 Collections.singleton(IP2));
 
         expect(hostService.getHostsByIp(IP1))
-                .andReturn(Collections.<Host>emptySet());
+                .andReturn(Collections.emptySet());
+        expect(interfaceService.getInterfacesByIp(IP2))
+                .andReturn(Collections.emptySet());
         expect(hostService.getHost(HID2)).andReturn(requestor);
 
 
         replay(hostService);
+        replay(interfaceService);
 
         Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
 
@@ -354,9 +370,12 @@
 
         expect(hostService.getHostsByIp(IP1))
                 .andReturn(Collections.singleton(replyer));
+        expect(interfaceService.getInterfacesByIp(IP2))
+                .andReturn(Collections.emptySet());
         expect(hostService.getHost(HID2)).andReturn(requestor);
 
         replay(hostService);
+        replay(interfaceService);
 
         Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
 
@@ -382,6 +401,7 @@
 
         expect(hostService.getHost(HID2)).andReturn(requestor);
         replay(hostService);
+        replay(interfaceService);
 
         Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourFirstIp);
         isEdgePointReturn = true;
@@ -405,6 +425,7 @@
     @Test
     public void testReplyExternalPortBadRequest() {
         replay(hostService); // no further host service expectations
+        replay(interfaceService);
 
         Ip4Address theirIp = Ip4Address.valueOf("10.0.1.254");
 
@@ -428,8 +449,13 @@
         Ip4Address theirIp = Ip4Address.valueOf("10.0.1.100");
 
         expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet());
+        expect(interfaceService.getInterfacesByIp(ourIp))
+                .andReturn(Collections.singleton(new Interface(getLocation(1),
+                        Collections.singleton(new InterfaceIpAddress(ourIp, IpPrefix.valueOf("10.0.1.1/24"))),
+                        ourMac, VLAN1)));
         expect(hostService.getHost(HostId.hostId(ourMac, VLAN1))).andReturn(null);
         replay(hostService);
+        replay(interfaceService);
 
         // This is a request from something inside our network (like a BGP
         // daemon) to an external host.
@@ -462,6 +488,7 @@
         expect(hostService.getHost(HID1)).andReturn(host1);
         expect(hostService.getHost(HID2)).andReturn(host2);
         replay(hostService);
+        replay(interfaceService);
 
         Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
 
@@ -482,6 +509,7 @@
     public void testForwardFlood() {
         expect(hostService.getHost(HID1)).andReturn(null);
         replay(hostService);
+        replay(interfaceService);
 
         Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
 
@@ -508,12 +536,7 @@
         assertEquals(NUM_FLOOD_PORTS - 1, packetService.packets.size());
 
         Collections.sort(packetService.packets,
-                new Comparator<OutboundPacket>() {
-                    @Override
-                    public int compare(OutboundPacket o1, OutboundPacket o2) {
-                        return o1.sendThrough().uri().compareTo(o2.sendThrough().uri());
-                    }
-                });
+                (o1, o2) -> o1.sendThrough().uri().compareTo(o2.sendThrough().uri()));
 
 
         for (int i = 0; i < NUM_FLOOD_PORTS - 1; i++) {