Re: [PATCH v1 net 1/1] net/sched: sch_dualpi2: fix limit/memlimit enforcement when dequeueing L-queue
From: Paolo Abeni
Date: Thu Apr 16 2026 - 09:34:15 EST
On 4/13/26 6:37 PM, chia-yu.chang@xxxxxxxxxxxxxxxxxxx wrote:
> From: Chia-Yu Chang <chia-yu.chang@xxxxxxxxxxxxxxxxxxx>
>
> Fix dualpi2_change() to correctly enforce updated limit and memlimit values
> after a configuration change of the dualpi2 qdisc.
>
> Before this patch, dualpi2_change() always attempted to dequeue packets via
> the root qdisc (C-queue) when reducing backlog or memory usage, and
> unconditionally assumed that a valid skb will be returned. When traffic
> classification results in packets being queued in the L-queue while the
> C-queue is empty, this leads to a NULL skb dereference during limit or
> memlimit enforcement.
>
> This is fixed by first dequeuing from the C-queue path if it is non-empty.
> Once the C-queue is empty, packets are dequeued directly from the L-queue.
> Return values from qdisc_dequeue_internal() are checked for both queues. When
> dequeuing from the L-queue, the parent qdisc qlen and backlog counters are
> updated explicitly to keep overall qdisc statistics consistent.
>
> Fixes: 320d031ad6e4 ("sched: Struct definition and parsing of dualpi2 qdisc")
> Signed-off-by: Chia-Yu Chang <chia-yu.chang@xxxxxxxxxxxxxxxxxxx>
> ---
> net/sched/sch_dualpi2.c | 24 +++++++++++++++++++-----
> 1 file changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c
> index 6d7e6389758d..56d4422970b6 100644
> --- a/net/sched/sch_dualpi2.c
> +++ b/net/sched/sch_dualpi2.c
> @@ -872,11 +872,25 @@ static int dualpi2_change(struct Qdisc *sch, struct nlattr *opt,
> old_backlog = sch->qstats.backlog;
> while (qdisc_qlen(sch) > sch->limit ||
> q->memory_used > q->memory_limit) {
> - struct sk_buff *skb = qdisc_dequeue_internal(sch, true);
> -
> - q->memory_used -= skb->truesize;
> - qdisc_qstats_backlog_dec(sch, skb);
> - rtnl_qdisc_drop(skb, sch);
> + int c_len = qdisc_qlen(sch) - qdisc_qlen(q->l_queue);
> + struct sk_buff *skb = NULL;
> +
> + if (c_len) {
> + skb = qdisc_dequeue_internal(sch, true);
> + if (!skb)
> + break;
> + q->memory_used -= skb->truesize;
> + rtnl_qdisc_drop(skb, sch);
> + } else if (qdisc_qlen(q->l_queue)) {
> + skb = qdisc_dequeue_internal(q->l_queue, true);
> + if (!skb)
> + break;
> + q->memory_used -= skb->truesize;
> + rtnl_qdisc_drop(skb, q->l_queue);
> + /* Keep the overall qdisc stats consistent */
> + --sch->q.qlen;
> + qdisc_qstats_backlog_dec(sch, skb);
Sashiko says:
---
The drop counter is incremented for the L-queue via rtnl_qdisc_drop(),
but it appears the drop counter for the parent qdisc (sch) is not updated.
Will this cause user-facing statistics for the overall dualpi2 qdisc to
underreport drops?
---