]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ipv6: adopt skb_dst_dev() and skb_dst_dev_net[_rcu]() helpers
authorEric Dumazet <edumazet@google.com>
Mon, 30 Jun 2025 12:19:33 +0000 (12:19 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 2 Jul 2025 21:32:30 +0000 (14:32 -0700)
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>
16 files changed:
include/net/inet6_hashtables.h
include/net/ip6_tunnel.h
net/ipv6/exthdrs.c
net/ipv6/ioam6.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/netfilter.c
net/ipv6/netfilter/nf_reject_ipv6.c
net/ipv6/output_core.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/seg6_iptunnel.c
net/ipv6/tcp_ipv6.c
net/ipv6/xfrm6_output.c

index c32878c69179dac5a7fcfa098a297420d9adfab2..ab3929a2a95697a0e417cf4a4e3b355f3a68a78c 100644 (file)
@@ -150,7 +150,7 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
                                              int iif, int sdif,
                                              bool *refcounted)
 {
-       struct net *net = dev_net_rcu(skb_dst(skb)->dev);
+       struct net *net = skb_dst_dev_net_rcu(skb);
        const struct ipv6hdr *ip6h = ipv6_hdr(skb);
        struct sock *sk;
 
index dd163495f3539f1e3522c0c8d8715e5b0dd91b27..120db2865811250ea9ddbf3bc5396c20a90e1937 100644 (file)
@@ -159,7 +159,7 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
        memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
        IP6CB(skb)->flags = ip6cb_flags;
        pkt_len = skb->len - skb_inner_network_offset(skb);
-       err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
+       err = ip6_local_out(skb_dst_dev_net(skb), sk, skb);
 
        if (dev) {
                if (unlikely(net_xmit_eval(err)))
index 1947530fb20ac17dcd6660703e3e94d584d5f688..d1ef9644f82629cde1307eaa2d21a69f2793e946 100644 (file)
@@ -460,7 +460,7 @@ looped_back:
                return -1;
        }
 
-       if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
+       if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) {
                if (ipv6_hdr(skb)->hop_limit <= 1) {
                        __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
                        icmpv6_send(skb, ICMPV6_TIME_EXCEED,
@@ -621,7 +621,7 @@ looped_back:
                return -1;
        }
 
-       if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
+       if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) {
                if (ipv6_hdr(skb)->hop_limit <= 1) {
                        __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
                        icmpv6_send(skb, ICMPV6_TIME_EXCEED,
@@ -783,7 +783,7 @@ looped_back:
                        kfree_skb(skb);
                        return -1;
                }
-               if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
+               if (!ipv6_chk_home_addr(skb_dst_dev_net(skb), addr)) {
                        __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
                        kfree_skb(skb);
                        return -1;
@@ -809,7 +809,7 @@ looped_back:
                return -1;
        }
 
-       if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
+       if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) {
                if (ipv6_hdr(skb)->hop_limit <= 1) {
                        __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
                        icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
index a84d332f952f66fb59554ee64057859d2c3f8c09..9553a32000813469265cacea4511fa74c1737c21 100644 (file)
@@ -696,6 +696,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
                                    struct ioam6_schema *sc,
                                    u8 sclen, bool is_input)
 {
+       struct net_device *dev = skb_dst_dev(skb);
        struct timespec64 ts;
        ktime_t tstamp;
        u64 raw64;
@@ -712,7 +713,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
                if (is_input)
                        byte--;
 
-               raw32 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id;
+               raw32 = dev_net(dev)->ipv6.sysctl.ioam6_id;
 
                *(__be32 *)data = cpu_to_be32((byte << 24) | raw32);
                data += sizeof(__be32);
@@ -728,10 +729,10 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
                *(__be16 *)data = cpu_to_be16(raw16);
                data += sizeof(__be16);
 
-               if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
+               if (dev->flags & IFF_LOOPBACK)
                        raw16 = IOAM6_U16_UNAVAILABLE;
                else
-                       raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id);
+                       raw16 = (__force u16)READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id);
 
                *(__be16 *)data = cpu_to_be16(raw16);
                data += sizeof(__be16);
@@ -783,10 +784,10 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
                struct Qdisc *qdisc;
                __u32 qlen, backlog;
 
-               if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
+               if (dev->flags & IFF_LOOPBACK) {
                        *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
                } else {
-                       queue = skb_get_tx_queue(skb_dst(skb)->dev, skb);
+                       queue = skb_get_tx_queue(dev, skb);
                        qdisc = rcu_dereference(queue->qdisc);
                        qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog);
 
@@ -807,7 +808,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
                if (is_input)
                        byte--;
 
-               raw64 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id_wide;
+               raw64 = dev_net(dev)->ipv6.sysctl.ioam6_id_wide;
 
                *(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64);
                data += sizeof(__be64);
@@ -823,10 +824,10 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
                *(__be32 *)data = cpu_to_be32(raw32);
                data += sizeof(__be32);
 
-               if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
+               if (dev->flags & IFF_LOOPBACK)
                        raw32 = IOAM6_U32_UNAVAILABLE;
                else
-                       raw32 = READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide);
+                       raw32 = READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id_wide);
 
                *(__be32 *)data = cpu_to_be32(raw32);
                data += sizeof(__be32);
index 39da6a7ce5f1245145dd74d4ac4eae63dd970939..16953bd0096047f9b5fbb8e66bf9cc591e6693aa 100644 (file)
@@ -187,7 +187,9 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
         * arrived via the sending interface (ethX), because of the
         * nature of scoping architecture. --yoshfuji
         */
-       IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex;
+       IP6CB(skb)->iif = skb_valid_dst(skb) ?
+                               ip6_dst_idev(skb_dst(skb))->dev->ifindex :
+                               dev->ifindex;
 
        if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
                goto err;
@@ -504,7 +506,7 @@ int ip6_mc_input(struct sk_buff *skb)
        struct net_device *dev;
        bool deliver;
 
-       __IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev),
+       __IP6_UPD_PO_STATS(skb_dst_dev_net(skb),
                         __in6_dev_get_safely(skb->dev), IPSTATS_MIB_INMCAST,
                         skb->len);
 
index f494b4ece6b7cf08522abd20817c7a37432ab37e..877bee7ffee9284cf88cb13a79e8bf777b470bb9 100644 (file)
@@ -232,8 +232,9 @@ static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
 
 int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
-       struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev;
-       struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
+       struct dst_entry *dst = skb_dst(skb);
+       struct net_device *dev = dst_dev(dst), *indev = skb->dev;
+       struct inet6_dev *idev = ip6_dst_idev(dst);
 
        skb->protocol = htons(ETH_P_IPV6);
        skb->dev = dev;
index cd8a4141e5c0e36cbfc363a5acb2668932e2adbd..3262e81223dfc859a06b55087d5dac20f43e6c11 100644 (file)
@@ -632,7 +632,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        } else {
                if (ip_route_input(skb2, eiph->daddr, eiph->saddr,
                                   ip4h_dscp(eiph), skb2->dev) ||
-                   skb_dst(skb2)->dev->type != ARPHRD_TUNNEL6)
+                   skb_dst_dev(skb2)->type != ARPHRD_TUNNEL6)
                        goto out;
        }
 
index 2a86de922d42710b110057c23daad2f63fc69fe2..ad5290be4dd61dd98a6f6b4fd3a2161b3f44bf23 100644 (file)
@@ -529,7 +529,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
 xmit:
        skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
        skb_dst_set(skb, dst);
-       skb->dev = skb_dst(skb)->dev;
+       skb->dev = dst_dev(dst);
 
        err = dst_output(t->net, skb->sk, skb);
        if (net_xmit_eval(err) == 0)
index 4541836ee3da207b163123f432d45647b6f869f7..45f9105f9ac1e1497c6471b01ce515d4d8672eed 100644 (file)
@@ -24,7 +24,7 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
 {
        const struct ipv6hdr *iph = ipv6_hdr(skb);
        struct sock *sk = sk_to_full_sk(sk_partial);
-       struct net_device *dev = skb_dst(skb)->dev;
+       struct net_device *dev = skb_dst_dev(skb);
        struct flow_keys flkeys;
        unsigned int hh_len;
        struct dst_entry *dst;
@@ -72,7 +72,7 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
 #endif
 
        /* Change in oif may mean change in hh_len. */
-       hh_len = skb_dst(skb)->dev->hard_header_len;
+       hh_len = skb_dst_dev(skb)->hard_header_len;
        if (skb_headroom(skb) < hh_len &&
            pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)),
                             0, GFP_ATOMIC))
index 9ae2b2725bf99ab0c6057032996b7f249fb6f45c..838295fa32e36426a07645d215920d373e742f91 100644 (file)
@@ -300,7 +300,7 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
                skb_dst_set(oldskb, dst);
        }
 
-       fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
+       fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst_dev(oldskb));
        fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
        security_skb_classify_flow(oldskb, flowi6_to_flowi_common(&fl6));
        dst = ip6_route_output(net, NULL, &fl6);
index 90a178dd24aaeb44b69ad4abc9da6fa1c10f46d1..d21fe27fe21e344b694e0378214fbad04c4844d2 100644 (file)
@@ -141,7 +141,7 @@ int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
        skb->protocol = htons(ETH_P_IPV6);
 
        return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
-                      net, sk, skb, NULL, skb_dst(skb)->dev,
+                      net, sk, skb, NULL, skb_dst_dev(skb),
                       dst_output);
 }
 EXPORT_SYMBOL_GPL(__ip6_local_out);
index 7d4bcf3fda5bac556b032e38934c6bc40d4f2ec9..25ec8001898df76eba08233c182e0c7154c1c1b7 100644 (file)
@@ -104,11 +104,11 @@ fq_find(struct net *net, __be32 id, const struct ipv6hdr *hdr, int iif)
        return container_of(q, struct frag_queue, q);
 }
 
-static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
+static int ip6_frag_queue(struct net *net,
+                         struct frag_queue *fq, struct sk_buff *skb,
                          struct frag_hdr *fhdr, int nhoff,
                          u32 *prob_offset, int *refs)
 {
-       struct net *net = dev_net(skb_dst(skb)->dev);
        int offset, end, fragsize;
        struct sk_buff *prev_tail;
        struct net_device *dev;
@@ -324,10 +324,10 @@ out_fail:
 
 static int ipv6_frag_rcv(struct sk_buff *skb)
 {
+       const struct ipv6hdr *hdr = ipv6_hdr(skb);
+       struct net *net = skb_dst_dev_net(skb);
        struct frag_hdr *fhdr;
        struct frag_queue *fq;
-       const struct ipv6hdr *hdr = ipv6_hdr(skb);
-       struct net *net = dev_net(skb_dst(skb)->dev);
        u8 nexthdr;
        int iif;
 
@@ -384,7 +384,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
                spin_lock(&fq->q.lock);
 
                fq->iif = iif;
-               ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff,
+               ret = ip6_frag_queue(net, fq, skb, fhdr, IP6CB(skb)->nhoff,
                                     &prob_offset, &refs);
 
                spin_unlock(&fq->q.lock);
index dacfe1284918bffc75d1b41745c8873b9132bfc6..3fbe0885c21c6e2dcab27d47b09dd71764762794 100644 (file)
@@ -4631,7 +4631,7 @@ static int ip6_pkt_discard(struct sk_buff *skb)
 
 static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
-       skb->dev = skb_dst(skb)->dev;
+       skb->dev = skb_dst_dev(skb);
        return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
 }
 
@@ -4642,7 +4642,7 @@ static int ip6_pkt_prohibit(struct sk_buff *skb)
 
 static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
-       skb->dev = skb_dst(skb)->dev;
+       skb->dev = skb_dst_dev(skb);
        return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
 }
 
index 27918fc0c9721d777965a819863169f3bde5114c..3e1b9991131a233a3e6b080d6213e3eec946e81b 100644 (file)
@@ -364,7 +364,7 @@ static int __seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
        if (sr_has_hmac(isrh)) {
-               struct net *net = dev_net(skb_dst(skb)->dev);
+               struct net *net = skb_dst_dev_net(skb);
 
                err = seg6_push_hmac(net, &hdr->saddr, isrh);
                if (unlikely(err))
@@ -530,7 +530,7 @@ drop:
 
 static int seg6_input_nf(struct sk_buff *skb)
 {
-       struct net_device *dev = skb_dst(skb)->dev;
+       struct net_device *dev = skb_dst_dev(skb);
        struct net *net = dev_net(skb->dev);
 
        switch (skb->protocol) {
@@ -616,7 +616,7 @@ drop:
 
 static int seg6_output_nf(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
-       struct net_device *dev = skb_dst(skb)->dev;
+       struct net_device *dev = skb_dst_dev(skb);
 
        switch (skb->protocol) {
        case htons(ETH_P_IP):
index ed0b891885d848b25667edbaf4e925b3ece46033..8f2c3cba1f1fa4c1074cb020722508726588c3ac 100644 (file)
@@ -868,7 +868,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
                                 int oif, int rst, u8 tclass, __be32 label,
                                 u32 priority, u32 txhash, struct tcp_key *key)
 {
-       struct net *net = sk ? sock_net(sk) : dev_net_rcu(skb_dst(skb)->dev);
+       struct net *net = sk ? sock_net(sk) : skb_dst_dev_net_rcu(skb);
        unsigned int tot_len = sizeof(struct tcphdr);
        struct sock *ctl_sk = net->ipv6.tcp_sk;
        const struct tcphdr *th = tcp_hdr(skb);
@@ -1043,7 +1043,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb,
        if (!sk && !ipv6_unicast_destination(skb))
                return;
 
-       net = sk ? sock_net(sk) : dev_net_rcu(skb_dst(skb)->dev);
+       net = sk ? sock_net(sk) : skb_dst_dev_net_rcu(skb);
        /* Invalid TCP option size or twice included auth */
        if (tcp_parse_auth_options(th, &md5_hash_location, &aoh))
                return;
index b3d5d1f266eeea6bea32d81feede4c1076f2f829..512bdaf136997a29698029560b37992ae806a9e8 100644 (file)
@@ -106,7 +106,7 @@ skip_frag:
 int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
        return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
-                           net, sk, skb,  skb->dev, skb_dst(skb)->dev,
+                           net, sk, skb,  skb->dev, skb_dst_dev(skb),
                            __xfrm6_output,
                            !(IP6CB(skb)->flags & IP6SKB_REROUTED));
 }