From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mail.toke.dk; dkim=pass header.d=mojatatu.com header.i=@mojatatu.com header.a=rsa-sha256 header.s=google header.b=Zd0Lnk1p; arc=none (Message is not ARC signed); dmarc=none Received: from mail-qk1-x72b.google.com (mail-qk1-x72b.google.com [IPv6:2607:f8b0:4864:20::72b]) by mail.toke.dk (Postfix) with ESMTPS id 1BFCC17E7A7A for ; Wed, 14 Oct 2026 11:55:39 +0200 (CEST) Received: by mail-qk1-x72b.google.com with SMTP id af79cd13be357-93e6f83f0bbso362051185a.2 for ; Wed, 14 Oct 2026 02:55:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu.com; s=google; t=1791971738; x=1792576538; darn=lists.bufferbloat.net; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=QQV0Fcz4XhYiKhgXtDp98wuypaR6LNxiYitvQA87yVg=; b=Zd0Lnk1p5BHfPR16VlaSey7V5p61ZVg8GwQXYbPPYkdjOTmVO3ppPS8Elo0etCV00W 6jXQP1dMf8OoceKlQXUB23yhSTQX5qW2xhx5Hig8LJLII/R0Lhr0aXDGbEkdLF8OH6/e rYd7ubRS9mcg0XcWF9LL7OovIB+M41Mrdzj00= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791971738; x=1792576538; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=QQV0Fcz4XhYiKhgXtDp98wuypaR6LNxiYitvQA87yVg=; b=fdM/p2o8uCn8d5/WDgxV1QaGwC6G9y7k6GzkRokddY87YEVGwiCFQsi652FSSBZJDC uPupf9aNi4TIHSduM72B2RrBNGcFM984gmPGFOCBXfIf+acnusuM9uJxw3/aFiHPgVPU 1gkRLWr9zWCHJdd954VQYkeTDLehSRvKCy8OjaOfuE23WHa1+CDSe2vmS+jCEw0Vofiq Pr3pvse4KL+UL2AjDxAxKbIjX9K7DVKsd/yNi4fjbeTuo5jRVm4ZDmmKfxY8ZbJD1/ck PWcMNjbpDeg4v03nirpWl+fLI8FiqmdGPLDp5NsibIZSLc77OebOLIJMe0fpnxGEy3Se QSpw== X-Forwarded-Encrypted: i=1; AKwUvBzyTH+nrbZ1hRxS9wS8WLX7jCvAt+TYQ1ohYDAibwO7i9BQ5/fqOl5+YxsTQ2jlCzkCALMQ@lists.bufferbloat.net X-Gm-Message-State: AFq9FYKD8dwEheyvW83GRSFG1wHNhVOClfBGiGCdVjMypBFdhBS0W6YL T3Tv/4GtOdQ8cWCmBrX5vfx3j6ir0w0dwoOvxd1cRg78Pcs7OLC4lCpNGHqBCzC7HA== X-Gm-Gg: AYBFou2X9KsI+toGPoEkmlyvlTqKDfUDzorLb9pC6dZ5EbwmnciN/j6ZAzA3XAhE+79 +ae/kOQeXg5rMJTHW1xjUyU5YbTW/00aVrgt76MC5Sjxsuc1kPASRId6228lewWWoO6XFnpFZ4j sFBWSFuy/le8/y7ReNX4uzxCMdhvNCYf8XsHKcM9A0HQFiE0NkTUle5FnMuSxQOnB+Ez6bxeHec rPrCVjwGN41REzqdC7h2o8QCJOhVxI1uO4stjXqKPYW2qLdQvPEwkh9CRw8yAdYky7LJBouSqZJ tetKn7gS4ghddtUKVQWGU5Y7KE8WAfsVl4aEarV6X6LMIpKo36GryZFpIW7KtxdRq4nK622efiZ R9CTXf1a6rLisoeAIF3G8iPabYDLWznpbofW2MyUsKo3pTVzbBZ7CtS5tSWDAJ5VLk+BxYiH5mY QgHaQ2CId7FwOcGhRs5+sfr4TVYwuRMxKYQpxo2724+L6WzfR9YOMyuUhga+IU5ImdK2JqtqtYw RSzL0zqSo/jKjMDgfTwy/lMq6/GWG1PRcWYf8LP3R4zWgGua/XBSukNc+NX X-Received: by 2002:a05:620a:6f0e:b0:93c:8f50:8c65 with SMTP id af79cd13be357-93ebd2763bdmr2371964185a.64.1791971738420; Wed, 14 Oct 2026 02:55:38 -0700 (PDT) Received: from mbili.tail33bf8.ts.net ([64.203.83.2]) by smtp.gmail.com with ESMTPSA id af79cd13be357-93ef5055eb3sm453074985a.33.2026.10.14.02.55.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Oct 2026 02:55:37 -0700 (PDT) From: Jamal Hadi Salim To: netdev@vger.kernel.org Cc: Jamal Hadi Salim , Jiri Pirko , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Victor Nogueira , =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= , cake@lists.bufferbloat.net, Sashiko Date: Wed, 14 Oct 2026 05:55:29 -0400 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: 7BEEGIPOVRFWYQZ3MYBYVPNHLZY6XGS7 X-Message-ID-Hash: 7BEEGIPOVRFWYQZ3MYBYVPNHLZY6XGS7 X-MailFrom: jhs@mojatatu.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list Subject: [Cake] [PATCH net-next v6 1/4] net/sched: cake, fq_codel: return the classifier result to the caller List-Id: Cake - FQ_codel the next generation Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The Fix: cake and fq_codel run an optional external classifier from their enqueue path and then compute the flow hash inside the helper. Have the helper return the filter's overrides (cake) or a 1-based flow index or a request to hash (fq_codel) instead, so the caller owns the flow selection. This is preparation for the accounting changes that follow. Packet classification and flow selection are unchanged. Reviewed-by: Victor Nogueira Signed-off-by: Jamal Hadi Salim --- v5 -> v6: split out of the single v5 patch; the classifier refactor is unchanged. --- net/sched/sch_cake.c | 35 ++++++++++++++++++++------------ net/sched/sch_fq_codel.c | 44 ++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index dc93267029e7..6432d10c992e 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -1712,18 +1712,24 @@ static struct cake_tin_data *cake_select_tin(struct Qdisc *sch, return &qd->tins[tin]; } -static u32 cake_classify(struct Qdisc *sch, struct cake_tin_data **t, - struct sk_buff *skb, int flow_mode, int *qerr) +/* Run the qdisc's optional external classifier. Returns true when a + * terminal TC action consumed the packet, with the reason in *qerr; + * otherwise *flow and *host hold the filter's overrides (0 if none). + */ +static bool cake_tcf_classify(struct Qdisc *sch, struct sk_buff *skb, + u16 *flow, u16 *host, int *qerr) { struct cake_sched_data *q = qdisc_priv(sch); struct tcf_proto *filter; struct tcf_result res; - u16 flow = 0, host = 0; int result; + *flow = 0; + *host = 0; + filter = rcu_dereference_bh(q->filter_list); if (!filter) - goto hash; + return false; *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; result = tcf_classify_qdisc(skb, filter, &res, false); @@ -1737,17 +1743,15 @@ static u32 cake_classify(struct Qdisc *sch, struct cake_tin_data **t, *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; fallthrough; case TC_ACT_SHOT: - return 0; + return true; } #endif if (TC_H_MIN(res.classid) <= CAKE_QUEUES) - flow = TC_H_MIN(res.classid); + *flow = TC_H_MIN(res.classid); if (TC_H_MAJ(res.classid) <= (CAKE_QUEUES << 16)) - host = TC_H_MAJ(res.classid) >> 16; + *host = TC_H_MAJ(res.classid) >> 16; } -hash: - *t = cake_select_tin(sch, skb); - return cake_hash(*t, skb, flow_mode, flow, host) + 1; + return false; } static void cake_reconfigure(struct Qdisc *sch); @@ -1758,20 +1762,25 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, u32 idx, tin, prev_qlen, prev_backlog, drop_id; struct cake_sched_data *q = qdisc_priv(sch); int len = qdisc_pkt_len(skb), ret; + u16 flow_override, host_override; struct sk_buff *ack = NULL; ktime_t now = ktime_get(); struct cake_tin_data *b; struct cake_flow *flow; bool same_flow = false; - /* choose flow to insert into */ - idx = cake_classify(sch, &b, skb, q->config->flow_mode, &ret); - if (idx == 0) { + /* Classify first: a terminal TC action consumes the packet. */ + if (cake_tcf_classify(sch, skb, &flow_override, &host_override, &ret)) { if (ret & __NET_XMIT_BYPASS) qdisc_qstats_drop(sch); __qdisc_drop(skb, to_free); return ret; } + + /* choose flow to insert into */ + b = cake_select_tin(sch, skb); + idx = cake_hash(b, skb, q->config->flow_mode, flow_override, + host_override) + 1; tin = (u32)(b - q->tins); idx--; flow = &b->flows[idx]; diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index e6c87a32950f..4cf3d379b8e9 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -73,22 +73,35 @@ static unsigned int fq_codel_hash(const struct fq_codel_sched_data *q, return reciprocal_scale(skb_get_hash(skb), q->flows_cnt); } -static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch, - int *qerr) +/* Run the qdisc's optional external classifier. Returns true when the + * caller must drop the packet (a terminal TC action consumed it, or the + * result carried no class ID); the reason is then in *qerr. Otherwise *idx + * is the 1-based flow index, or *do_hash asks the caller to use + * fq_codel_hash(). + */ +static bool fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch, + unsigned int *idx, bool *do_hash, int *qerr) { struct fq_codel_sched_data *q = qdisc_priv(sch); struct tcf_proto *filter; struct tcf_result res; int result; + *idx = 0; + *do_hash = false; + if (TC_H_MAJ(skb->priority) == sch->handle && TC_H_MIN(skb->priority) > 0 && - TC_H_MIN(skb->priority) <= q->flows_cnt) - return TC_H_MIN(skb->priority); + TC_H_MIN(skb->priority) <= q->flows_cnt) { + *idx = TC_H_MIN(skb->priority); + return false; + } filter = rcu_dereference_bh(q->filter_list); - if (!filter) - return fq_codel_hash(q, skb) + 1; + if (!filter) { + *do_hash = true; + return false; + } *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; result = tcf_classify_qdisc(skb, filter, &res, false); @@ -101,13 +114,16 @@ static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch, *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; fallthrough; case TC_ACT_SHOT: - return 0; + return true; } #endif - if (TC_H_MIN(res.classid) <= q->flows_cnt) - return TC_H_MIN(res.classid); + if (TC_H_MIN(res.classid) > 0 && + TC_H_MIN(res.classid) <= q->flows_cnt) { + *idx = TC_H_MIN(res.classid); + return false; + } } - return 0; + return true; } /* helper functions : might be changed when/if skb use a standard list_head */ @@ -188,17 +204,19 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct fq_codel_sched_data *q = qdisc_priv(sch); unsigned int idx, prev_backlog, prev_qlen; struct fq_codel_flow *flow; - int ret; + bool do_hash = false; unsigned int pkt_len; bool memory_limited; + int ret; - idx = fq_codel_classify(skb, sch, &ret); - if (idx == 0) { + if (fq_codel_classify(skb, sch, &idx, &do_hash, &ret)) { if (ret & __NET_XMIT_BYPASS) qdisc_qstats_drop(sch); __qdisc_drop(skb, to_free); return ret; } + if (do_hash) + idx = fq_codel_hash(q, skb) + 1; idx--; codel_set_enqueue_time(skb); -- 2.43.0