Skip to content

Commit 864ecc4

Browse files
committed
Merge branch 'net-add-rcu-safety-to-dst-dev'
Eric Dumazet says: ==================== net: add rcu safety to dst->dev Followup of commit 88fe142 ("net: dst: add four helpers to annotate data-races around dst->dev"). Use lockdep enabled helpers to convert our unsafe dst->dev uses one at a time. More to come... ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents e71aa5a + 6ad8de3 commit 864ecc4

File tree

19 files changed

+99
-75
lines changed

19 files changed

+99
-75
lines changed

include/net/dst.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
struct sk_buff;
2525

2626
struct dst_entry {
27-
struct net_device *dev;
27+
union {
28+
struct net_device *dev;
29+
struct net_device __rcu *dev_rcu;
30+
};
2831
struct dst_ops *ops;
2932
unsigned long _metrics;
3033
unsigned long expires;
@@ -570,9 +573,12 @@ static inline struct net_device *dst_dev(const struct dst_entry *dst)
570573

571574
static inline struct net_device *dst_dev_rcu(const struct dst_entry *dst)
572575
{
573-
/* In the future, use rcu_dereference(dst->dev) */
574-
WARN_ON_ONCE(!rcu_read_lock_held());
575-
return READ_ONCE(dst->dev);
576+
return rcu_dereference(dst->dev_rcu);
577+
}
578+
579+
static inline struct net *dst_dev_net_rcu(const struct dst_entry *dst)
580+
{
581+
return dev_net_rcu(dst_dev_rcu(dst));
576582
}
577583

578584
static inline struct net_device *skb_dst_dev(const struct sk_buff *skb)
@@ -592,7 +598,7 @@ static inline struct net *skb_dst_dev_net(const struct sk_buff *skb)
592598

593599
static inline struct net *skb_dst_dev_net_rcu(const struct sk_buff *skb)
594600
{
595-
return dev_net_rcu(skb_dst_dev(skb));
601+
return dev_net_rcu(skb_dst_dev_rcu(skb));
596602
}
597603

598604
struct dst_entry *dst_blackhole_check(struct dst_entry *dst, u32 cookie);

include/net/ip.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,12 +467,14 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
467467
bool forwarding)
468468
{
469469
const struct rtable *rt = dst_rtable(dst);
470+
const struct net_device *dev;
470471
unsigned int mtu, res;
471472
struct net *net;
472473

473474
rcu_read_lock();
474475

475-
net = dev_net_rcu(dst_dev(dst));
476+
dev = dst_dev_rcu(dst);
477+
net = dev_net_rcu(dev);
476478
if (READ_ONCE(net->ipv4.sysctl_ip_fwd_use_pmtu) ||
477479
ip_mtu_locked(dst) ||
478480
!forwarding) {
@@ -486,7 +488,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
486488
if (mtu)
487489
goto out;
488490

489-
mtu = READ_ONCE(dst_dev(dst)->mtu);
491+
mtu = READ_ONCE(dev->mtu);
490492

491493
if (unlikely(ip_mtu_locked(dst))) {
492494
if (rt->rt_uses_gateway && mtu > 576)

include/net/ip6_route.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dst
337337

338338
mtu = IPV6_MIN_MTU;
339339
rcu_read_lock();
340-
idev = __in6_dev_get(dst_dev(dst));
340+
idev = __in6_dev_get(dst_dev_rcu(dst));
341341
if (idev)
342342
mtu = READ_ONCE(idev->cnf.mtu6);
343343
rcu_read_unlock();

include/net/route.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
390390
const struct net *net;
391391

392392
rcu_read_lock();
393-
net = dev_net_rcu(dst_dev(dst));
393+
net = dst_dev_net_rcu(dst);
394394
hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
395395
rcu_read_unlock();
396396
}

net/core/dst.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ void dst_dev_put(struct dst_entry *dst)
150150
dst->ops->ifdown(dst, dev);
151151
WRITE_ONCE(dst->input, dst_discard);
152152
WRITE_ONCE(dst->output, dst_discard_out);
153-
WRITE_ONCE(dst->dev, blackhole_netdev);
153+
rcu_assign_pointer(dst->dev_rcu, blackhole_netdev);
154154
netdev_ref_replace(dev, blackhole_netdev, &dst->dev_tracker,
155155
GFP_ATOMIC);
156156
}

net/core/sock.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2587,7 +2587,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
25872587
}
25882588
EXPORT_SYMBOL_GPL(sk_clone_lock);
25892589

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)
25912591
{
25922592
bool is_ipv6 = false;
25932593
u32 max_size;
@@ -2597,8 +2597,8 @@ static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst)
25972597
!ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr));
25982598
#endif
25992599
/* 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);
26022602
if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk))
26032603
max_size = GSO_LEGACY_MAX_SIZE;
26042604

@@ -2607,9 +2607,12 @@ static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst)
26072607

26082608
void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
26092609
{
2610+
const struct net_device *dev;
26102611
u32 max_segs = 1;
26112612

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;
26132616
if (sk_is_tcp(sk)) {
26142617
struct inet_connection_sock *icsk = inet_csk(sk);
26152618

@@ -2625,13 +2628,14 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
26252628
sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
26262629
} else {
26272630
sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
2628-
sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dst);
2631+
sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dev);
26292632
/* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */
2630-
max_segs = max_t(u32, READ_ONCE(dst_dev(dst)->gso_max_segs), 1);
2633+
max_segs = max_t(u32, READ_ONCE(dev->gso_max_segs), 1);
26312634
}
26322635
}
26332636
sk->sk_gso_max_segs = max_segs;
26342637
sk_dst_set(sk, dst);
2638+
rcu_read_unlock();
26352639
}
26362640
EXPORT_SYMBOL_GPL(sk_setup_caps);
26372641

net/ipv4/icmp.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,17 +319,17 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
319319
return true;
320320

321321
/* No rate limit on loopback */
322-
dev = dst_dev(dst);
322+
rcu_read_lock();
323+
dev = dst_dev_rcu(dst);
323324
if (dev && (dev->flags & IFF_LOOPBACK))
324325
goto out;
325326

326-
rcu_read_lock();
327327
peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr,
328328
l3mdev_master_ifindex_rcu(dev));
329329
rc = inet_peer_xrlim_allow(peer,
330330
READ_ONCE(net->ipv4.sysctl_icmp_ratelimit));
331-
rcu_read_unlock();
332331
out:
332+
rcu_read_unlock();
333333
if (!rc)
334334
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
335335
else

net/ipv4/ip_fragment.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,14 +476,16 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
476476
/* Process an incoming IP datagram fragment. */
477477
int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
478478
{
479-
struct net_device *dev = skb->dev ? : skb_dst_dev(skb);
480-
int vif = l3mdev_master_ifindex_rcu(dev);
479+
struct net_device *dev;
481480
struct ipq *qp;
481+
int vif;
482482

483483
__IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS);
484484

485485
/* Lookup (or create) queue header */
486486
rcu_read_lock();
487+
dev = skb->dev ? : skb_dst_dev_rcu(skb);
488+
vif = l3mdev_master_ifindex_rcu(dev);
487489
qp = ip_find(net, ip_hdr(skb), user, vif);
488490
if (qp) {
489491
int ret, refs = 0;

net/ipv4/ipmr.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,7 +1905,7 @@ static int ipmr_prepare_xmit(struct net *net, struct mr_table *mrt,
19051905
return -1;
19061906
}
19071907

1908-
encap += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;
1908+
encap += LL_RESERVED_SPACE(dst_dev_rcu(&rt->dst)) + rt->dst.header_len;
19091909

19101910
if (skb_cow(skb, encap)) {
19111911
ip_rt_put(rt);
@@ -1958,7 +1958,7 @@ static void ipmr_queue_fwd_xmit(struct net *net, struct mr_table *mrt,
19581958
* result in receiving multiple packets.
19591959
*/
19601960
NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
1961-
net, NULL, skb, skb->dev, rt->dst.dev,
1961+
net, NULL, skb, skb->dev, dst_dev_rcu(&rt->dst),
19621962
ipmr_forward_finish);
19631963
return;
19641964

@@ -2302,7 +2302,7 @@ int ip_mr_output(struct net *net, struct sock *sk, struct sk_buff *skb)
23022302

23032303
guard(rcu)();
23042304

2305-
dev = rt->dst.dev;
2305+
dev = dst_dev_rcu(&rt->dst);
23062306

23072307
if (IPCB(skb)->flags & IPSKB_FORWARDED)
23082308
goto mc_output;

net/ipv4/route.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,11 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
414414
const void *daddr)
415415
{
416416
const struct rtable *rt = container_of(dst, struct rtable, dst);
417-
struct net_device *dev = dst_dev(dst);
417+
struct net_device *dev;
418418
struct neighbour *n;
419419

420420
rcu_read_lock();
421-
421+
dev = dst_dev_rcu(dst);
422422
if (likely(rt->rt_gw_family == AF_INET)) {
423423
n = ip_neigh_gw4(dev, rt->rt_gw4);
424424
} else if (rt->rt_gw_family == AF_INET6) {
@@ -1027,7 +1027,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
10271027
return;
10281028

10291029
rcu_read_lock();
1030-
net = dev_net_rcu(dst_dev(dst));
1030+
net = dst_dev_net_rcu(dst);
10311031
if (mtu < net->ipv4.ip_rt_min_pmtu) {
10321032
lock = true;
10331033
mtu = min(old_mtu, net->ipv4.ip_rt_min_pmtu);
@@ -1327,7 +1327,7 @@ static unsigned int ipv4_default_advmss(const struct dst_entry *dst)
13271327
struct net *net;
13281328

13291329
rcu_read_lock();
1330-
net = dev_net_rcu(dst_dev(dst));
1330+
net = dst_dev_net_rcu(dst);
13311331
advmss = max_t(unsigned int, ipv4_mtu(dst) - header_size,
13321332
net->ipv4.ip_rt_min_advmss);
13331333
rcu_read_unlock();

0 commit comments

Comments
 (0)