diff mbox series

[PATCHv7,net-next,1/2] ipv6: do not match device when remove source route

Message ID 20230818082902.1972738-2-liuhangbin@gmail.com (mailing list archive)
State Accepted
Commit b358f57f7db620f5c25e60d70015f4e4bb050688
Delegated to: Netdev Maintainers
Headers show
Series ipv6: update route when delete source address | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1331 this patch: 1331
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/build_clang success Errors and warnings before: 1353 this patch: 1353
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1354 this patch: 1354
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 30 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Hangbin Liu Aug. 18, 2023, 8:29 a.m. UTC
After deleting an IPv6 address on an interface and cleaning up the
related preferred source entries, it is important to ensure that all
routes associated with the deleted address are properly cleared. The
current implementation of rt6_remove_prefsrc() only checks the preferred
source addresses bound to the current device. However, there may be
routes that are bound to other devices but still utilize the same
preferred source address.

To address this issue, it is necessary to also delete entries that are
bound to other interfaces but share the same source address with the
current device. Failure to delete these entries would leave routes that
are bound to the deleted address unclear. Here is an example reproducer
(I have omitted unrelated routes):

+ ip link add dummy1 type dummy
+ ip link add dummy2 type dummy
+ ip link set dummy1 up
+ ip link set dummy2 up
+ ip addr add 1:2:3:4::5/64 dev dummy1
+ ip route add 7:7:7:0::1 dev dummy1 src 1:2:3:4::5
+ ip route add 7:7:7:0::2 dev dummy2 src 1:2:3:4::5
+ ip -6 route show
1:2:3:4::/64 dev dummy1 proto kernel metric 256 pref medium
7:7:7::1 dev dummy1 src 1:2:3:4::5 metric 1024 pref medium
7:7:7::2 dev dummy2 src 1:2:3:4::5 metric 1024 pref medium
+ ip addr del 1:2:3:4::5/64 dev dummy1
+ ip -6 route show
7:7:7::1 dev dummy1 metric 1024 pref medium
7:7:7::2 dev dummy2 src 1:2:3:4::5 metric 1024 pref medium

As Ido reminds, in IPv6, the preferred source address is looked up in
the same VRF as the first nexthop device, which is different with IPv4.
So, while removing the device checking, we also need to add an
ipv6_chk_addr() check to make sure the address does not exist on the other
devices of the rt nexthop device's VRF.

After fix:
+ ip addr del 1:2:3:4::5/64 dev dummy1
+ ip -6 route show
7:7:7::1 dev dummy1 metric 1024 pref medium
7:7:7::2 dev dummy2 metric 1024 pref medium

Reported-by: Thomas Haller <thaller@redhat.com>
Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2170513
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
v7: remove fixes tag
v6:
 - Add back the "!rt->nh" checking as Ido said this should be fixed in
   another patch.
 - Remove the table id checking as the preferred source address is
   looked up in the same VRF as the first nexthop device in IPv6. not VRF
   table like IPv4.
 - Move the fib tests to a separate patch.
v5: Move the addr check back to fib6_remove_prefsrc.
v4: check if the prefsrc address still exists on other device
v3: remove rt nh checking. update the ipv6_del_addr test descriptions
v2: checking table id and update fib_test.sh
---
 net/ipv6/route.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

Comments

David Ahern Aug. 19, 2023, 12:28 a.m. UTC | #1
On 8/18/23 2:29 AM, Hangbin Liu wrote:
> After deleting an IPv6 address on an interface and cleaning up the
> related preferred source entries, it is important to ensure that all
> routes associated with the deleted address are properly cleared. The
> current implementation of rt6_remove_prefsrc() only checks the preferred
> source addresses bound to the current device. However, there may be
> routes that are bound to other devices but still utilize the same
> preferred source address.
> 
> To address this issue, it is necessary to also delete entries that are
> bound to other interfaces but share the same source address with the
> current device. Failure to delete these entries would leave routes that
> are bound to the deleted address unclear. Here is an example reproducer
> (I have omitted unrelated routes):
> 
> + ip link add dummy1 type dummy
> + ip link add dummy2 type dummy
> + ip link set dummy1 up
> + ip link set dummy2 up
> + ip addr add 1:2:3:4::5/64 dev dummy1
> + ip route add 7:7:7:0::1 dev dummy1 src 1:2:3:4::5
> + ip route add 7:7:7:0::2 dev dummy2 src 1:2:3:4::5
> + ip -6 route show
> 1:2:3:4::/64 dev dummy1 proto kernel metric 256 pref medium
> 7:7:7::1 dev dummy1 src 1:2:3:4::5 metric 1024 pref medium
> 7:7:7::2 dev dummy2 src 1:2:3:4::5 metric 1024 pref medium
> + ip addr del 1:2:3:4::5/64 dev dummy1
> + ip -6 route show
> 7:7:7::1 dev dummy1 metric 1024 pref medium
> 7:7:7::2 dev dummy2 src 1:2:3:4::5 metric 1024 pref medium
> 
> As Ido reminds, in IPv6, the preferred source address is looked up in
> the same VRF as the first nexthop device, which is different with IPv4.
> So, while removing the device checking, we also need to add an
> ipv6_chk_addr() check to make sure the address does not exist on the other
> devices of the rt nexthop device's VRF.
> 
> After fix:
> + ip addr del 1:2:3:4::5/64 dev dummy1
> + ip -6 route show
> 7:7:7::1 dev dummy1 metric 1024 pref medium
> 7:7:7::2 dev dummy2 metric 1024 pref medium
> 
> Reported-by: Thomas Haller <thaller@redhat.com>
> Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2170513
> Reviewed-by: Ido Schimmel <idosch@nvidia.com>
> Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
> ---
> v7: remove fixes tag
> v6:
>  - Add back the "!rt->nh" checking as Ido said this should be fixed in
>    another patch.
>  - Remove the table id checking as the preferred source address is
>    looked up in the same VRF as the first nexthop device in IPv6. not VRF
>    table like IPv4.
>  - Move the fib tests to a separate patch.
> v5: Move the addr check back to fib6_remove_prefsrc.
> v4: check if the prefsrc address still exists on other device
> v3: remove rt nh checking. update the ipv6_del_addr test descriptions
> v2: checking table id and update fib_test.sh
> ---
>  net/ipv6/route.c | 7 ++-----
>  1 file changed, 2 insertions(+), 5 deletions(-)
> 

Reviewed-by: David Ahern <dsahern@kernel.org>
diff mbox series

Patch

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index db10c36f34bb..a5b74b91c8f3 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -4582,21 +4582,19 @@  struct fib6_info *addrconf_f6i_alloc(struct net *net,
 
 /* remove deleted ip from prefsrc entries */
 struct arg_dev_net_ip {
-	struct net_device *dev;
 	struct net *net;
 	struct in6_addr *addr;
 };
 
 static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
 {
-	struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
 	struct net *net = ((struct arg_dev_net_ip *)arg)->net;
 	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
 
 	if (!rt->nh &&
-	    ((void *)rt->fib6_nh->fib_nh_dev == dev || !dev) &&
 	    rt != net->ipv6.fib6_null_entry &&
-	    ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
+	    ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr) &&
+	    !ipv6_chk_addr(net, addr, rt->fib6_nh->fib_nh_dev, 0)) {
 		spin_lock_bh(&rt6_exception_lock);
 		/* remove prefsrc entry */
 		rt->fib6_prefsrc.plen = 0;
@@ -4609,7 +4607,6 @@  void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
 {
 	struct net *net = dev_net(ifp->idev->dev);
 	struct arg_dev_net_ip adni = {
-		.dev = ifp->idev->dev,
 		.net = net,
 		.addr = &ifp->addr,
 	};