ProxyArp: Reply directly when we know an external target host

Change-Id: I38773dcdcae05506c678c2006d1f63306af6b383
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 7b1f2a4..161518c 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
@@ -146,47 +146,25 @@
 
         VlanId vlan = VlanId.vlanId(eth.getVlanID());
 
-        // If the request came from outside the network, only reply if it was
-        // for one of our external addresses.
         if (isOutsidePort(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);
+                    hostService.getAddressBindingsForPort(inPort);
 
             for (PortAddresses addresses : addressSet) {
                 for (InterfaceIpAddress ia : addresses.ipAddresses()) {
                     if (ia.ipAddress().equals(targetAddress)) {
                         Ethernet arpReply =
-                            buildArpReply(targetAddress, addresses.mac(), eth);
+                                buildArpReply(targetAddress, 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 ports.
-            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;
-                    }
-                }
-            }
-
-            if (matched) {
-                return;
-            }
         }
 
-        // Continue with normal proxy ARP case
+        // See if we have the target host in the host store
 
         Set<Host> hosts = hostService.getHostsByIp(targetAddress);
 
@@ -201,20 +179,41 @@
             }
         }
 
-        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
+            Ethernet arpReply = buildArpReply(targetAddress, dst.mac(), eth);
+            sendTo(arpReply, inPort);
+            return;
+        }
+
+        // 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.
+        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;
+                }
+            }
+        }
+
+        if (matched) {
             return;
         }
 
         //
-        // Reply on the port the request was received on
+        // The request couldn't be resolved.
+        // Flood the request on all ports except the incoming port.
         //
-        Ethernet arpReply = buildArpReply(targetAddress, dst.mac(), eth);
-        sendTo(arpReply, inPort);
+        flood(eth, inPort);
+        return;
     }
 
     private void replyNdp(Ethernet eth, ConnectPoint inPort) {
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 6d90971..09f4f14 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
@@ -242,8 +242,8 @@
     }
 
     /**
-     * Tests {@link ProxyArpManager#isKnown(Ip4Address)} in the case where the
-     * IP address is not known.
+     * Tests {@link ProxyArpManager#isKnown(org.onlab.packet.IpAddress)} in the
+     * case where the IP address is not known.
      * Verifies the method returns false.
      */
     @Test
@@ -255,8 +255,8 @@
     }
 
     /**
-     * Tests {@link ProxyArpManager#isKnown(Ip4Address)} in the case where the
-     * IP address is known.
+     * Tests {@link ProxyArpManager#isKnown(org.onlab.packet.IpAddress)} in the
+     * case where the IP address is known.
      * Verifies the method returns true.
      */
     @Test
@@ -403,12 +403,14 @@
 
     @Test
     public void testReplyToRequestFromUs() {
-        replay(hostService); // no further host service expectations
-
         Ip4Address ourIp = Ip4Address.valueOf("10.0.1.1");
         MacAddress ourMac = MacAddress.valueOf(1L);
         Ip4Address theirIp = Ip4Address.valueOf("10.0.1.100");
 
+        expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet());
+        expect(hostService.getHost(HostId.hostId(ourMac, VLAN1))).andReturn(null);
+        replay(hostService);
+
         // This is a request from something inside our network (like a BGP
         // daemon) to an external host.
         Ethernet arpRequest = buildArp(ARP.OP_REQUEST, ourMac, null, ourIp, theirIp);