* [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics
@ 2026-06-14 12:49 Hemendra M. Naik
2026-06-14 12:49 ` [PATCH net-next v2 1/2] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Hemendra M. Naik @ 2026-06-14 12:49 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.
---
Changelog:
v2: Addressed ABI backward compatibility issue for tc_fq_pie_xstats.
v1: https://lore.kernel.org/netdev/20260531125314.22492-1-hemendranaik@gmail.com/
---
Hemendra M. Naik (2):
net/sched: sch_fq_pie: add per-flow statistics via class ops
selftests: tc-testing: add fq_pie per-flow class stats test
include/uapi/linux/pkt_sched.h | 29 ++++-
net/sched/sch_fq_pie.c | 118 +++++++++++++++++-
tools/include/uapi/linux/pkt_sched.h | 4 +-
.../tc-testing/tc-tests/qdiscs/fq_pie.json | 22 ++++
4 files changed, 163 insertions(+), 10 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH net-next v2 1/2] net/sched: sch_fq_pie: add per-flow statistics via class ops
2026-06-14 12:49 [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik
@ 2026-06-14 12:49 ` Hemendra M. Naik
2026-06-14 12:50 ` [PATCH net-next v2 2/2] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik
2026-06-16 2:00 ` [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics Jakub Kicinski
2 siblings, 0 replies; 4+ messages in thread
From: Hemendra M. Naik @ 2026-06-14 12:49 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 to support both qdisc and class-level
extended statistics.
- Add enum with QDISC and CLASS type discriminators.
- Add struct tc_fq_pie_cl_stats for per-flow metrics (prob,
delay, deficit, avg_dq_rate, dq_rate_estimating).
- Add empty struct tc_fq_pie_xqd_stats placeholder.
Wire up fq_pie_class_ops (.walk, .dump, .dump_stats) so that
'tc -s class show' against an fq_pie qdisc reports per-flow state:
prob per-flow PIE drop probability
delay per-flow queue sojourn time (microseconds)
deficit remaining DRR byte credits (signed integer)
avg_dq_rate dequeue rate estimate in bytes/second
(dq_rate_estimator mode only)
dq_rate_estimating flag indicating active delay estimation mode
Fix the 'delay' field comment in struct tc_pie_xstats from "in ms" to
"in microseconds" to match the kernel's
PSCHED_TICKS2NS / NSEC_PER_USEC conversion.
Also correct the avg_dq_rate comment in tc_pie_xstats from
"bits/pie_time" to "bytes/second" to match the actual kernel
conversion (avg_dq_rate * PSCHED_TICKS_PER_SEC >> PIE_SCALE).
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>
---
Changelog:
v2: Addressed ABI backward compatibility issue for tc_fq_pie_xstats.
v1: https://lore.kernel.org/netdev/20260531125314.22492-2-hemendranaik@gmail.com
---
include/uapi/linux/pkt_sched.h | 29 ++++++-
net/sched/sch_fq_pie.c | 118 +++++++++++++++++++++++++--
tools/include/uapi/linux/pkt_sched.h | 4 +-
3 files changed, 141 insertions(+), 10 deletions(-)
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 66e8072f44df..fd4daad98abc 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -910,9 +910,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 */
@@ -943,6 +943,25 @@ 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_xqd_stats {
+ /* placeholder for new qdisc-level stats */
+};
+
struct tc_fq_pie_xstats {
__u32 packets_in; /* total number of packets enqueued */
__u32 dropped; /* packets dropped due to fq_pie_action */
@@ -953,6 +972,12 @@ 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;
+ union {
+ struct tc_fq_pie_cl_stats class_stats;
+ struct tc_fq_pie_xqd_stats xqdisc_stats;
+ };
+
};
/* CBS */
diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
index 7becbf5362b3..2778d3cda956 100644
--- a/net/sched/sch_fq_pie.c
+++ b/net/sched/sch_fq_pie.c
@@ -330,7 +330,7 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
/* tupdate is in jiffies */
if (tb[TCA_FQ_PIE_TUPDATE])
WRITE_ONCE(q->p_params.tupdate,
- usecs_to_jiffies(nla_get_u32(tb[TCA_FQ_PIE_TUPDATE])));
+ usecs_to_jiffies(nla_get_u32(tb[TCA_FQ_PIE_TUPDATE])));
if (tb[TCA_FQ_PIE_ALPHA])
WRITE_ONCE(q->p_params.alpha,
@@ -509,7 +509,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);
@@ -517,10 +519,10 @@ static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
st.packets_in = q->stats.packets_in;
st.overlimit = q->stats.overlimit;
st.overmemory = q->overmemory;
- st.dropped = q->stats.dropped;
- st.ecn_mark = q->stats.ecn_mark;
- st.new_flow_count = q->new_flow_count;
- st.memory_usage = q->memory_usage;
+ st.dropped = q->stats.dropped;
+ st.ecn_mark = q->stats.ecn_mark;
+ st.new_flow_count = q->new_flow_count;
+ st.memory_usage = q->memory_usage;
list_for_each(pos, &q->new_flows)
st.new_flows_len++;
@@ -561,7 +563,111 @@ 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 unsigned long fq_pie_bind(struct Qdisc *sch, unsigned long parent,
+ u32 classid)
+{
+ return 0;
+}
+
+static void fq_pie_unbind(struct Qdisc *q, unsigned long cl)
+{
+}
+
+static struct tcf_block *fq_pie_tcf_block(struct Qdisc *sch, unsigned long cl,
+ struct netlink_ext_ack *extack)
+{
+ struct fq_pie_sched_data *q = qdisc_priv(sch);
+
+ if (cl)
+ return NULL;
+ return q->block;
+}
+
+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 =
+ ((u32)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 =
+ 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,
+ .tcf_block = fq_pie_tcf_block,
+ .bind_tcf = fq_pie_bind,
+ .unbind_tcf = fq_pie_unbind,
+ .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,
diff --git a/tools/include/uapi/linux/pkt_sched.h b/tools/include/uapi/linux/pkt_sched.h
index 587481a19433..45ea10026742 100644
--- a/tools/include/uapi/linux/pkt_sched.h
+++ b/tools/include/uapi/linux/pkt_sched.h
@@ -847,8 +847,8 @@ enum {
struct tc_pie_xstats {
__u32 prob; /* current probability */
- __u32 delay; /* current delay in ms */
- __u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */
+ __u32 delay; /* current delay in micoseconds */
+ __u32 avg_dq_rate; /* current average dq_rate in bytes/second */
__u32 packets_in; /* total number of packets enqueued */
__u32 dropped; /* packets dropped due to pie_action */
__u32 overlimit; /* dropped due to lack of space in queue */
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH net-next v2 2/2] selftests: tc-testing: add fq_pie per-flow class stats test
2026-06-14 12:49 [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik
2026-06-14 12:49 ` [PATCH net-next v2 1/2] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
@ 2026-06-14 12:50 ` Hemendra M. Naik
2026-06-16 2:00 ` [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics Jakub Kicinski
2 siblings, 0 replies; 4+ messages in thread
From: Hemendra M. Naik @ 2026-06-14 12:50 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, horms, jiri, jhs, shuah,
linux-kernel, linux-kselftest, vishy0777, tahiliani,
Hemendra M. Naik
Add a tc-testing entry (id: 83c0) to verify the fq_pie class ops
wired up in the previous patch do not crash and integrate cleanly
with the tc class show path.
The test creates an fq_pie root qdisc on a dummy interface and runs
'tc -s class show'.
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>
---
Changelog:
v2: No changes from v1.
v1: https://lore.kernel.org/netdev/20260531125314.22492-3-hemendranaik@gmail.com/
---
.../tc-testing/tc-tests/qdiscs/fq_pie.json | 22 +++++++++++++++++++
1 file changed, 22 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..88139f429430 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,27 @@
"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": [
+ "$TC qdisc add dev $DUMMY handle 1: root fq_pie"
+ ],
+ "cmdUnderTest": "$TC -s class show dev $DUMMY",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -s class show dev $DUMMY",
+ "matchPattern": "class fq_pie",
+ "matchCount": "0",
+ "teardown": [
+ "$TC qdisc del dev $DUMMY handle 1: root"
+ ]
}
]
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics
2026-06-14 12:49 [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik
2026-06-14 12:49 ` [PATCH net-next v2 1/2] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
2026-06-14 12:50 ` [PATCH net-next v2 2/2] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik
@ 2026-06-16 2:00 ` Jakub Kicinski
2 siblings, 0 replies; 4+ messages in thread
From: Jakub Kicinski @ 2026-06-16 2:00 UTC (permalink / raw)
To: Hemendra M. Naik
Cc: netdev, davem, edumazet, pabeni, horms, jiri, jhs, shuah,
linux-kernel, linux-kselftest, vishy0777, tahiliani
On Sun, 14 Jun 2026 18:19:58 +0530 Hemendra M. Naik wrote:
> 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.
net-next is closed for the duration of the merge window.
Please see: https://netdev.bots.linux.dev/net-next.html
And of course:
https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html#development-cycle
--
pw-bot: defer
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-06-16 2:00 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-14 12:49 [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik
2026-06-14 12:49 ` [PATCH net-next v2 1/2] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
2026-06-14 12:50 ` [PATCH net-next v2 2/2] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik
2026-06-16 2:00 ` [PATCH net-next v2 0/2] net/sched: sch_fq_pie: add per-flow class statistics Jakub Kicinski
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.