fib: set the value of the sw_if_index for DROP route 18/40718/3
authorMohsin Kazmi <[email protected]>
Fri, 19 Apr 2024 09:10:46 +0000 (09:10 +0000)
committerBeno�t Ganne <[email protected]>
Mon, 3 Jun 2024 12:22:10 +0000 (12:22 +0000)
Type: fix

fib_api_path_decode() is utilized by the IP route API call
to translate the path from the API to the fib_route_path_t
structure. The ip_route_add_del_handler_t function initializes
the fib_route_path_t structure to zeros, consequently setting
the sw_if_index value to 0, which is a valid value in VPP.
Typically, the default VRF (Virtual Routing and Forwarding)
has a local interface at index 0, leading to normal functionality.
However, a custom VRF table without any interface will result
in a crash.

The issue arises because the DROP route in fib_api_path_decode()
does not override the sw_if_index value with the one provided
in vl_api_fib_path_t. Subsequently, when this sw_if_index is
attempted to be resolved in the VRF table where the interface
does not exist, it leads to a crash.

This patch addresses the problem by setting the sw_if_index of
fib_route_path_t to the sw_if_index value of the API path.

To reproduce the issue, please remove the fix and run the following command:
make test-debug TEST=test_ip4.TestIPv4RouteLookup.test_exact_match

Change-Id: I5d72e91e5c701e749a92873941bee7b7b5eabd41
Signed-off-by: Mohsin Kazmi <[email protected]>
src/vnet/fib/fib_api.c
test/test_ip4.py

index 07d6699..1b1c0d1 100644 (file)
@@ -190,6 +190,7 @@ fib_api_path_decode (vl_api_fib_path_t *in,
         break;
     case FIB_API_PATH_TYPE_DROP:
         out->frp_flags |= FIB_ROUTE_PATH_DROP;
+        out->frp_sw_if_index = ntohl(in->sw_if_index);
         break;
     case FIB_API_PATH_TYPE_LOCAL:
         out->frp_flags |= FIB_ROUTE_PATH_LOCAL;
index 926ca77..a183b0c 100644 (file)
@@ -244,12 +244,13 @@ class TestIPv4RouteLookup(VppTestCase):
     """IPv4 Route Lookup Test Case"""
 
     routes = []
+    tables = []
 
-    def route_lookup(self, prefix, exact):
+    def route_lookup(self, prefix, exact, table_id=0):
         return self.vapi.api(
             self.vapi.papi.ip_route_lookup,
             {
-                "table_id": 0,
+                "table_id": table_id,
                 "exact": exact,
                 "prefix": prefix,
             },
@@ -283,11 +284,30 @@ class TestIPv4RouteLookup(VppTestCase):
         r.add_vpp_config()
         self.routes.append(r)
 
+        custom_vrf = VppIpTable(self, 200)
+        custom_vrf.add_vpp_config()
+        self.tables.append(custom_vrf)
+
+        r = VppIpRoute(self, "2.2.0.0", 16, [drop_nh], 200)
+        r.add_vpp_config()
+        self.routes.append(r)
+
+        r = VppIpRoute(self, "2.2.2.0", 24, [drop_nh], 200)
+        r.add_vpp_config()
+        self.routes.append(r)
+
+        r = VppIpRoute(self, "2.2.2.2", 32, [drop_nh], 200)
+        r.add_vpp_config()
+        self.routes.append(r)
+
     def tearDown(self):
         # Remove the routes we added
         for r in self.routes:
             r.remove_vpp_config()
 
+        for vrf in self.tables:
+            vrf.remove_vpp_config()
+
         super(TestIPv4RouteLookup, self).tearDown()
 
     def test_exact_match(self):
@@ -305,6 +325,20 @@ class TestIPv4RouteLookup(VppTestCase):
         with self.vapi.assert_negative_api_retval():
             self.route_lookup("1.1.1.2/32", True)
 
+        # Verify we find the host route
+        prefix = "2.2.2.2/32"
+        result = self.route_lookup(prefix, True, 200)
+        assert prefix == str(result.route.prefix)
+
+        # Verify we find a middle prefix route
+        prefix = "2.2.2.0/24"
+        result = self.route_lookup(prefix, True, 200)
+        assert prefix == str(result.route.prefix)
+
+        # Verify we do not find an available LPM.
+        with self.vapi.assert_negative_api_retval():
+            self.route_lookup("2.2.2.1/32", True, 200)
+
     def test_longest_prefix_match(self):
         # verify we find lpm
         lpm_prefix = "1.1.1.0/24"
@@ -315,6 +349,15 @@ class TestIPv4RouteLookup(VppTestCase):
         result = self.route_lookup(lpm_prefix, False)
         assert lpm_prefix == str(result.route.prefix)
 
+        # verify we find lpm
+        lpm_prefix = "2.2.2.0/24"
+        result = self.route_lookup("2.2.2.1/32", False, 200)
+        assert lpm_prefix == str(result.route.prefix)
+
+        # Verify we find the exact when not requested
+        result = self.route_lookup(lpm_prefix, False, 200)
+        assert lpm_prefix == str(result.route.prefix)
+
         # Can't seem to delete the default route so no negative LPM test.