]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net_sched: use qdisc_skb_cb(skb)->pkt_segs in bstats_update()
authorEric Dumazet <edumazet@google.com>
Fri, 21 Nov 2025 08:32:47 +0000 (08:32 +0000)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 25 Nov 2025 15:10:32 +0000 (16:10 +0100)
Avoid up to two cache line misses in qdisc dequeue() to fetch
skb_shinfo(skb)->gso_segs/gso_size while qdisc spinlock is held.

This gives a 5 % improvement in a TX intensive workload.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20251121083256.674562-6-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/sch_generic.h
net/sched/sch_cake.c
net/sched/sch_dualpi2.c
net/sched/sch_netem.c
net/sched/sch_qfq.c
net/sched/sch_taprio.c
net/sched/sch_tbf.c

index 9cd8b5d4b23698fd8959ef40c303468e31c1d4af..cdf7a58ebcf5ef2b5f8b76eb6fbe92d5f0e07899 100644 (file)
@@ -829,6 +829,15 @@ static inline unsigned int qdisc_pkt_len(const struct sk_buff *skb)
        return qdisc_skb_cb(skb)->pkt_len;
 }
 
+static inline unsigned int qdisc_pkt_segs(const struct sk_buff *skb)
+{
+       u32 pkt_segs = qdisc_skb_cb(skb)->pkt_segs;
+
+       DEBUG_NET_WARN_ON_ONCE(pkt_segs !=
+                       (skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1));
+       return pkt_segs;
+}
+
 /* additional qdisc xmit flags (NET_XMIT_MASK in linux/netdevice.h) */
 enum net_xmit_qdisc_t {
        __NET_XMIT_STOLEN = 0x00010000,
@@ -870,9 +879,7 @@ static inline void _bstats_update(struct gnet_stats_basic_sync *bstats,
 static inline void bstats_update(struct gnet_stats_basic_sync *bstats,
                                 const struct sk_buff *skb)
 {
-       _bstats_update(bstats,
-                      qdisc_pkt_len(skb),
-                      skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1);
+       _bstats_update(bstats, qdisc_pkt_len(skb), qdisc_pkt_segs(skb));
 }
 
 static inline void qdisc_bstats_cpu_update(struct Qdisc *sch,
index 9213129f0de10bc67ce418f77c36fed2581f3781..a20880034aa5eacec0c25977406104448b336397 100644 (file)
@@ -1800,6 +1800,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
                skb_list_walk_safe(segs, segs, nskb) {
                        skb_mark_not_on_list(segs);
                        qdisc_skb_cb(segs)->pkt_len = segs->len;
+                       qdisc_skb_cb(segs)->pkt_segs = 1;
                        cobalt_set_enqueue_time(segs, now);
                        get_cobalt_cb(segs)->adjusted_len = cake_overhead(q,
                                                                          segs);
index 4b975feb52b1f3d3b37b31713d1477de5f5806d9..6d7e6389758dc8e645b1116efe4e11fb7290ac86 100644 (file)
@@ -475,6 +475,7 @@ static int dualpi2_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
                         * (3) Enqueue fragment & set ts in dualpi2_enqueue_skb
                         */
                        qdisc_skb_cb(nskb)->pkt_len = nskb->len;
+                       qdisc_skb_cb(nskb)->pkt_segs = 1;
                        dualpi2_skb_cb(nskb)->classified =
                                dualpi2_skb_cb(skb)->classified;
                        dualpi2_skb_cb(nskb)->ect = dualpi2_skb_cb(skb)->ect;
index eafc316ae319e3f8c23b0cb0c58fdf54be102213..32a5f33040461f3be952055c097b5f2fe760a858 100644 (file)
@@ -429,6 +429,7 @@ static struct sk_buff *netem_segment(struct sk_buff *skb, struct Qdisc *sch,
        struct sk_buff *segs;
        netdev_features_t features = netif_skb_features(skb);
 
+       qdisc_skb_cb(skb)->pkt_segs = 1;
        segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
 
        if (IS_ERR_OR_NULL(segs)) {
index 2255355e51d350eded4549c1584b60d4d9b00fff..d920f57dc6d7659c510a98956c6dd2ed9e5ee5b8 100644 (file)
@@ -1250,7 +1250,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
                }
        }
 
-       gso_segs = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
+       gso_segs = qdisc_pkt_segs(skb);
        err = qdisc_enqueue(skb, cl->qdisc, to_free);
        if (unlikely(err != NET_XMIT_SUCCESS)) {
                pr_debug("qfq_enqueue: enqueue failed %d\n", err);
index 39b735386996eb59712a1fc28f7bb903ec1b2220..300d577b328699eb42d2b829ecfc76464fd7b186 100644 (file)
@@ -595,6 +595,7 @@ static int taprio_enqueue_segmented(struct sk_buff *skb, struct Qdisc *sch,
        skb_list_walk_safe(segs, segs, nskb) {
                skb_mark_not_on_list(segs);
                qdisc_skb_cb(segs)->pkt_len = segs->len;
+               qdisc_skb_cb(segs)->pkt_segs = 1;
                slen += segs->len;
 
                /* FIXME: we should be segmenting to a smaller size
index 4c977f049670a600eafd219c898e5f29597be2c1..f2340164f579a25431979e12ec3d23ab828edd16 100644 (file)
@@ -221,6 +221,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch,
                skb_mark_not_on_list(segs);
                seg_len = segs->len;
                qdisc_skb_cb(segs)->pkt_len = seg_len;
+               qdisc_skb_cb(segs)->pkt_segs = 1;
                ret = qdisc_enqueue(segs, q->qdisc, to_free);
                if (ret != NET_XMIT_SUCCESS) {
                        if (net_xmit_drop_count(ret))