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: 4a6ce2b6f2 ("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>
This commit is contained in:
Eric Dumazet 2025-08-28 19:58:20 +00:00 committed by Jakub Kicinski
parent 11709573cc
commit 99a2ace61b
4 changed files with 16 additions and 10 deletions

View File

@ -467,12 +467,14 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
bool forwarding) bool forwarding)
{ {
const struct rtable *rt = dst_rtable(dst); const struct rtable *rt = dst_rtable(dst);
const struct net_device *dev;
unsigned int mtu, res; unsigned int mtu, res;
struct net *net; struct net *net;
rcu_read_lock(); rcu_read_lock();
net = dev_net_rcu(dst_dev(dst)); dev = dst_dev_rcu(dst);
net = dev_net_rcu(dev);
if (READ_ONCE(net->ipv4.sysctl_ip_fwd_use_pmtu) || if (READ_ONCE(net->ipv4.sysctl_ip_fwd_use_pmtu) ||
ip_mtu_locked(dst) || ip_mtu_locked(dst) ||
!forwarding) { !forwarding) {
@ -486,7 +488,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
if (mtu) if (mtu)
goto out; goto out;
mtu = READ_ONCE(dst_dev(dst)->mtu); mtu = READ_ONCE(dev->mtu);
if (unlikely(ip_mtu_locked(dst))) { if (unlikely(ip_mtu_locked(dst))) {
if (rt->rt_uses_gateway && mtu > 576) if (rt->rt_uses_gateway && mtu > 576)

View File

@ -337,7 +337,7 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dst
mtu = IPV6_MIN_MTU; mtu = IPV6_MIN_MTU;
rcu_read_lock(); rcu_read_lock();
idev = __in6_dev_get(dst_dev(dst)); idev = __in6_dev_get(dst_dev_rcu(dst));
if (idev) if (idev)
mtu = READ_ONCE(idev->cnf.mtu6); mtu = READ_ONCE(idev->cnf.mtu6);
rcu_read_unlock(); rcu_read_unlock();

View File

@ -390,7 +390,7 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
const struct net *net; const struct net *net;
rcu_read_lock(); rcu_read_lock();
net = dev_net_rcu(dst_dev(dst)); net = dst_dev_net_rcu(dst);
hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl); hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
rcu_read_unlock(); rcu_read_unlock();
} }

View File

@ -2587,7 +2587,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
} }
EXPORT_SYMBOL_GPL(sk_clone_lock); EXPORT_SYMBOL_GPL(sk_clone_lock);
static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst) static u32 sk_dst_gso_max_size(struct sock *sk, const struct net_device *dev)
{ {
bool is_ipv6 = false; bool is_ipv6 = false;
u32 max_size; u32 max_size;
@ -2597,8 +2597,8 @@ static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst)
!ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)); !ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr));
#endif #endif
/* pairs with the WRITE_ONCE() in netif_set_gso(_ipv4)_max_size() */ /* pairs with the WRITE_ONCE() in netif_set_gso(_ipv4)_max_size() */
max_size = is_ipv6 ? READ_ONCE(dst_dev(dst)->gso_max_size) : max_size = is_ipv6 ? READ_ONCE(dev->gso_max_size) :
READ_ONCE(dst_dev(dst)->gso_ipv4_max_size); READ_ONCE(dev->gso_ipv4_max_size);
if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk)) if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk))
max_size = GSO_LEGACY_MAX_SIZE; max_size = GSO_LEGACY_MAX_SIZE;
@ -2607,9 +2607,12 @@ static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst)
void sk_setup_caps(struct sock *sk, struct dst_entry *dst) void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
{ {
const struct net_device *dev;
u32 max_segs = 1; u32 max_segs = 1;
sk->sk_route_caps = dst_dev(dst)->features; rcu_read_lock();
dev = dst_dev_rcu(dst);
sk->sk_route_caps = dev->features;
if (sk_is_tcp(sk)) { if (sk_is_tcp(sk)) {
struct inet_connection_sock *icsk = inet_csk(sk); struct inet_connection_sock *icsk = inet_csk(sk);
@ -2625,13 +2628,14 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
sk->sk_route_caps &= ~NETIF_F_GSO_MASK; sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
} else { } else {
sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dst); sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dev);
/* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */ /* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */
max_segs = max_t(u32, READ_ONCE(dst_dev(dst)->gso_max_segs), 1); max_segs = max_t(u32, READ_ONCE(dev->gso_max_segs), 1);
} }
} }
sk->sk_gso_max_segs = max_segs; sk->sk_gso_max_segs = max_segs;
sk_dst_set(sk, dst); sk_dst_set(sk, dst);
rcu_read_unlock();
} }
EXPORT_SYMBOL_GPL(sk_setup_caps); EXPORT_SYMBOL_GPL(sk_setup_caps);