Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv6: start using dst_dev_rcu()

Refactor icmpv6_xrlim_allow() and ip6_dst_hoplimit()
so that we acquire rcu_read_lock() a bit longer
to be able to use dst_dev_rcu() instead of dst_dev().

__ip6_rt_update_pmtu() and rt6_do_redirect can directly
use dst_dev_rcu() in sections already holding rcu_read_lock().

Small changes to use dst_dev_net_rcu() in
ip6_default_advmss(), ipv6_sock_ac_join(),
ip6_mc_find_dev() and ndisc_send_skb().

Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250828195823.3958522-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
b775ecf1 caedcc5b

+14 -13
+1 -1
net/ipv6/anycast.c
··· 104 104 rcu_read_lock(); 105 105 rt = rt6_lookup(net, addr, NULL, 0, NULL, 0); 106 106 if (rt) { 107 - dev = dst_dev(&rt->dst); 107 + dev = dst_dev_rcu(&rt->dst); 108 108 netdev_hold(dev, &dev_tracker, GFP_ATOMIC); 109 109 ip6_rt_put(rt); 110 110 } else if (ishost) {
+3 -3
net/ipv6/icmp.c
··· 209 209 * this lookup should be more aggressive (not longer than timeout). 210 210 */ 211 211 dst = ip6_route_output(net, sk, fl6); 212 - dev = dst_dev(dst); 212 + rcu_read_lock(); 213 + dev = dst_dev_rcu(dst); 213 214 if (dst->error) { 214 215 IP6_INC_STATS(net, ip6_dst_idev(dst), 215 216 IPSTATS_MIB_OUTNOROUTES); ··· 225 224 if (rt->rt6i_dst.plen < 128) 226 225 tmo >>= ((128 - rt->rt6i_dst.plen)>>5); 227 226 228 - rcu_read_lock(); 229 227 peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr); 230 228 res = inet_peer_xrlim_allow(peer, tmo); 231 - rcu_read_unlock(); 232 229 } 230 + rcu_read_unlock(); 233 231 if (!res) 234 232 __ICMP6_INC_STATS(net, ip6_dst_idev(dst), 235 233 ICMP6_MIB_RATELIMITHOST);
+1 -1
net/ipv6/mcast.c
··· 180 180 rcu_read_lock(); 181 181 rt = rt6_lookup(net, group, NULL, 0, NULL, 0); 182 182 if (rt) { 183 - dev = dst_dev(&rt->dst); 183 + dev = dst_dev_rcu(&rt->dst); 184 184 dev_hold(dev); 185 185 ip6_rt_put(rt); 186 186 }
+1 -1
net/ipv6/ndisc.c
··· 505 505 506 506 ip6_nd_hdr(skb, saddr, daddr, READ_ONCE(inet6_sk(sk)->hop_limit), skb->len); 507 507 508 - dev = dst_dev(dst); 508 + dev = dst_dev_rcu(dst); 509 509 idev = __in6_dev_get(dev); 510 510 IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); 511 511
+5 -3
net/ipv6/output_core.c
··· 104 104 int ip6_dst_hoplimit(struct dst_entry *dst) 105 105 { 106 106 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); 107 + 108 + rcu_read_lock(); 107 109 if (hoplimit == 0) { 108 - struct net_device *dev = dst_dev(dst); 110 + struct net_device *dev = dst_dev_rcu(dst); 109 111 struct inet6_dev *idev; 110 112 111 - rcu_read_lock(); 112 113 idev = __in6_dev_get(dev); 113 114 if (idev) 114 115 hoplimit = READ_ONCE(idev->cnf.hop_limit); 115 116 else 116 117 hoplimit = READ_ONCE(dev_net(dev)->ipv6.devconf_all->hop_limit); 117 - rcu_read_unlock(); 118 118 } 119 + rcu_read_unlock(); 120 + 119 121 return hoplimit; 120 122 } 121 123 EXPORT_SYMBOL(ip6_dst_hoplimit);
+3 -4
net/ipv6/route.c
··· 2943 2943 2944 2944 if (res.f6i->nh) { 2945 2945 struct fib6_nh_match_arg arg = { 2946 - .dev = dst_dev(dst), 2946 + .dev = dst_dev_rcu(dst), 2947 2947 .gw = &rt6->rt6i_gateway, 2948 2948 }; 2949 2949 ··· 3238 3238 3239 3239 static unsigned int ip6_default_advmss(const struct dst_entry *dst) 3240 3240 { 3241 - struct net_device *dev = dst_dev(dst); 3242 3241 unsigned int mtu = dst_mtu(dst); 3243 3242 struct net *net; 3244 3243 ··· 3245 3246 3246 3247 rcu_read_lock(); 3247 3248 3248 - net = dev_net_rcu(dev); 3249 + net = dst_dev_net_rcu(dst); 3249 3250 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) 3250 3251 mtu = net->ipv6.sysctl.ip6_rt_min_advmss; 3251 3252 ··· 4300 4301 4301 4302 if (res.f6i->nh) { 4302 4303 struct fib6_nh_match_arg arg = { 4303 - .dev = dst_dev(dst), 4304 + .dev = dst_dev_rcu(dst), 4304 4305 .gw = &rt->rt6i_gateway, 4305 4306 }; 4306 4307