ipv4: Fix incorrect route flushing when table ID 0 is used
authorIdo Schimmel <idosch@nvidia.com>
Sun, 4 Dec 2022 07:50:45 +0000 (09:50 +0200)
committerJakub Kicinski <kuba@kernel.org>
Wed, 7 Dec 2022 04:34:43 +0000 (20:34 -0800)
Cited commit added the table ID to the FIB info structure, but did not
properly initialize it when table ID 0 is used. This can lead to a route
in the default VRF with a preferred source address not being flushed
when the address is deleted.

Consider the following example:

 # ip address add dev dummy1 192.0.2.1/28
 # ip address add dev dummy1 192.0.2.17/28
 # ip route add 198.51.100.0/24 via 192.0.2.2 src 192.0.2.17 metric 100
 # ip route add table 0 198.51.100.0/24 via 192.0.2.2 src 192.0.2.17 metric 200
 # ip route show 198.51.100.0/24
 198.51.100.0/24 via 192.0.2.2 dev dummy1 src 192.0.2.17 metric 100
 198.51.100.0/24 via 192.0.2.2 dev dummy1 src 192.0.2.17 metric 200

Both routes are installed in the default VRF, but they are using two
different FIB info structures. One with a metric of 100 and table ID of
254 (main) and one with a metric of 200 and table ID of 0. Therefore,
when the preferred source address is deleted from the default VRF,
the second route is not flushed:

 # ip address del dev dummy1 192.0.2.17/28
 # ip route show 198.51.100.0/24
 198.51.100.0/24 via 192.0.2.2 dev dummy1 src 192.0.2.17 metric 200

Fix by storing a table ID of 254 instead of 0 in the route configuration
structure.

Add a test case that fails before the fix:

 # ./fib_tests.sh -t ipv4_del_addr

 IPv4 delete address route tests
     Regular FIB info
     TEST: Route removed from VRF when source address deleted            [ OK ]
     TEST: Route in default VRF not removed                              [ OK ]
     TEST: Route removed in default VRF when source address deleted      [ OK ]
     TEST: Route in VRF is not removed by address delete                 [ OK ]
     Identical FIB info with different table ID
     TEST: Route removed from VRF when source address deleted            [ OK ]
     TEST: Route in default VRF not removed                              [ OK ]
     TEST: Route removed in default VRF when source address deleted      [ OK ]
     TEST: Route in VRF is not removed by address delete                 [ OK ]
     Table ID 0
     TEST: Route removed in default VRF when source address deleted      [FAIL]

 Tests passed:   8
 Tests failed:   1

And passes after:

 # ./fib_tests.sh -t ipv4_del_addr

 IPv4 delete address route tests
     Regular FIB info
     TEST: Route removed from VRF when source address deleted            [ OK ]
     TEST: Route in default VRF not removed                              [ OK ]
     TEST: Route removed in default VRF when source address deleted      [ OK ]
     TEST: Route in VRF is not removed by address delete                 [ OK ]
     Identical FIB info with different table ID
     TEST: Route removed from VRF when source address deleted            [ OK ]
     TEST: Route in default VRF not removed                              [ OK ]
     TEST: Route removed in default VRF when source address deleted      [ OK ]
     TEST: Route in VRF is not removed by address delete                 [ OK ]
     Table ID 0
     TEST: Route removed in default VRF when source address deleted      [ OK ]

 Tests passed:   9
 Tests failed:   0

Fixes: 5a56a0b3a45d ("net: Don't delete routes in different VRFs")
Reported-by: Donald Sharp <sharpd@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/fib_frontend.c
tools/testing/selftests/net/fib_tests.sh

index f361d3d..b5736ef 100644 (file)
@@ -841,6 +841,9 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
                return -EINVAL;
        }
 
+       if (!cfg->fc_table)
+               cfg->fc_table = RT_TABLE_MAIN;
+
        return 0;
 errout:
        return err;
index 11c8914..5637b5d 100755 (executable)
@@ -1712,11 +1712,13 @@ ipv4_del_addr_test()
        $IP addr add dev dummy1 172.16.104.1/24
        $IP addr add dev dummy1 172.16.104.11/24
        $IP addr add dev dummy1 172.16.104.12/24
+       $IP addr add dev dummy1 172.16.104.13/24
        $IP addr add dev dummy2 172.16.104.1/24
        $IP addr add dev dummy2 172.16.104.11/24
        $IP addr add dev dummy2 172.16.104.12/24
        $IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
        $IP route add 172.16.106.0/24 dev lo src 172.16.104.12
+       $IP route add table 0 172.16.107.0/24 via 172.16.104.2 src 172.16.104.13
        $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
        $IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
        set +e
@@ -1762,6 +1764,14 @@ ipv4_del_addr_test()
        $IP ro ls vrf red | grep -q 172.16.106.0/24
        log_test $? 0 "Route in VRF is not removed by address delete"
 
+       # removing address from device in default vrf should remove route from
+       # the default vrf even when route was inserted with a table ID of 0.
+       echo "    Table ID 0"
+
+       $IP addr del dev dummy1 172.16.104.13/24
+       $IP ro ls | grep -q 172.16.107.0/24
+       log_test $? 1 "Route removed in default VRF when source address deleted"
+
        $IP li del dummy1
        $IP li del dummy2
        cleanup