]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: sched: sfq: convert to qdisc drop reasons
authorJesper Dangaard Brouer <hawk@kernel.org>
Thu, 26 Feb 2026 13:44:19 +0000 (14:44 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sat, 28 Feb 2026 23:31:34 +0000 (15:31 -0800)
Convert SFQ to use the new qdisc-specific drop reason infrastructure.

This patch demonstrates how to convert a flow-based qdisc to use the
new enum qdisc_drop_reason. As part of this conversion:

- Add QDISC_DROP_MAXFLOWS for flow table exhaustion
- Rename FQ_FLOW_LIMIT to generic FLOW_LIMIT, now shared by FQ and SFQ
- Use QDISC_DROP_OVERLIMIT for sfq_drop() when overall limit exceeded
- Use QDISC_DROP_FLOW_LIMIT for per-flow depth limit exceeded

The FLOW_LIMIT reason is now a common drop reason for per-flow limits,
applicable to both FQ and SFQ qdiscs.

Signed-off-by: Jesper Dangaard Brouer <hawk@kernel.org>
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://patch.msgid.link/177211345946.3011628.12770616071857185664.stgit@firesoul
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/dropreason-qdisc.h
net/sched/sch_fq.c
net/sched/sch_sfq.c

index 80a2d557e5f7f0e24db19e4eba8debbfa99bed3e..02a9f580411b90e9b3f6553c41223640c0723ad0 100644 (file)
@@ -9,10 +9,11 @@
        FN(GENERIC)                     \
        FN(OVERLIMIT)                   \
        FN(CONGESTED)                   \
+       FN(MAXFLOWS)                    \
        FN(CAKE_FLOOD)                  \
        FN(FQ_BAND_LIMIT)               \
        FN(FQ_HORIZON_LIMIT)            \
-       FN(FQ_FLOW_LIMIT)               \
+       FN(FLOW_LIMIT)                  \
        FNe(MAX)
 
 #undef FN
@@ -59,6 +60,13 @@ enum qdisc_drop_reason {
         * congestion to the sender and prevent bufferbloat.
         */
        QDISC_DROP_CONGESTED,
+       /**
+        * @QDISC_DROP_MAXFLOWS: packet dropped because the qdisc's flow
+        * tracking table is full and no free slots are available to allocate
+        * for a new flow. This indicates flow table exhaustion in flow-based
+        * qdiscs that maintain per-flow state (e.g., SFQ).
+        */
+       QDISC_DROP_MAXFLOWS,
        /**
         * @QDISC_DROP_CAKE_FLOOD: CAKE qdisc dropped packet due to flood
         * protection mechanism (BLUE algorithm). This indicates potential
@@ -77,10 +85,12 @@ enum qdisc_drop_reason {
         */
        QDISC_DROP_FQ_HORIZON_LIMIT,
        /**
-        * @QDISC_DROP_FQ_FLOW_LIMIT: FQ dropped packet because an individual
-        * flow exceeded its per-flow packet limit.
+        * @QDISC_DROP_FLOW_LIMIT: packet dropped because an individual flow
+        * exceeded its per-flow packet/depth limit. Used by FQ and SFQ qdiscs
+        * to enforce per-flow fairness and prevent a single flow from
+        * monopolizing queue resources.
         */
-       QDISC_DROP_FQ_FLOW_LIMIT,
+       QDISC_DROP_FLOW_LIMIT,
        /**
         * @QDISC_DROP_MAX: the maximum of qdisc drop reasons, which
         * shouldn't be used as a real 'reason' - only for tracing code gen
index 81322187bbe251d3d331b1e43e3c135ef0e9bd6e..eb5ae2b15cc0c2d65d6a7340dcf72d45cdd33cdd 100644 (file)
@@ -578,7 +578,7 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
                if (unlikely(f->qlen >= q->flow_plimit)) {
                        q->stat_flows_plimit++;
                        return qdisc_drop_reason(skb, sch, to_free,
-                                                QDISC_DROP_FQ_FLOW_LIMIT);
+                                                QDISC_DROP_FLOW_LIMIT);
                }
 
                if (fq_flow_is_detached(f)) {
index 503d7d3ca081782ee967fda63b4c045e7a3956d4..c3f3181dba5424eb9d26362a1628653bb9392e89 100644 (file)
@@ -302,7 +302,7 @@ drop:
                sfq_dec(q, x);
                sch->q.qlen--;
                qdisc_qstats_backlog_dec(sch, skb);
-               qdisc_drop(skb, sch, to_free);
+               qdisc_drop_reason(skb, sch, to_free, QDISC_DROP_OVERLIMIT);
                return len;
        }
 
@@ -363,7 +363,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
        if (x == SFQ_EMPTY_SLOT) {
                x = q->dep[0].next; /* get a free slot */
                if (x >= SFQ_MAX_FLOWS)
-                       return qdisc_drop(skb, sch, to_free);
+                       return qdisc_drop_reason(skb, sch, to_free, QDISC_DROP_MAXFLOWS);
                q->ht[hash] = x;
                slot = &q->slots[x];
                slot->hash = hash;
@@ -420,14 +420,14 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
        if (slot->qlen >= q->maxdepth) {
 congestion_drop:
                if (!sfq_headdrop(q))
-                       return qdisc_drop(skb, sch, to_free);
+                       return qdisc_drop_reason(skb, sch, to_free, QDISC_DROP_FLOW_LIMIT);
 
                /* We know we have at least one packet in queue */
                head = slot_dequeue_head(slot);
                delta = qdisc_pkt_len(head) - qdisc_pkt_len(skb);
                sch->qstats.backlog -= delta;
                slot->backlog -= delta;
-               qdisc_drop(head, sch, to_free);
+               qdisc_drop_reason(head, sch, to_free, QDISC_DROP_FLOW_LIMIT);
 
                slot_queue_add(slot, skb);
                qdisc_tree_reduce_backlog(sch, 0, delta);