Jonathan Hart
Committed by Gerrit Code Review

ProxyArp: Reply directly when we know an external target host

Change-Id: I38773dcdcae05506c678c2006d1f63306af6b383
......@@ -146,9 +146,9 @@ public class ProxyArpManager implements ProxyArpService {
VlanId vlan = VlanId.vlanId(eth.getVlanID());
if (isOutsidePort(inPort)) {
// 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);
......@@ -162,10 +162,33 @@ public class ProxyArpManager implements ProxyArpService {
}
}
return;
} else {
}
// See if we have the target host in the host store
Set<Host> hosts = hostService.getHostsByIp(targetAddress);
Host dst = null;
Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(),
VlanId.vlanId(eth.getVlanID())));
for (Host host : hosts) {
if (host.vlan().equals(vlan)) {
dst = host;
break;
}
}
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 ports.
// address. Forward it over to the correct port.
Ip4Address source =
Ip4Address.valueOf(arp.getSenderProtocolAddress());
Set<PortAddresses> sourceAddresses = findPortsInSubnet(source);
......@@ -184,39 +207,15 @@ public class ProxyArpManager implements ProxyArpService {
if (matched) {
return;
}
}
// Continue with normal proxy ARP case
Set<Host> hosts = hostService.getHostsByIp(targetAddress);
Host dst = null;
Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(),
VlanId.vlanId(eth.getVlanID())));
for (Host host : hosts) {
if (host.vlan().equals(vlan)) {
dst = host;
break;
}
}
if (src == null || dst == null) {
//
// The request couldn't be resolved.
// Flood the request on all ports except the incoming ports.
// Flood the request on all ports except the incoming port.
//
flood(eth, inPort);
return;
}
//
// Reply on the port the request was received on
//
Ethernet arpReply = buildArpReply(targetAddress, dst.mac(), eth);
sendTo(arpReply, inPort);
}
private void replyNdp(Ethernet eth, ConnectPoint inPort) {
IPv6 ipv6 = (IPv6) eth.getPayload();
......
......@@ -242,8 +242,8 @@ public class ProxyArpManagerTest {
}
/**
* 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 @@ public class ProxyArpManagerTest {
}
/**
* 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 @@ public class ProxyArpManagerTest {
@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);
......