diff options
-rw-r--r-- | src/vnet/ethernet/arp.c | 20 | ||||
-rw-r--r-- | test/test_neighbor.py | 64 | ||||
-rw-r--r-- | test/vpp_interface.py | 6 |
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 |