* [PATCH net-next v8 0/3] net/sched: sch_fq_pie: add per-flow class statistics
@ 2026-09-22 20:59 Hemendra M. Naik
2026-09-22 20:59 ` [PATCH net-next v8 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Hemendra M. Naik @ 2026-09-22 20:59 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, horms, jiri, jhs, shuah,
linux-kernel, linux-kselftest, vishy0777, tahiliani,
Hemendra M. Naik
FQ-PIE runs an independent PIE controller per flow but exposes no
per-flow statistics. This series wires up fq_pie_class_ops to expose
per-flow AQM state (prob, delay, deficit, avg_dq_rate) via
'tc -s class show', following a similar pattern as FQ-CoDel.
This patch series is accompanied by a companion iproute2 patch series that
will be posted on net-next as well.
Both the kernel and iproute2 patches can also be found in GitHub:
- https://github.com/H-N41K/linux-net-next/tree/fq_pie_class_stats/
- https://github.com/H-N41K/iproute2-next/tree/fq_pie_class_stats
---
Changelog:
v8:
- No code changes since v7.
- Reword commit message to reflect usage of div_u64().
v7: https://lore.kernel.org/netdev/20260919060125.38063-1-hemendranaik@gmail.com/
- No code changes since v6.
- Rebased over the latest net-next tree and re-submitted patch.
v6: https://lore.kernel.org/netdev/20260917204225.275251-1-hemendranaik@gmail.com/
- Address Sashiko review comments:
- Revert the fq_pie flows range to [1..65536].
- Also drop the accompanying selftest 83be change.
- Compute the per-flow delay with div_u64() on the full 64-bit
nanosecond value.
- Widen avg_dq_rate to u64 before scaling it by PSCHED_TICKS_PER_SEC.
- Document the 36 to 64 byte xstats growth in the patch 1 commit message.
- Fix selftest 83c0. The ping payload exceeded the TBF burst so no
packet ever reached fq_pie, and the missing -W left the run waiting
out ping's default timeout.
v5: https://lore.kernel.org/netdev/20260902035231.81866-1-hemendranaik@gmail.com/
- Addressed Sashiko review comments:
- Omitted .tcf_block / .bind_tcf / .unbind_tcf from cl_ops (statistics
only being exported; filter attach to fq_pie is now disabled).
- Dropped empty tc_fq_pie_xqd_stats placeholder; class_stats is a direct
struct member.
- Limited flows to [1..65535] so per-flow class handles fit in a 16-bit
TC minor.
- Rewrote selftest 83c0 with TBF + fq_pie, ping traffic, and
matchCount 1 on per-flow stats output.
- Updated selftest 83be for the new flows limit.
- Dropped the tools/include UAPI mirror changes from patch 3/3.
v4: https://lore.kernel.org/netdev/20260727164056.106203-1-hemendranaik@gmail.com/
- Fixed unaligned commit message; moved typo fixes to another patch.
v3: https://lore.kernel.org/netdev/20260630183702.170798-1-hemendranaik@gmail.com/
- No changes since v2.
- Resent after the previous submission was deferred due to the
net-next tree closing during review.
- Updated corresponding iproute2 patch in response to review comments;
kernel patches unchanged.
v2: https://lore.kernel.org/netdev/20260614125000.6058-1-hemendranaik@gmail.com/
- Addressed ABI backward compatibility issue for tc_fq_pie_xstats.
v1: https://lore.kernel.org/netdev/20260531125314.22492-1-hemendranaik@gmail.com/
- Initial submission
Hemendra M. Naik (3):
net/sched: sch_fq_pie: add per-flow statistics via class ops
selftests: tc-testing: add fq_pie per-flow class stats test
net/sched: pie: correct tc_pie_xstats field documentation
include/uapi/linux/pkt_sched.h | 20 ++++-
net/sched/sch_fq_pie.c | 86 ++++++++++++++++++-
.../tc-testing/tc-tests/qdiscs/fq_pie.json | 27 ++++++
3 files changed, 130 insertions(+), 3 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH net-next v8 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops 2026-09-22 20:59 [PATCH net-next v8 0/3] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik @ 2026-09-22 20:59 ` Hemendra M. Naik 2026-09-24 21:00 ` netdev-bot+sashiko 2026-09-22 20:59 ` [PATCH net-next v8 2/3] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik 2026-09-22 20:59 ` [PATCH net-next v8 3/3] net/sched: pie: correct tc_pie_xstats field documentation Hemendra M. Naik 2 siblings, 1 reply; 6+ messages in thread From: Hemendra M. Naik @ 2026-09-22 20:59 UTC (permalink / raw) To: netdev Cc: davem, edumazet, kuba, pabeni, horms, jiri, jhs, shuah, linux-kernel, linux-kselftest, vishy0777, tahiliani, Hemendra M. Naik FQ-PIE schedules independent PIE controllers per flow but exposes no per-flow AQM state. Without class-level statistics there is no way to observe the per-flow drop probability, queue delay, deficit or dequeue rate from userspace. Extend tc_fq_pie_xstats with a type discriminator and tc_fq_pie_cl_stats for per-flow metrics. The nine existing __u32 counters keep their offsets, type is appended at offset 36 and class_stats follows it, growing the structure from 36 to 64 bytes. Wire up fq_pie_class_ops with walk, dump, and dump_stats only so that 'tc -s class show' reports per-flow state (prob, delay, deficit, avg_dq_rate, dq_rate_estimating). Filter attachment callbacks (.tcf_block, .bind_tcf, .unbind_tcf) are omitted on purpose. Derive delay with div_u64() from the full 64-bit nanosecond. Widen avg_dq_rate to u64 before scaling it by PSCHED_TICKS_PER_SEC. Signed-off-by: Hemendra M. Naik <hemendranaik@gmail.com> Signed-off-by: Vishal Kamath <vishy0777@gmail.com> Signed-off-by: Mohit P. Tahiliani <tahiliani@nitk.edu.in> --- include/uapi/linux/pkt_sched.h | 16 +++++++ net/sched/sch_fq_pie.c | 86 +++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 490efd288526..9c0c9787f0c3 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -953,6 +953,20 @@ enum { }; #define TCA_FQ_PIE_MAX (__TCA_FQ_PIE_MAX - 1) +enum { + TCA_FQ_PIE_XSTATS_QDISC, + TCA_FQ_PIE_XSTATS_CLASS, +}; + +struct tc_fq_pie_cl_stats { + __u64 prob; /* current probability */ + __u32 delay; /* current delay in microseconds */ + __s32 deficit; /* number of remaining byte credits */ + __u32 avg_dq_rate; /* current average dq_rate in + * bytes/second + */ + __u32 dq_rate_estimating; /* is avg_dq_rate being calculated? */ +}; struct tc_fq_pie_xstats { __u32 packets_in; /* total number of packets enqueued */ __u32 dropped; /* packets dropped due to fq_pie_action */ @@ -963,6 +977,8 @@ struct tc_fq_pie_xstats { __u32 new_flows_len; /* count of flows in new list */ __u32 old_flows_len; /* count of flows in old list */ __u32 memory_usage; /* total memory across all queues */ + __u32 type; + struct tc_fq_pie_cl_stats class_stats; }; /* CBS */ diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c index 5982847df8f8..3a3ef83f328b 100644 --- a/net/sched/sch_fq_pie.c +++ b/net/sched/sch_fq_pie.c @@ -511,7 +511,9 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb) static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) { struct fq_pie_sched_data *q = qdisc_priv(sch); - struct tc_fq_pie_xstats st = { 0 }; + struct tc_fq_pie_xstats st = { + .type = TCA_FQ_PIE_XSTATS_QDISC, + }; struct list_head *pos; sch_tree_lock(sch); @@ -563,7 +565,89 @@ static void fq_pie_destroy(struct Qdisc *sch) kvfree(q->flows); } +static struct Qdisc *fq_pie_leaf(struct Qdisc *sch, unsigned long arg) +{ + return NULL; +} + +static unsigned long fq_pie_find(struct Qdisc *sch, u32 classid) +{ + return 0; +} + +static int fq_pie_dump_class(struct Qdisc *sch, unsigned long cl, + struct sk_buff *skb, struct tcmsg *tcm) +{ + tcm->tcm_handle |= TC_H_MIN(cl); + return 0; +} + +static int fq_pie_dump_class_stats(struct Qdisc *sch, unsigned long cl, + struct gnet_dump *d) +{ + struct fq_pie_sched_data *q = qdisc_priv(sch); + struct gnet_stats_queue qs = { 0 }; + struct tc_fq_pie_xstats xstats; + u32 idx = cl - 1; + + if (idx < q->flows_cnt) { + const struct fq_pie_flow *flow = &q->flows[idx]; + + memset(&xstats, 0, sizeof(xstats)); + xstats.type = TCA_FQ_PIE_XSTATS_CLASS; + xstats.class_stats.prob = + READ_ONCE(flow->vars.prob) << BITS_PER_BYTE; + xstats.class_stats.delay = + div_u64(PSCHED_TICKS2NS(READ_ONCE(flow->vars.qdelay)), + NSEC_PER_USEC); + xstats.class_stats.deficit = READ_ONCE(flow->deficit); + xstats.class_stats.dq_rate_estimating = + READ_ONCE(q->p_params.dq_rate_estimator); + + if (xstats.class_stats.dq_rate_estimating) { + xstats.class_stats.avg_dq_rate = + ((u64)READ_ONCE(flow->vars.avg_dq_rate) + * PSCHED_TICKS_PER_SEC) >> PIE_SCALE; + } + + qs.qlen = READ_ONCE(flow->qlen); + qs.backlog = READ_ONCE(flow->backlog); + } + if (gnet_stats_copy_queue(d, NULL, &qs, qs.qlen) < 0) + return -1; + if (idx < q->flows_cnt) + return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); + return 0; +} + +static void fq_pie_walk(struct Qdisc *sch, struct qdisc_walker *arg) +{ + struct fq_pie_sched_data *q = qdisc_priv(sch); + unsigned int i; + + if (arg->stop) + return; + + for (i = 0; i < q->flows_cnt; i++) { + if (list_empty(&q->flows[i].flowchain)) { + arg->count++; + continue; + } + if (!tc_qdisc_stats_dump(sch, i + 1, arg)) + break; + } +} + +static const struct Qdisc_class_ops fq_pie_class_ops = { + .leaf = fq_pie_leaf, + .find = fq_pie_find, + .dump = fq_pie_dump_class, + .dump_stats = fq_pie_dump_class_stats, + .walk = fq_pie_walk, +}; + static struct Qdisc_ops fq_pie_qdisc_ops __read_mostly = { + .cl_ops = &fq_pie_class_ops, .id = "fq_pie", .priv_size = sizeof(struct fq_pie_sched_data), .enqueue = fq_pie_qdisc_enqueue, -- 2.34.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v8 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops 2026-09-22 20:59 ` [PATCH net-next v8 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik @ 2026-09-24 21:00 ` netdev-bot+sashiko 0 siblings, 0 replies; 6+ messages in thread From: netdev-bot+sashiko @ 2026-09-24 21:00 UTC (permalink / raw) To: hemendranaik Cc: netdev, davem, edumazet, kuba, pabeni, horms, jiri, jhs, shuah, linux-kernel, linux-kselftest, vishy0777, tahiliani Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider. Critical: 0 · High: 0 · Medium: 2 · Low: 6 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [Medium] In include/uapi/linux/pkt_sched.h, the patch appends `__u32 type` at offset 36 and then a whole `struct tc_fq_pie_cl_stats… - [Medium] fq_pie_dump_class_stats() computes `((u64)READ_ONCE(flow->vars.avg_dq_rate) * PSCHED_TICKS_PER_SEC) >>… - [Low] The commit message says the class ops are wired up "so that 'tc -s class show' reports per-flow state (prob, delay, deficit,… - [Low] Setting `.cl_ops = &fq_pie_class_ops` makes the TC core treat fq_pie as classful. - [Low] The patch grows `struct tc_fq_pie_xstats` in include/uapi/linux/pkt_sched.h from 36 to 64 bytes. - [Low] fq_pie_walk() and fq_pie_dump_class() list classes `<major>:<i+1>` for every active flow, but fq_pie_find() always… - [Low] fq_pie_change() accepts `flows_cnt` up to 65536 (sch_fq_pie.c:313: `if (!q->flows_cnt || q->flows_cnt > 65536)`). - [Low] fq_pie_dump_class_stats() reads per-flow state with READ_ONCE() only and holds no qdisc lock. -- net/sched: sch_fq_pie: add per-flow statistics via class ops This commit adds a type discriminator and an embedded struct tc_fq_pie_cl_stats to struct tc_fq_pie_xstats. The struct grows from 36 to 64 bytes. It also adds a minimal Qdisc_class_ops table to fq_pie so that each active flow is reported as a pseudo-class with its per-flow PIE state. > diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h > index 490efd2885267..9c0c9787f0c32 100644 > --- a/include/uapi/linux/pkt_sched.h > +++ b/include/uapi/linux/pkt_sched.h > @@ -953,6 +953,20 @@ enum { > }; > #define TCA_FQ_PIE_MAX (__TCA_FQ_PIE_MAX - 1) > > +enum { > + TCA_FQ_PIE_XSTATS_QDISC, > + TCA_FQ_PIE_XSTATS_CLASS, > +}; > + > +struct tc_fq_pie_cl_stats { > + __u64 prob; /* current probability */ > + __u32 delay; /* current delay in microseconds */ > + __s32 deficit; /* number of remaining byte credits */ > + __u32 avg_dq_rate; /* current average dq_rate in > + * bytes/second > + */ > + __u32 dq_rate_estimating; /* is avg_dq_rate being calculated? */ > +}; [Severity: Low] Should Documentation/netlink/specs/tc.yaml be updated along with this? In the spec, tc-fq-pie-xstats still lists only the nine original u32 members. The tca-stats-app-msg sub-message still binds fq_pie to it: - value: fq_pie fixed-header: tc-fq-pie-xstats The spec has no type member, no class-stats member, no tc-fq-pie-cl-stats struct and no enum for TCA_FQ_PIE_XSTATS_QDISC/CLASS. A spec-driven (YNL) decoder will only decode the first 36 bytes of the new 64-byte payload. It cannot tell class records from qdisc records, and it never shows prob, delay, deficit, avg_dq_rate or dq_rate_estimating. tc.yaml is still unchanged at the end of the series (after "net/sched: pie: correct tc_pie_xstats field documentation"). > struct tc_fq_pie_xstats { > __u32 packets_in; /* total number of packets enqueued */ > __u32 dropped; /* packets dropped due to fq_pie_action */ > @@ -963,6 +977,8 @@ struct tc_fq_pie_xstats { > __u32 new_flows_len; /* count of flows in new list */ > __u32 old_flows_len; /* count of flows in old list */ > __u32 memory_usage; /* total memory across all queues */ > + __u32 type; > + struct tc_fq_pie_cl_stats class_stats; > }; [Severity: Medium] Will this layout limit how both views can be extended later? type sits at offset 36 and class_stats at offset 40, so the struct is 64 bytes. Once this is released: - a new qdisc-level counter can only be appended after class_stats - after that, struct tc_fq_pie_cl_stats can never grow again Every message also carries both views. fq_pie_dump_stats() sends 24 zero bytes of class stats, and fq_pie_dump_class_stats() sends nine zeroed qdisc counters. The sibling struct in the same header avoids this with a union: struct tc_fq_codel_xstats { __u32 type; union { struct tc_fq_codel_qd_stats qdisc_stats; struct tc_fq_codel_cl_stats class_stats; }; }; Keeping the existing offsets means type cannot go first here. Would a union after the discriminator still let the two views grow independently? __u32 type; union { struct tc_fq_pie_cl_stats class_stats; /* future qdisc extension */ }; The commit message gives the new size and offsets but does not mention this constraint. > > /* CBS */ > diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c > index 5982847df8f85..3a3ef83f328b2 100644 > --- a/net/sched/sch_fq_pie.c > +++ b/net/sched/sch_fq_pie.c [ ... ] > @@ -563,7 +565,89 @@ static void fq_pie_destroy(struct Qdisc *sch) > kvfree(q->flows); > } > > +static struct Qdisc *fq_pie_leaf(struct Qdisc *sch, unsigned long arg) > +{ > + return NULL; > +} > + > +static unsigned long fq_pie_find(struct Qdisc *sch, u32 classid) > +{ > + return 0; > +} [Severity: Low] fq_pie_walk() lists a class <major>:<i+1> for every active flow, but fq_pie_find() always returns 0. Is it intended that a class shown by 'tc class show' gets -ENOENT from a targeted RTM_GETTCLASS, such as 'tc class get dev X classid <major>:N' going through __tc_ctl_tclass()? fq_codel_find(), sfq_find() and cake_find() also return 0 for their pseudo-classes. A non-zero return would also send qdisc_leaf() and the RTM_DELTCLASS paths into ops that fq_pie does not implement. So this may well be the intended convention. It does mean per-flow stats can only be read through a full dump. > + > +static int fq_pie_dump_class(struct Qdisc *sch, unsigned long cl, > + struct sk_buff *skb, struct tcmsg *tcm) > +{ > + tcm->tcm_handle |= TC_H_MIN(cl); [Severity: Low] Can the last flow be reported under the qdisc's own handle? fq_pie_change() accepts up to 65536 flows: if (!q->flows_cnt || q->flows_cnt > 65536) { fq_pie_walk() passes i + 1 as the class id. With flows_cnt == 65536, the flow at index 65535 is dumped with cl == 65536. TC_H_MIN() masks that to minor 0, which gives a handle of <major>:0, the same as the qdisc itself. fq_pie_dump_class_stats() still uses the unmasked cl, so the stats are correct but userspace sees them under the qdisc handle. fq_codel has the same latent issue. This patch brings it into fq_pie. > + return 0; > +} > + > +static int fq_pie_dump_class_stats(struct Qdisc *sch, unsigned long cl, > + struct gnet_dump *d) > +{ > + struct fq_pie_sched_data *q = qdisc_priv(sch); > + struct gnet_stats_queue qs = { 0 }; > + struct tc_fq_pie_xstats xstats; > + u32 idx = cl - 1; > + > + if (idx < q->flows_cnt) { > + const struct fq_pie_flow *flow = &q->flows[idx]; > + > + memset(&xstats, 0, sizeof(xstats)); > + xstats.type = TCA_FQ_PIE_XSTATS_CLASS; [Severity: Low] The commit message says the class ops are wired up: so that 'tc -s class show' reports per-flow state (prob, delay, deficit, avg_dq_rate, dq_rate_estimating). Does that hold with an existing tc binary? Here the nine qdisc counters are zeroed and the per-flow data is in class_stats at offset 40. A tc that predates the type field treats every fq_pie xstats blob as qdisc stats. It would likely print a row of zero qdisc counters for each active flow class and none of the per-flow values. Before this patch fq_pie had no cl_ops, so 'tc class show' printed nothing for it. The companion iproute2 change is only mentioned in the follow-up commit "selftests: tc-testing: add fq_pie per-flow class stats test" ("printed with the companion iproute2 change"). Could this commit mention it as well? > + xstats.class_stats.prob = > + READ_ONCE(flow->vars.prob) << BITS_PER_BYTE; > + xstats.class_stats.delay = > + div_u64(PSCHED_TICKS2NS(READ_ONCE(flow->vars.qdelay)), > + NSEC_PER_USEC); > + xstats.class_stats.deficit = READ_ONCE(flow->deficit); > + xstats.class_stats.dq_rate_estimating = > + READ_ONCE(q->p_params.dq_rate_estimator); > + > + if (xstats.class_stats.dq_rate_estimating) { > + xstats.class_stats.avg_dq_rate = > + ((u64)READ_ONCE(flow->vars.avg_dq_rate) > + * PSCHED_TICKS_PER_SEC) >> PIE_SCALE; > + } [Severity: Medium] Does this silently truncate the rate? The product is computed in 64 bits and then assigned to the __u32 tc_fq_pie_cl_stats.avg_dq_rate, so the high bits are lost. pie_vars.avg_dq_rate holds bytes per psched tick scaled by 2^8. pie_process_dequeue() fills it from (dq_count << PIE_SCALE) / dtime, and dtime can be only a few ticks during back-to-back GSO dequeues. PSCHED_TICKS_PER_SEC is 15625000 and PIE_SCALE is 8. Any internal value above about 70369 (roughly 4.29e9 B/s, about 34.4 Gbit/s) wraps. For example, 81920 converts to 5,000,000,000 B/s but is exported as 705,032,704. The commit message says: Widen avg_dq_rate to u64 before scaling it by PSCHED_TICKS_PER_SEC. That moves the overflow to the narrowing assignment instead of avoiding it. This is a new uAPI field. Could it be made __u64, or saturated at U32_MAX, before it is released? > + > + qs.qlen = READ_ONCE(flow->qlen); > + qs.backlog = READ_ONCE(flow->backlog); > + } [Severity: Low] Are these lockless reads safe against the datapath writers? tc_fill_tclass() passes a NULL lock to gnet_stats_start_copy_compat(), so this function runs under RTNL only. Meanwhile enqueue, dequeue and fq_pie_timer() update the same fields under the qdisc root lock on other CPUs. The writers of deficit, qlen and backlog use plain stores with no WRITE_ONCE(). In fq_pie_qdisc_enqueue(): if (list_empty(&sel_flow->flowchain)) { ... sel_flow->deficit = q->quantum; sel_flow->qlen = 0; sel_flow->backlog = 0; } sel_flow->qlen++; sel_flow->backlog += pkt_len; And in fq_pie_qdisc_dequeue(): flow->qlen--; flow->deficit -= pkt_len; flow->backlog -= pkt_len; KCSAN_ASSUME_PLAIN_WRITES_ATOMIC does not cover compound writes like these, so KCSAN will likely report them. The reader can also see intermediate values, such as qlen == 0 on a flow that was just activated. fq_codel annotates the equivalent writers, for example WRITE_ONCE(flow->deficit, ...). vars.prob and vars.qdelay are u64, so READ_ONCE() can tear on 32-bit kernels. pie_calculate_probability() also publishes an unclamped value before it applies the overflow fix-up: WRITE_ONCE(vars->prob, vars->prob + delta); if (delta > 0) { /* prevent overflow */ if (vars->prob < oldprob) { WRITE_ONCE(vars->prob, MAX_PROB); A lockless reader here could therefore export a wrapped probability. fq_pie_dump_stats() in the same file takes sch_tree_lock(). Should the class dump take it too, or should the fq_pie writers be annotated? [ ... ] > +static const struct Qdisc_class_ops fq_pie_class_ops = { > + .leaf = fq_pie_leaf, > + .find = fq_pie_find, > + .dump = fq_pie_dump_class, > + .dump_stats = fq_pie_dump_class_stats, > + .walk = fq_pie_walk, > +}; > + > static struct Qdisc_ops fq_pie_qdisc_ops __read_mostly = { > + .cl_ops = &fq_pie_class_ops, [Severity: Low] Setting .cl_ops makes the TC core treat fq_pie as classful. Is the change in user-visible errors intended? Filter add on parent <fq_pie>: used to fail in __tcf_qdisc_find() with -EINVAL "Qdisc not classful". It now reaches this check instead: if (!cops->tcf_block) { NL_SET_ERR_MSG(extack, "Class doesn't support blocks"); err = -EOPNOTSUPP; goto errout_qdisc; } Grafting or getting a child on parent <fq_pie>:N through qdisc_leaf() used to return -EOPNOTSUPP "Parent qdisc is not classful". Because fq_pie_find() always returns 0, it now returns -ENOENT "Specified class not found". RTM_GETTCLASS and RTM_DELTCLASS in __tc_ctl_tclass() also change from -EINVAL to -ENOENT. fq_pie_init() still calls tcf_block_get(), and fq_pie_classify() still reads q->filter_list and maps tcf results to flow ids 1..flows_cnt. That is the class id space this patch exposes. With .tcf_block, .bind_tcf and .unbind_tcf left out, the classifier path stays unreachable, as it was before this patch. The commit message says these callbacks are "omitted on purpose". Could it give the reason and mention the errno changes? -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260922205924.32173-1-hemendranaik%40gmail.com ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next v8 2/3] selftests: tc-testing: add fq_pie per-flow class stats test 2026-09-22 20:59 [PATCH net-next v8 0/3] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik 2026-09-22 20:59 ` [PATCH net-next v8 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik @ 2026-09-22 20:59 ` Hemendra M. Naik 2026-09-24 21:00 ` netdev-bot+sashiko 2026-09-22 20:59 ` [PATCH net-next v8 3/3] net/sched: pie: correct tc_pie_xstats field documentation Hemendra M. Naik 2 siblings, 1 reply; 6+ messages in thread From: Hemendra M. Naik @ 2026-09-22 20:59 UTC (permalink / raw) To: netdev Cc: davem, edumazet, kuba, pabeni, horms, jiri, jhs, shuah, linux-kernel, linux-kselftest, vishy0777, tahiliani, Hemendra M. Naik Add tc-testing case 83c0: build a TBF + fq_pie hierarchy on $DUMMY, push traffic through it with ping, and verify that 'tc -s class show' reports an fq_pie class. The per-flow counters themselves (prob, delay, deficit) are printed with the companion iproute2 change, "tc: fq_pie: add support for printing per-flow PIE statistics" Signed-off-by: Hemendra M. Naik <hemendranaik@gmail.com> Signed-off-by: Vishal Kamath <vishy0777@gmail.com> Signed-off-by: Mohit P. Tahiliani <tahiliani@nitk.edu.in> --- .../tc-testing/tc-tests/qdiscs/fq_pie.json | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq_pie.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq_pie.json index 229fe1bf4a90..15b2667285eb 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq_pie.json +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq_pie.json @@ -40,5 +40,32 @@ "matchPattern": "qdisc fq_pie 1: root refcnt [0-9]+ limit 1p", "matchCount": "1", "teardown": ["$TC qdisc del dev $DEV1 handle 1: root"] + }, + { + "id": "83c0", + "name": "FQ-PIE class stats accessible via tc class show", + "category": [ + "qdisc", + "fq_pie" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + "$IP link set dev $DUMMY up || true", + "$IP addr add 10.10.11.10/24 dev $DUMMY || true", + "$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 100ms", + "$TC qdisc add dev $DUMMY parent 1:1 handle 2: fq_pie limit 100 flows 1", + "ping -c 50 -i 0.001 -W 0.01 -s 56 10.10.11.11 -I $DUMMY > /dev/null 2>&1 || true" + ], + "cmdUnderTest": "$TC -s class show dev $DUMMY", + "expExitCode": "0", + "verifyCmd": "$TC -s class show dev $DUMMY", + "matchPattern": "class fq_pie 2:[0-9]+ .*prob .*delay .*deficit", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY handle 1: root", + "$IP addr del 10.10.11.10/24 dev $DUMMY || true" + ] } ] -- 2.34.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v8 2/3] selftests: tc-testing: add fq_pie per-flow class stats test 2026-09-22 20:59 ` [PATCH net-next v8 2/3] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik @ 2026-09-24 21:00 ` netdev-bot+sashiko 0 siblings, 0 replies; 6+ messages in thread From: netdev-bot+sashiko @ 2026-09-24 21:00 UTC (permalink / raw) To: hemendranaik Cc: netdev, davem, edumazet, kuba, pabeni, horms, jiri, jhs, shuah, linux-kernel, linux-kselftest, vishy0777, tahiliani Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider. Critical: 0 · High: 0 · Medium: 1 · Low: 1 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [Medium] Test 83c0 in tools/testing/selftests/tc-testing/tc- tests/qdiscs/fq_pie.json depends on an iproute2 change that has not… - [Low] Test 83c0 relies on a ping step, `ping -c 50 -i 0.001 -W 0.01 -s 56 10.10.11.11 -I $DUMMY > /dev/null 2>&1 || true`, to put packets… -- selftests: tc-testing: add fq_pie per-flow class stats test This adds tc-testing case 83c0. It builds a tbf + fq_pie hierarchy on $DUMMY, pushes traffic through it with ping, and checks the output of "tc -s class show" for an fq_pie class. The commit message says the per-flow counters are printed by a companion iproute2 change. > diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq_pie.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq_pie.json > index 229fe1bf4a906..15b2667285eb4 100644 > --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq_pie.json > +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq_pie.json [ ... ] > + "setup": [ > + "$IP link set dev $DUMMY up || true", > + "$IP addr add 10.10.11.10/24 dev $DUMMY || true", > + "$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 100ms", > + "$TC qdisc add dev $DUMMY parent 1:1 handle 2: fq_pie limit 100 flows 1", > + "ping -c 50 -i 0.001 -W 0.01 -s 56 10.10.11.11 -I $DUMMY > /dev/null 2>&1 || true" [Severity: Low] This is a robustness point, not a bug. fq_pie_walk() in net/sched/sch_fq_pie.c only dumps flows that have a non-empty flowchain: if (list_empty(&q->flows[i].flowchain)) { arg->count++; continue; } That makes this ping the only thing that gets class 2:1 into the output. In the standard tdc setup this works. nsPlugin runs the command inside the namespace, dummy is NOARP, and the 98-byte frame fits under tbf's max_size of 100. If ping is missing, or doesn't accept -i 0.001 / -W 0.01, the "|| true" and the redirect hide the error. The test then fails as a regex mismatch in the verify stage, not as a setup error. Should this step be allowed to fail visibly? The same pattern is already used elsewhere in tc-testing (infra/qdiscs.json), so it may be fine as is. > + ], > + "cmdUnderTest": "$TC -s class show dev $DUMMY", > + "expExitCode": "0", > + "verifyCmd": "$TC -s class show dev $DUMMY", > + "matchPattern": "class fq_pie 2:[0-9]+ .*prob .*delay .*deficit", [Severity: Medium] Will this test fail with any iproute2 release available today? The kernel side, fq_pie_dump_class_stats(), only sends a binary struct tc_fq_pie_xstats with type TCA_FQ_PIE_XSTATS_CLASS: xstats.type = TCA_FQ_PIE_XSTATS_CLASS; ... return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); The words "prob", "delay" and "deficit" only appear if tc formats that struct. According to the commit message, only the pending iproute2 patch does that. With a stock tc, re.findall() in run_one_test() in tdc.py finds 0 matches against a matchCount of 1. tdc then marks the test as failed, even on a kernel where the fq_pie class stats work correctly. tdc already has a way to skip in this case: the dependsOn key handled in run_one_test(). Other tests use it to gate on newer iproute2 features. For example, in actions/mirred.json: "dependsOn": "$TC actions add action mirred help 2>&1 | grep -q blockid", Could 83c0 get a similar dependsOn probe, so that it skips instead of failing when the tc in use can't print the per-flow stats? The commit message also describes the test more narrowly than it behaves: verify that 'tc -s class show' reports an fq_pie class. The pattern needs the per-flow counters too, not just an fq_pie class. Could the description say that the test depends on the iproute2 change? > + "matchCount": "1", > + "teardown": [ > + "$TC qdisc del dev $DUMMY handle 1: root", > + "$IP addr del 10.10.11.10/24 dev $DUMMY || true" > + ] > } > ] -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260922205924.32173-1-hemendranaik%40gmail.com ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next v8 3/3] net/sched: pie: correct tc_pie_xstats field documentation 2026-09-22 20:59 [PATCH net-next v8 0/3] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik 2026-09-22 20:59 ` [PATCH net-next v8 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik 2026-09-22 20:59 ` [PATCH net-next v8 2/3] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik @ 2026-09-22 20:59 ` Hemendra M. Naik 2 siblings, 0 replies; 6+ messages in thread From: Hemendra M. Naik @ 2026-09-22 20:59 UTC (permalink / raw) To: netdev Cc: davem, edumazet, kuba, pabeni, horms, jiri, jhs, shuah, linux-kernel, linux-kselftest, vishy0777, tahiliani, Hemendra M. Naik The comments describing struct tc_pie_xstats do not match the values exported by the kernel. Update the delay field comment to microseconds (PSCHED_TICKS2NS() / NSEC_PER_USEC). Update avg_dq_rate to bytes/second (avg_dq_rate * PSCHED_TICKS_PER_SEC >> PIE_SCALE). Documentation-only; no UAPI layout or runtime change. Touch include/uapi/linux/pkt_sched.h only Signed-off-by: Hemendra M. Naik <hemendranaik@gmail.com> Signed-off-by: Vishal Kamath <vishy0777@gmail.com> Signed-off-by: Mohit P. Tahiliani <tahiliani@nitk.edu.in> --- include/uapi/linux/pkt_sched.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 9c0c9787f0c3..969fa30efae7 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -920,9 +920,9 @@ enum { struct tc_pie_xstats { __u64 prob; /* current probability */ - __u32 delay; /* current delay in ms */ + __u32 delay; /* current delay in microseconds */ __u32 avg_dq_rate; /* current average dq_rate in - * bits/pie_time + * bytes/second */ __u32 dq_rate_estimating; /* is avg_dq_rate being calculated? */ __u32 packets_in; /* total number of packets enqueued */ -- 2.34.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-24 21:00 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-09-22 20:59 [PATCH net-next v8 0/3] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik 2026-09-22 20:59 ` [PATCH net-next v8 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik 2026-09-24 21:00 ` netdev-bot+sashiko 2026-09-22 20:59 ` [PATCH net-next v8 2/3] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik 2026-09-24 21:00 ` netdev-bot+sashiko 2026-09-22 20:59 ` [PATCH net-next v8 3/3] net/sched: pie: correct tc_pie_xstats field documentation Hemendra M. Naik
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®