aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vnet/ethernet/arp.c20
-rw-r--r--test/test_neighbor.py64
-rw-r--r--test/vpp_interface.py6
3 files changed, 86 insertions, 4 deletions
diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c
index c22be3fc809..c84ff47bc00 100644
--- a/src/vnet/ethernet/arp.c
+++ b/src/vnet/ethernet/arp.c
@@ -1004,7 +1004,17 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
if (FIB_ENTRY_FLAG_LOCAL & src_flags)
{
error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
- goto drop2;
+ /*
+ * When VPP has an interface whose address is also
+ * applied to a TAP interface on the host, then VPP's
+ * TAP interface will be unnumbered to the 'real'
+ * interface and do proxy ARP from the host.
+ * The curious aspect of this setup is that ARP requests
+ * from the host will come from the VPP's own address.
+ * So don't drop immediately here, instead go see if this
+ * is a proxy ARP case.
+ */
+ goto drop1;
}
/* A Source must also be local to subnet of matching
* interface address. */
@@ -1151,9 +1161,11 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
}
}
- /* We are going to reply to this request, so learn the sender */
- error0 = arp_learn (vnm, am, sw_if_index0,
- &arp0->ip4_over_ethernet[1]);
+ /* We are going to reply to this request, so, in the absence of
+ errors, learn the sender */
+ if (!error0)
+ error0 = arp_learn (vnm, am, sw_if_index0,
+ &arp0->ip4_over_ethernet[1]);
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
n_left_to_next, pi0, next0);
diff --git a/test/test_neighbor.py b/test/test_neighbor.py
index b4a6878d759..1c7cc2678ff 100644
--- a/test/test_neighbor.py
+++ b/test/test_neighbor.py
@@ -657,6 +657,70 @@ class ARPTestCase(VppTestCase):
self.pg2.admin_down()
self.pg1.admin_down()
+ def test_proxy_mirror_arp(self):
+ """ Interface Mirror Proxy ARP """
+
+ #
+ # When VPP has an interface whose address is also applied to a TAP
+ # interface on the host, then VPP's TAP interface will be unnumbered
+ # to the 'real' interface and do proxy ARP from the host.
+ # the curious aspect of this setup is that ARP requests from the host
+ # will come from the VPP's own address.
+ #
+ self.pg0.generate_remote_hosts(2)
+
+ arp_req_from_me = (Ether(src=self.pg2.remote_mac,
+ dst="ff:ff:ff:ff:ff:ff") /
+ ARP(op="who-has",
+ hwsrc=self.pg2.remote_mac,
+ pdst=self.pg0.remote_hosts[1].ip4,
+ psrc=self.pg0.local_ip4))
+
+ #
+ # Configure Proxy ARP for the subnet on PG0addresses on pg0
+ #
+ self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet,
+ self.pg0._local_ip4n_bcast)
+
+ # Make pg2 un-numbered to pg0
+ #
+ self.pg2.set_unnumbered(self.pg0.sw_if_index)
+
+ #
+ # Enable pg2 for proxy ARP
+ #
+ self.pg2.set_proxy_arp()
+
+ #
+ # Send the ARP request with an originating address that
+ # is VPP's own address
+ #
+ self.pg2.add_stream(arp_req_from_me)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg2.get_capture(1)
+ self.verify_arp_resp(rx[0],
+ self.pg2.local_mac,
+ self.pg2.remote_mac,
+ self.pg0.remote_hosts[1].ip4,
+ self.pg0.local_ip4)
+
+ #
+ # validate we have not learned an ARP entry as a result of this
+ #
+ self.assertFalse(find_nbr(self,
+ self.pg2.sw_if_index,
+ self.pg0.local_ip4))
+
+ #
+ # cleanup
+ #
+ self.pg2.set_proxy_arp(0)
+ self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet,
+ self.pg0._local_ip4n_bcast,
+ is_add=0)
+
def test_proxy_arp(self):
""" Proxy ARP """
diff --git a/test/vpp_interface.py b/test/vpp_interface.py
index 662015eacf7..b8505ce39d7 100644
--- a/test/vpp_interface.py
+++ b/test/vpp_interface.py
@@ -163,6 +163,12 @@ class VppInterface(object):
self._local_ip4 = "172.16.%u.1" % self.sw_if_index
self._local_ip4n = socket.inet_pton(socket.AF_INET, self.local_ip4)
+ self._local_ip4_subnet = "172.16.%u.0" % self.sw_if_index
+ self._local_ip4n_subnet = socket.inet_pton(socket.AF_INET,
+ self._local_ip4_subnet)
+ self._local_ip4_bcast = "172.16.%u.255" % self.sw_if_index
+ self._local_ip4n_bcast = socket.inet_pton(socket.AF_INET,
+ self._local_ip4_bcast)
self.local_ip4_prefix_len = 24
self.has_ip4_config = False
self.ip4_table_id = 0