vnet: fix ARP for unnumbered 82/40482/7
authorPim van Pelt <pim@ipng.nl>
Fri, 8 Mar 2024 08:27:40 +0000 (09:27 +0100)
committerNeale Ranns <neale@graphiant.com>
Tue, 9 Apr 2024 04:26:21 +0000 (04:26 +0000)
On unnumbered interfaces, ARP fails because there is no attached route.
Allow replies to peer-to-peer addresses on unnumbered interfaces:
  eg. 192.0.2.1/32 <-> 192.0.2.2/32

Type: fix
Change-Id: Ibeb8d8ebc8d58d5bfb0724739a17694e0217356e
Signed-off-by: Pim van Pelt <pim@ipng.nl>
src/vnet/arp/arp.c
test/test_neighbor.py

index cacdd71..43b2a93 100644 (file)
@@ -423,6 +423,10 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
 
            }
 
+         dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
+                                         &arp0->ip4_over_ethernet[1].ip4, 32);
+         conn_sw_if_index0 = fib_entry_get_any_resolving_interface (dst_fei);
+
          {
            /*
             * we're looking for FIB entries that indicate the source
@@ -509,24 +513,20 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
            while (!attached &&
                   !fib_entry_is_sourced (src_fei, FIB_SOURCE_DEFAULT_ROUTE));
 
-           if (!attached)
+           if (!attached &&
+               !arp_unnumbered (p0, sw_if_index0, conn_sw_if_index0))
              {
                /*
-                * the matching route is a not attached, i.e. it was
-                * added as a result of routing, rather than interface/ARP
-                * configuration. If the matching route is not a host route
-                * (i.e. a /32)
+                * the matching route is a not attached and not unnumbered,
+                * i.e. it was added as a result of routing, rather than
+                * interface/ARP configuration. If the matching route is not
+                * a host route (i.e. a /32)
                 */
                error0 = ARP_ERROR_L3_SRC_ADDRESS_NOT_LOCAL;
                goto drop;
              }
          }
 
-         dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
-                                         &arp0->ip4_over_ethernet[1].ip4,
-                                         32);
-         conn_sw_if_index0 = fib_entry_get_any_resolving_interface (dst_fei);
-
          switch (arp_dst_fib_check (dst_fei, &dst_flags))
            {
            case ARP_DST_FIB_ADJ:
@@ -619,9 +619,9 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
              sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
            {
              /*
-              * The interface the ARP is sent to or was received on is not the
-              * interface on which the covering prefix is configured.
-              * Maybe this is a case for unnumbered.
+              * The interface the ARP is sent to or was received on is
+              * not the interface on which the covering prefix is
+              * configured. Maybe this is a case for unnumbered.
               */
              if (!arp_unnumbered (p0, sw_if_index0, conn_sw_if_index0))
                {
@@ -636,8 +636,7 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
              goto drop;
            }
 
-         next0 = arp_mk_reply (vnm, p0, sw_if_index0,
-                               if_addr0, arp0, eth_rx);
+         next0 = arp_mk_reply (vnm, p0, sw_if_index0, if_addr0, arp0, eth_rx);
 
          /* We are going to reply to this request, so, in the absence of
             errors, learn the sender */
index 7338eff..6fcf13f 100644 (file)
@@ -432,14 +432,24 @@ class ARPTestCase(VppTestCase):
         self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
         self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
 
-        #
-        # We should respond to ARP requests for the unnumbered to address
-        # once an attached route to the source is known
-        #
-        self.send_and_assert_no_replies(
-            self.pg2, p, "ARP req for unnumbered address - no source"
+        # Allow for ARP requests from point-to-point ethernet neighbors
+        # without an attached route on pg2
+        self.pg2.add_stream(p)
+        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.pg1.local_ip4,
+            self.pg2.remote_hosts[3].ip4,
         )
 
+        #
+        # Allow for ARP requests from neighbors on unnumbered with
+        # an attached route on pg2
         attached_host = VppIpRoute(
             self,
             self.pg2.remote_hosts[3].ip4,