ipv4: Fix incorrect route flushing when table ID 0 is used

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: 5a56a0b3a4 ("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>
This commit is contained in:
Ido Schimmel 2022-12-04 09:50:45 +02:00 committed by Jakub Kicinski
parent f96a3d7455
commit c0d999348e
2 changed files with 13 additions and 0 deletions

View File

@ -841,6 +841,9 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
return -EINVAL; return -EINVAL;
} }
if (!cfg->fc_table)
cfg->fc_table = RT_TABLE_MAIN;
return 0; return 0;
errout: errout:
return err; return err;

View File

@ -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.1/24
$IP addr add dev dummy1 172.16.104.11/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.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.1/24
$IP addr add dev dummy2 172.16.104.11/24 $IP addr add dev dummy2 172.16.104.11/24
$IP addr add dev dummy2 172.16.104.12/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.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 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.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 $IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
set +e set +e
@ -1762,6 +1764,14 @@ ipv4_del_addr_test()
$IP ro ls vrf red | grep -q 172.16.106.0/24 $IP ro ls vrf red | grep -q 172.16.106.0/24
log_test $? 0 "Route in VRF is not removed by address delete" 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 dummy1
$IP li del dummy2 $IP li del dummy2
cleanup cleanup