* [BUG] net/sched: skb leak with HTB + fq_codel on packet drops @ 2026-04-06 14:29 Damilola Bello 2026-04-07 16:38 ` Fernando Fernandez Mancera 0 siblings, 1 reply; 3+ messages in thread From: Damilola Bello @ 2026-04-06 14:29 UTC (permalink / raw) To: netdev, linux-kernel Description: Using fq_codel as a child qdisc under HTB results in continuous growth of skbuff_head_cache objects when packet drops occur. Memory is not freed even after traffic stops, and the system can eventually run out of memory. Regression: - Works on: 6.18.16 - Fails on: 6.19.x (tested on 6.19.10-200.fc43) Environment: - Kernel: 6.19.10-200.fc43 - Distro: Fedora 43 - NICs: ens2f0np0, ens2f1np1 - GRO/GSO/TSO: disabled Reproduction: #!/bin/sh DEVS="ens2f0np0 ens2f1np1" for DEV in $DEVS; do tc qdisc del dev $DEV root 2>/dev/null tc qdisc add dev $DEV root handle 1: htb default 10 tc class add dev $DEV parent 1: classid 1:10 htb rate 100mbit tc qdisc add dev $DEV parent 1:10 handle 10: fq_codel tc filter add dev $DEV parent 1: matchall flowid 1:10 done Generate traffic exceeding 100mbit (e.g., iperf3) to force drops. Observed behavior: - fq_codel reports packet drops - skbuff_head_cache grows continuously: - grep skbuff_head_cache /proc/slabinfo skbuff_head_cache 12144512 ... (continues increasing) - skbuff_head_cache doesn't clear off even after traffic stops. Key observations: - Leak only occurs when fq_codel drops packets - No drops -> no leak - HTB + pfifo -> no leak - fq_codel as root qdisc -> no leak - cake as root qdisc -> no leak - The leak only occurs when fq_codel (or cake) is used as a child qdisc under HTB Expected behavior: - SKBs should be freed after drops - skbuff_head_cache should stabilize after traffic stops Additional notes: - This appears related to skb lifetime/accounting during drop handling in the HTB + child qdisc path - Possibly related to GRO/GSO interaction or skb segmentation handling Request: - Is this a known regression? - Any guidance on further debugging or identifying the offending commit? ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [BUG] net/sched: skb leak with HTB + fq_codel on packet drops 2026-04-06 14:29 [BUG] net/sched: skb leak with HTB + fq_codel on packet drops Damilola Bello @ 2026-04-07 16:38 ` Fernando Fernandez Mancera 2026-04-07 19:38 ` Damilola Bello 0 siblings, 1 reply; 3+ messages in thread From: Fernando Fernandez Mancera @ 2026-04-07 16:38 UTC (permalink / raw) To: Damilola Bello, netdev, linux-kernel On 4/6/26 4:29 PM, Damilola Bello wrote: > Description: > > Using fq_codel as a child qdisc under HTB results in continuous growth > of skbuff_head_cache objects when packet drops occur. Memory is not > freed even after traffic stops, and the system can eventually run out > of memory. > > Regression: > > - Works on: 6.18.16 > > - Fails on: 6.19.x (tested on 6.19.10-200.fc43) > > Environment: > > - Kernel: 6.19.10-200.fc43 > > - Distro: Fedora 43 > > - NICs: ens2f0np0, ens2f1np1 > > - GRO/GSO/TSO: disabled > > Reproduction: > > #!/bin/sh > DEVS="ens2f0np0 ens2f1np1" > for DEV in $DEVS; do > tc qdisc del dev $DEV root 2>/dev/null > tc qdisc add dev $DEV root handle 1: htb default 10 > tc class add dev $DEV parent 1: classid 1:10 htb rate 100mbit > tc qdisc add dev $DEV parent 1:10 handle 10: fq_codel > tc filter add dev $DEV parent 1: matchall flowid 1:10 > done > > Generate traffic exceeding 100mbit (e.g., iperf3) to force drops. > Hi, I managed to reproduce this and did a bisect. This commit introduces the issue: commit a6efc273ab8245722eee2150fa12cf75781dc410 Author: Eric Dumazet <edumazet@google.com> Date: Fri Nov 21 08:32:56 2025 +0000 net_sched: use qdisc_dequeue_drop() in cake, codel, fq_codel cake, codel and fq_codel can drop many packets from dequeue(). Use qdisc_dequeue_drop() so that the freeing can happen outside of the qdisc spinlock scope. Add TCQ_F_DEQUEUE_DROPS to sch->flags. Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20251121083256.674562-15-edumazet@google.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> I tested this solution a bit and seems to be fine. We could probably just drop directly if the qdisc isn't the root.. but I believe this is cleaner and more future-proof. diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index c3d657359a3d..61ba54e909f2 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -1170,12 +1170,18 @@ static inline void tcf_kfree_skb_list(struct sk_buff *skb) static inline void qdisc_dequeue_drop(struct Qdisc *q, struct sk_buff *skb, enum skb_drop_reason reason) { + struct Qdisc *root = qdisc_root_sleeping(q); + DEBUG_NET_WARN_ON_ONCE(!(q->flags & TCQ_F_DEQUEUE_DROPS)); DEBUG_NET_WARN_ON_ONCE(q->flags & TCQ_F_NOLOCK); - tcf_set_drop_reason(skb, reason); - skb->next = q->to_free; - q->to_free = skb; + if (root->flags & TCQ_F_DEQUEUE_DROPS) { + tcf_set_drop_reason(skb, reason); + skb->next = q->to_free; + q->to_free = skb; + } else { + kfree_skb_reason(skb, reason); + } } /* Instead of calling kfree_skb() while root qdisc lock is held, Of course, in this situation if the root qdisc does not support TCQ_F_DEQUEUE_DROPS flag then, the child won't use the optimization. If I am not wrong all the qdiscs that can be parent currently do not support TCQ_F_DEQUEUE_DROPS. Anyway, this generic fix is in my opinion cleaner than handling every caller. I am sending this as patch for net tree. Thanks, Fernando. ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [BUG] net/sched: skb leak with HTB + fq_codel on packet drops 2026-04-07 16:38 ` Fernando Fernandez Mancera @ 2026-04-07 19:38 ` Damilola Bello 0 siblings, 0 replies; 3+ messages in thread From: Damilola Bello @ 2026-04-07 19:38 UTC (permalink / raw) To: Fernando Fernandez Mancera; +Cc: netdev, linux-kernel Yes, that's the commit that caused this. Fix looks good. Thanks. On Tue, Apr 7, 2026 at 12:39 PM Fernando Fernandez Mancera <fmancera@suse.de> wrote: > > On 4/6/26 4:29 PM, Damilola Bello wrote: > > Description: > > > > Using fq_codel as a child qdisc under HTB results in continuous growth > > of skbuff_head_cache objects when packet drops occur. Memory is not > > freed even after traffic stops, and the system can eventually run out > > of memory. > > > > Regression: > > > > - Works on: 6.18.16 > > > > - Fails on: 6.19.x (tested on 6.19.10-200.fc43) > > > > Environment: > > > > - Kernel: 6.19.10-200.fc43 > > > > - Distro: Fedora 43 > > > > - NICs: ens2f0np0, ens2f1np1 > > > > - GRO/GSO/TSO: disabled > > > > Reproduction: > > > > #!/bin/sh > > DEVS="ens2f0np0 ens2f1np1" > > for DEV in $DEVS; do > > tc qdisc del dev $DEV root 2>/dev/null > > tc qdisc add dev $DEV root handle 1: htb default 10 > > tc class add dev $DEV parent 1: classid 1:10 htb rate 100mbit > > tc qdisc add dev $DEV parent 1:10 handle 10: fq_codel > > tc filter add dev $DEV parent 1: matchall flowid 1:10 > > done > > > > Generate traffic exceeding 100mbit (e.g., iperf3) to force drops. > > > > Hi, > > I managed to reproduce this and did a bisect. This commit introduces the > issue: > > commit a6efc273ab8245722eee2150fa12cf75781dc410 > Author: Eric Dumazet <edumazet@google.com> > Date: Fri Nov 21 08:32:56 2025 +0000 > > net_sched: use qdisc_dequeue_drop() in cake, codel, fq_codel > > cake, codel and fq_codel can drop many packets from dequeue(). > > Use qdisc_dequeue_drop() so that the freeing can happen > outside of the qdisc spinlock scope. > > Add TCQ_F_DEQUEUE_DROPS to sch->flags. > > Signed-off-by: Eric Dumazet <edumazet@google.com> > Link: > https://patch.msgid.link/20251121083256.674562-15-edumazet@google.com > Signed-off-by: Paolo Abeni <pabeni@redhat.com> > > > I tested this solution a bit and seems to be fine. We could probably > just drop directly if the qdisc isn't the root.. but I believe this is > cleaner and more future-proof. > > diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h > index c3d657359a3d..61ba54e909f2 100644 > --- a/include/net/sch_generic.h > +++ b/include/net/sch_generic.h > @@ -1170,12 +1170,18 @@ static inline void tcf_kfree_skb_list(struct > sk_buff *skb) > static inline void qdisc_dequeue_drop(struct Qdisc *q, struct sk_buff > *skb, > enum skb_drop_reason reason) > { > + struct Qdisc *root = qdisc_root_sleeping(q); > + > DEBUG_NET_WARN_ON_ONCE(!(q->flags & TCQ_F_DEQUEUE_DROPS)); > DEBUG_NET_WARN_ON_ONCE(q->flags & TCQ_F_NOLOCK); > > - tcf_set_drop_reason(skb, reason); > - skb->next = q->to_free; > - q->to_free = skb; > + if (root->flags & TCQ_F_DEQUEUE_DROPS) { > + tcf_set_drop_reason(skb, reason); > + skb->next = q->to_free; > + q->to_free = skb; > + } else { > + kfree_skb_reason(skb, reason); > + } > } > > /* Instead of calling kfree_skb() while root qdisc lock is held, > > Of course, in this situation if the root qdisc does not support > TCQ_F_DEQUEUE_DROPS flag then, the child won't use the optimization. If > I am not wrong all the qdiscs that can be parent currently do not > support TCQ_F_DEQUEUE_DROPS. Anyway, this generic fix is in my opinion > cleaner than handling every caller. > > I am sending this as patch for net tree. > > Thanks, > Fernando. ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-04-07 19:38 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-06 14:29 [BUG] net/sched: skb leak with HTB + fq_codel on packet drops Damilola Bello 2026-04-07 16:38 ` Fernando Fernandez Mancera 2026-04-07 19:38 ` Damilola Bello
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox