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

ipv6: adopt skb_dst_dev() and skb_dst_dev_net[_rcu]() helpers

Use the new helpers as a step to deal with potential dst->dev races.

v2: fix typo in ipv6_rthdr_rcv() (kernel test robot <lkp@intel.com>)

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250630121934.3399505-10-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
93d1cff3 1caf2729

+41 -37
+1 -1
include/net/inet6_hashtables.h
··· 150 150 int iif, int sdif, 151 151 bool *refcounted) 152 152 { 153 - struct net *net = dev_net_rcu(skb_dst(skb)->dev); 153 + struct net *net = skb_dst_dev_net_rcu(skb); 154 154 const struct ipv6hdr *ip6h = ipv6_hdr(skb); 155 155 struct sock *sk; 156 156
+1 -1
include/net/ip6_tunnel.h
··· 159 159 memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); 160 160 IP6CB(skb)->flags = ip6cb_flags; 161 161 pkt_len = skb->len - skb_inner_network_offset(skb); 162 - err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb); 162 + err = ip6_local_out(skb_dst_dev_net(skb), sk, skb); 163 163 164 164 if (dev) { 165 165 if (unlikely(net_xmit_eval(err)))
+4 -4
net/ipv6/exthdrs.c
··· 460 460 return -1; 461 461 } 462 462 463 - if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) { 463 + if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) { 464 464 if (ipv6_hdr(skb)->hop_limit <= 1) { 465 465 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 466 466 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ··· 621 621 return -1; 622 622 } 623 623 624 - if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) { 624 + if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) { 625 625 if (ipv6_hdr(skb)->hop_limit <= 1) { 626 626 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 627 627 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ··· 783 783 kfree_skb(skb); 784 784 return -1; 785 785 } 786 - if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) { 786 + if (!ipv6_chk_home_addr(skb_dst_dev_net(skb), addr)) { 787 787 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); 788 788 kfree_skb(skb); 789 789 return -1; ··· 809 809 return -1; 810 810 } 811 811 812 - if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) { 812 + if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) { 813 813 if (ipv6_hdr(skb)->hop_limit <= 1) { 814 814 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 815 815 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
+9 -8
net/ipv6/ioam6.c
··· 696 696 struct ioam6_schema *sc, 697 697 u8 sclen, bool is_input) 698 698 { 699 + struct net_device *dev = skb_dst_dev(skb); 699 700 struct timespec64 ts; 700 701 ktime_t tstamp; 701 702 u64 raw64; ··· 713 712 if (is_input) 714 713 byte--; 715 714 716 - raw32 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id; 715 + raw32 = dev_net(dev)->ipv6.sysctl.ioam6_id; 717 716 718 717 *(__be32 *)data = cpu_to_be32((byte << 24) | raw32); 719 718 data += sizeof(__be32); ··· 729 728 *(__be16 *)data = cpu_to_be16(raw16); 730 729 data += sizeof(__be16); 731 730 732 - if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) 731 + if (dev->flags & IFF_LOOPBACK) 733 732 raw16 = IOAM6_U16_UNAVAILABLE; 734 733 else 735 - raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id); 734 + raw16 = (__force u16)READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id); 736 735 737 736 *(__be16 *)data = cpu_to_be16(raw16); 738 737 data += sizeof(__be16); ··· 784 783 struct Qdisc *qdisc; 785 784 __u32 qlen, backlog; 786 785 787 - if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) { 786 + if (dev->flags & IFF_LOOPBACK) { 788 787 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 789 788 } else { 790 - queue = skb_get_tx_queue(skb_dst(skb)->dev, skb); 789 + queue = skb_get_tx_queue(dev, skb); 791 790 qdisc = rcu_dereference(queue->qdisc); 792 791 qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog); 793 792 ··· 808 807 if (is_input) 809 808 byte--; 810 809 811 - raw64 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id_wide; 810 + raw64 = dev_net(dev)->ipv6.sysctl.ioam6_id_wide; 812 811 813 812 *(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64); 814 813 data += sizeof(__be64); ··· 824 823 *(__be32 *)data = cpu_to_be32(raw32); 825 824 data += sizeof(__be32); 826 825 827 - if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) 826 + if (dev->flags & IFF_LOOPBACK) 828 827 raw32 = IOAM6_U32_UNAVAILABLE; 829 828 else 830 - raw32 = READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide); 829 + raw32 = READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id_wide); 831 830 832 831 *(__be32 *)data = cpu_to_be32(raw32); 833 832 data += sizeof(__be32);
+4 -2
net/ipv6/ip6_input.c
··· 187 187 * arrived via the sending interface (ethX), because of the 188 188 * nature of scoping architecture. --yoshfuji 189 189 */ 190 - IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; 190 + IP6CB(skb)->iif = skb_valid_dst(skb) ? 191 + ip6_dst_idev(skb_dst(skb))->dev->ifindex : 192 + dev->ifindex; 191 193 192 194 if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) 193 195 goto err; ··· 506 504 struct net_device *dev; 507 505 bool deliver; 508 506 509 - __IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev), 507 + __IP6_UPD_PO_STATS(skb_dst_dev_net(skb), 510 508 __in6_dev_get_safely(skb->dev), IPSTATS_MIB_INMCAST, 511 509 skb->len); 512 510
+3 -2
net/ipv6/ip6_output.c
··· 232 232 233 233 int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb) 234 234 { 235 - struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev; 236 - struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); 235 + struct dst_entry *dst = skb_dst(skb); 236 + struct net_device *dev = dst_dev(dst), *indev = skb->dev; 237 + struct inet6_dev *idev = ip6_dst_idev(dst); 237 238 238 239 skb->protocol = htons(ETH_P_IPV6); 239 240 skb->dev = dev;
+1 -1
net/ipv6/ip6_tunnel.c
··· 632 632 } else { 633 633 if (ip_route_input(skb2, eiph->daddr, eiph->saddr, 634 634 ip4h_dscp(eiph), skb2->dev) || 635 - skb_dst(skb2)->dev->type != ARPHRD_TUNNEL6) 635 + skb_dst_dev(skb2)->type != ARPHRD_TUNNEL6) 636 636 goto out; 637 637 } 638 638
+1 -1
net/ipv6/ip6_vti.c
··· 529 529 xmit: 530 530 skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev))); 531 531 skb_dst_set(skb, dst); 532 - skb->dev = skb_dst(skb)->dev; 532 + skb->dev = dst_dev(dst); 533 533 534 534 err = dst_output(t->net, skb->sk, skb); 535 535 if (net_xmit_eval(err) == 0)
+2 -2
net/ipv6/netfilter.c
··· 24 24 { 25 25 const struct ipv6hdr *iph = ipv6_hdr(skb); 26 26 struct sock *sk = sk_to_full_sk(sk_partial); 27 - struct net_device *dev = skb_dst(skb)->dev; 27 + struct net_device *dev = skb_dst_dev(skb); 28 28 struct flow_keys flkeys; 29 29 unsigned int hh_len; 30 30 struct dst_entry *dst; ··· 72 72 #endif 73 73 74 74 /* Change in oif may mean change in hh_len. */ 75 - hh_len = skb_dst(skb)->dev->hard_header_len; 75 + hh_len = skb_dst_dev(skb)->hard_header_len; 76 76 if (skb_headroom(skb) < hh_len && 77 77 pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)), 78 78 0, GFP_ATOMIC))
+1 -1
net/ipv6/netfilter/nf_reject_ipv6.c
··· 300 300 skb_dst_set(oldskb, dst); 301 301 } 302 302 303 - fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev); 303 + fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst_dev(oldskb)); 304 304 fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark); 305 305 security_skb_classify_flow(oldskb, flowi6_to_flowi_common(&fl6)); 306 306 dst = ip6_route_output(net, NULL, &fl6);
+1 -1
net/ipv6/output_core.c
··· 141 141 skb->protocol = htons(ETH_P_IPV6); 142 142 143 143 return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, 144 - net, sk, skb, NULL, skb_dst(skb)->dev, 144 + net, sk, skb, NULL, skb_dst_dev(skb), 145 145 dst_output); 146 146 } 147 147 EXPORT_SYMBOL_GPL(__ip6_local_out);
+5 -5
net/ipv6/reassembly.c
··· 104 104 return container_of(q, struct frag_queue, q); 105 105 } 106 106 107 - static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, 107 + static int ip6_frag_queue(struct net *net, 108 + struct frag_queue *fq, struct sk_buff *skb, 108 109 struct frag_hdr *fhdr, int nhoff, 109 110 u32 *prob_offset, int *refs) 110 111 { 111 - struct net *net = dev_net(skb_dst(skb)->dev); 112 112 int offset, end, fragsize; 113 113 struct sk_buff *prev_tail; 114 114 struct net_device *dev; ··· 324 324 325 325 static int ipv6_frag_rcv(struct sk_buff *skb) 326 326 { 327 + const struct ipv6hdr *hdr = ipv6_hdr(skb); 328 + struct net *net = skb_dst_dev_net(skb); 327 329 struct frag_hdr *fhdr; 328 330 struct frag_queue *fq; 329 - const struct ipv6hdr *hdr = ipv6_hdr(skb); 330 - struct net *net = dev_net(skb_dst(skb)->dev); 331 331 u8 nexthdr; 332 332 int iif; 333 333 ··· 384 384 spin_lock(&fq->q.lock); 385 385 386 386 fq->iif = iif; 387 - ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff, 387 + ret = ip6_frag_queue(net, fq, skb, fhdr, IP6CB(skb)->nhoff, 388 388 &prob_offset, &refs); 389 389 390 390 spin_unlock(&fq->q.lock);
+2 -2
net/ipv6/route.c
··· 4631 4631 4632 4632 static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb) 4633 4633 { 4634 - skb->dev = skb_dst(skb)->dev; 4634 + skb->dev = skb_dst_dev(skb); 4635 4635 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES); 4636 4636 } 4637 4637 ··· 4642 4642 4643 4643 static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb) 4644 4644 { 4645 - skb->dev = skb_dst(skb)->dev; 4645 + skb->dev = skb_dst_dev(skb); 4646 4646 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); 4647 4647 } 4648 4648
+3 -3
net/ipv6/seg6_iptunnel.c
··· 364 364 365 365 #ifdef CONFIG_IPV6_SEG6_HMAC 366 366 if (sr_has_hmac(isrh)) { 367 - struct net *net = dev_net(skb_dst(skb)->dev); 367 + struct net *net = skb_dst_dev_net(skb); 368 368 369 369 err = seg6_push_hmac(net, &hdr->saddr, isrh); 370 370 if (unlikely(err)) ··· 530 530 531 531 static int seg6_input_nf(struct sk_buff *skb) 532 532 { 533 - struct net_device *dev = skb_dst(skb)->dev; 533 + struct net_device *dev = skb_dst_dev(skb); 534 534 struct net *net = dev_net(skb->dev); 535 535 536 536 switch (skb->protocol) { ··· 616 616 617 617 static int seg6_output_nf(struct net *net, struct sock *sk, struct sk_buff *skb) 618 618 { 619 - struct net_device *dev = skb_dst(skb)->dev; 619 + struct net_device *dev = skb_dst_dev(skb); 620 620 621 621 switch (skb->protocol) { 622 622 case htons(ETH_P_IP):
+2 -2
net/ipv6/tcp_ipv6.c
··· 868 868 int oif, int rst, u8 tclass, __be32 label, 869 869 u32 priority, u32 txhash, struct tcp_key *key) 870 870 { 871 - struct net *net = sk ? sock_net(sk) : dev_net_rcu(skb_dst(skb)->dev); 871 + struct net *net = sk ? sock_net(sk) : skb_dst_dev_net_rcu(skb); 872 872 unsigned int tot_len = sizeof(struct tcphdr); 873 873 struct sock *ctl_sk = net->ipv6.tcp_sk; 874 874 const struct tcphdr *th = tcp_hdr(skb); ··· 1043 1043 if (!sk && !ipv6_unicast_destination(skb)) 1044 1044 return; 1045 1045 1046 - net = sk ? sock_net(sk) : dev_net_rcu(skb_dst(skb)->dev); 1046 + net = sk ? sock_net(sk) : skb_dst_dev_net_rcu(skb); 1047 1047 /* Invalid TCP option size or twice included auth */ 1048 1048 if (tcp_parse_auth_options(th, &md5_hash_location, &aoh)) 1049 1049 return;
+1 -1
net/ipv6/xfrm6_output.c
··· 106 106 int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) 107 107 { 108 108 return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, 109 - net, sk, skb, skb->dev, skb_dst(skb)->dev, 109 + net, sk, skb, skb->dev, skb_dst_dev(skb), 110 110 __xfrm6_output, 111 111 !(IP6CB(skb)->flags & IP6SKB_REROUTED)); 112 112 }