fib: change the order of adding interface routes 89/43589/2
authorArtem Glazychev <[email protected]>
Mon, 18 Aug 2025 04:18:05 +0000 (11:18 +0700)
committerNeale Ranns <[email protected]>
Thu, 28 Aug 2025 02:11:57 +0000 (02:11 +0000)
The order in which fib_table_entry is added affects the update of adjacency. If you assign a /31 address to the interface, an ARP request is sent to the peer with the source address from the glean adjacency, which is incorrect before adding the local address route.
Steps to reproduce the problem:
create tap
set interface state tap0 up
set interface ip address tap0 192.168.100.1/31

In this case, ARP-Request was sent with an incorrect sender IP:
Sender IP Address: 192.168.100.0
Target IP Address: 192.168.100.0

Type: fix

Change-Id: I8712bcf9fd0cb96788fe4a6c4b4827af774c0ab9
Signed-off-by: Artem Glazychev <[email protected]>
src/vnet/ip/ip4_forward.c
src/vnet/ip/ip6_forward.c
test/test_ip4.py

index 4760e29..fb96159 100644 (file)
@@ -452,9 +452,6 @@ ip4_add_interface_routes (u32 sw_if_index,
     .fp_addr.ip4 = *address,
   };
 
-  /* set special routes for the prefix if needed */
-  ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
-
   if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
     {
       u32 classify_table_index =
@@ -487,6 +484,10 @@ ip4_add_interface_routes (u32 sw_if_index,
                                    ~0,
                                   1, NULL,
                                   FIB_ROUTE_PATH_FLAG_NONE);
+
+  /* set special routes for the prefix if needed */
+  if (a->address_length < 32)
+    ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
 }
 
 static void
index 803396f..1a77bd7 100644 (file)
@@ -132,10 +132,6 @@ ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
     .fp_addr.ip6 = *address,
   };
 
-  /* set special routes for the prefix if needed */
-  ip6_add_interface_prefix_routes (im, sw_if_index, fib_index,
-                                  address, a->address_length);
-
   pfx.fp_len = 128;
   if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
     {
@@ -166,6 +162,11 @@ ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
                                   &pfx.fp_addr,
                                   sw_if_index, ~0,
                                   1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
+
+  /* set special routes for the prefix if needed */
+  if (a->address_length < 128)
+    ip6_add_interface_prefix_routes (im, sw_if_index, fib_index, address,
+                                    a->address_length);
 }
 
 static void
index 9d5db0d..5f8aafa 100644 (file)
@@ -1194,11 +1194,33 @@ class TestIPSubNets(VppTestCase):
         # A /31 is a special case where the 'other-side' is an attached host
         # packets to that peer generate ARP requests
         #
-        ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
+        # Let's consider two cases:
+        # Case 1: interface has the second address of /31
+        #
+        self.pg_enable_capture(self.pg_interfaces)
+        self.vapi.sw_interface_add_del_address(
+            sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.11/31"
+        )
+
+        rx = self.pg0.get_capture(1)
+        self.assertEqual(rx[0][ARP].psrc, "10.10.10.11")
+        self.assertEqual(rx[0][ARP].pdst, "10.10.10.10")
 
+        # remove the sub-net
+        self.vapi.sw_interface_add_del_address(
+            sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.11/31", is_add=0
+        )
+
+        #
+        # Case 2: interface has the first address of /31
+        #
+        self.pg_enable_capture(self.pg_interfaces)
         self.vapi.sw_interface_add_del_address(
             sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/31"
         )
+        rx = self.pg0.get_capture(1)
+        self.assertEqual(rx[0][ARP].psrc, "10.10.10.10")
+        self.assertEqual(rx[0][ARP].pdst, "10.10.10.11")
 
         pn = (
             Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
@@ -1211,7 +1233,8 @@ class TestIPSubNets(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
         rx = self.pg0.get_capture(1)
-        rx[ARP]
+        self.assertEqual(rx[0][ARP].psrc, "10.10.10.10")
+        self.assertEqual(rx[0][ARP].pdst, "10.10.10.11")
 
         # remove the sub-net and we are forwarding via the cover again
         self.vapi.sw_interface_add_del_address(