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 |
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 --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, };