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

net: use dst_dev_rcu() in sk_setup_caps()

Use RCU to protect accesses to dst->dev from sk_setup_caps()
and sk_dst_gso_max_size().

Also use dst_dev_rcu() in ip6_dst_mtu_maybe_forward(),
and ip_dst_mtu_maybe_forward().

ip4_dst_hoplimit() can use dst_dev_net_rcu().

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-6-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
99a2ace6 11709573

+16 -10
+4 -2
include/net/ip.h
··· 467 467 bool forwarding) 468 468 { 469 469 const struct rtable *rt = dst_rtable(dst); 470 + const struct net_device *dev; 470 471 unsigned int mtu, res; 471 472 struct net *net; 472 473 473 474 rcu_read_lock(); 474 475 475 - net = dev_net_rcu(dst_dev(dst)); 476 + dev = dst_dev_rcu(dst); 477 + net = dev_net_rcu(dev); 476 478 if (READ_ONCE(net->ipv4.sysctl_ip_fwd_use_pmtu) || 477 479 ip_mtu_locked(dst) || 478 480 !forwarding) { ··· 488 486 if (mtu) 489 487 goto out; 490 488 491 - mtu = READ_ONCE(dst_dev(dst)->mtu); 489 + mtu = READ_ONCE(dev->mtu); 492 490 493 491 if (unlikely(ip_mtu_locked(dst))) { 494 492 if (rt->rt_uses_gateway && mtu > 576)
+1 -1
include/net/ip6_route.h
··· 337 337 338 338 mtu = IPV6_MIN_MTU; 339 339 rcu_read_lock(); 340 - idev = __in6_dev_get(dst_dev(dst)); 340 + idev = __in6_dev_get(dst_dev_rcu(dst)); 341 341 if (idev) 342 342 mtu = READ_ONCE(idev->cnf.mtu6); 343 343 rcu_read_unlock();
+1 -1
include/net/route.h
··· 390 390 const struct net *net; 391 391 392 392 rcu_read_lock(); 393 - net = dev_net_rcu(dst_dev(dst)); 393 + net = dst_dev_net_rcu(dst); 394 394 hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl); 395 395 rcu_read_unlock(); 396 396 }
+10 -6
net/core/sock.c
··· 2587 2587 } 2588 2588 EXPORT_SYMBOL_GPL(sk_clone_lock); 2589 2589 2590 - static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst) 2590 + static u32 sk_dst_gso_max_size(struct sock *sk, const struct net_device *dev) 2591 2591 { 2592 2592 bool is_ipv6 = false; 2593 2593 u32 max_size; ··· 2597 2597 !ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)); 2598 2598 #endif 2599 2599 /* pairs with the WRITE_ONCE() in netif_set_gso(_ipv4)_max_size() */ 2600 - max_size = is_ipv6 ? READ_ONCE(dst_dev(dst)->gso_max_size) : 2601 - READ_ONCE(dst_dev(dst)->gso_ipv4_max_size); 2600 + max_size = is_ipv6 ? READ_ONCE(dev->gso_max_size) : 2601 + READ_ONCE(dev->gso_ipv4_max_size); 2602 2602 if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk)) 2603 2603 max_size = GSO_LEGACY_MAX_SIZE; 2604 2604 ··· 2607 2607 2608 2608 void sk_setup_caps(struct sock *sk, struct dst_entry *dst) 2609 2609 { 2610 + const struct net_device *dev; 2610 2611 u32 max_segs = 1; 2611 2612 2612 - sk->sk_route_caps = dst_dev(dst)->features; 2613 + rcu_read_lock(); 2614 + dev = dst_dev_rcu(dst); 2615 + sk->sk_route_caps = dev->features; 2613 2616 if (sk_is_tcp(sk)) { 2614 2617 struct inet_connection_sock *icsk = inet_csk(sk); 2615 2618 ··· 2628 2625 sk->sk_route_caps &= ~NETIF_F_GSO_MASK; 2629 2626 } else { 2630 2627 sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; 2631 - sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dst); 2628 + sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dev); 2632 2629 /* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */ 2633 - max_segs = max_t(u32, READ_ONCE(dst_dev(dst)->gso_max_segs), 1); 2630 + max_segs = max_t(u32, READ_ONCE(dev->gso_max_segs), 1); 2634 2631 } 2635 2632 } 2636 2633 sk->sk_gso_max_segs = max_segs; 2637 2634 sk_dst_set(sk, dst); 2635 + rcu_read_unlock(); 2638 2636 } 2639 2637 EXPORT_SYMBOL_GPL(sk_setup_caps); 2640 2638