From: "Hemendra M. Naik" <hemendranaik@gmail.com>
To: netdev@vger.kernel.org
Cc: jiri@resnulli.us, jhs@mojatatu.com, linux-kernel@vger.kernel.org,
vishy0777@gmail.com, tahiliani@nitk.edu.in,
"Hemendra M. Naik" <hemendranaik@gmail.com>
Subject: [PATCH iproute2-next v2] tc: fq_pie: add support for printing per-flow PIE statistics
Date: Sun, 14 Jun 2026 18:37:29 +0530 [thread overview]
Message-ID: <20260614130729.10076-1-hemendranaik@gmail.com> (raw)
'tc -s class show' against an fq_pie qdisc now prints:
prob drop probability for the flow
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)
avg_dq_rate is formatted using tc_print_rate(), which converts the
kernel's bytes/second value to a human-readable bits/second string
(e.g. '3906Kbit'), consistent with how other tc schedulers display
rate fields. Apply the same fix to tc/q_pie.c, where avg_dq_rate was
also printed as a raw integer without a unit.
Update the UAPI header to mirror tc_fq_pie_cl_stats from the kernel.
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.
Add a 'tc -s class show' example to tc-fq_pie(8) with dq_rate_estimator
enabled, showing all per-flow fields (prob, delay, deficit, avg_dq_rate)
across multiple flows. Update tc-pie(8) avg_dq_rate example from a raw
integer to a formatted bits/second string.
The corresponding kernel patch can be viewed here:
https://lore.kernel.org/netdev/20260614125000.6058-1-hemendranaik@gmail.com/
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/20260531131411.28213-1-hemendranaik@gmail.com/
---
include/uapi/linux/pkt_sched.h | 29 +++++++++++++++--
man/man8/tc-fq_pie.8 | 18 +++++++++++
man/man8/tc-pie.8 | 2 +-
tc/q_fq_pie.c | 57 +++++++++++++++++++++++-----------
tc/q_pie.c | 4 +--
5 files changed, 87 insertions(+), 23 deletions(-)
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index fb07a889..4927f7b8 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/man/man8/tc-fq_pie.8 b/man/man8/tc-fq_pie.8
index 457a56bb..bf988f5f 100644
--- a/man/man8/tc-fq_pie.8
+++ b/man/man8/tc-fq_pie.8
@@ -153,6 +153,24 @@ dq_rate_estimator
pkts_in 6082 overlimit 0 overmemory 0 dropped 4 ecn_mark 0
new_flow_count 94 new_flows_len 0 old_flows_len 8 memory_used 1157632
+# tc qdisc add dev eth0 parent 100:1 handle 200: fq_pie target 2ms flows 3
+.br
+# tc -s class show dev eth0
+.br
+class fq_pie 200:2 parent 200:
+ Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
+ backlog 22800b 2p requeues 0
+ prob 0.57679 delay 2.38ms
+
+# tc qdisc add dev eth0 parent 100:1 handle 200: fq_pie target 2ms flows 3 dq_rate_estimator
+.br
+# tc -s class show dev eth0
+.br
+class fq_pie 200:2 parent 200:
+ Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
+ backlog 22800b 2p requeues 0
+ prob 0.57679 delay 2.38ms avg_dq_rate 10742Kbit
+
.SH SEE ALSO
.BR tc (8),
.BR tc-pie (8),
diff --git a/man/man8/tc-pie.8 b/man/man8/tc-pie.8
index 5a8c7820..f3a09616 100644
--- a/man/man8/tc-pie.8
+++ b/man/man8/tc-pie.8
@@ -115,7 +115,7 @@ is turned off.
qdisc pie 8036: dev eth0 root refcnt 2 limit 1000p target 15.0ms tupdate 16.0ms alpha 2 beta 20
Sent 63947420 bytes 42414 pkt (dropped 41, overlimits 0 requeues 0)
backlog 271006b 179p requeues 0
- prob 0.000092 delay 22200us avg_dq_rate 12145996
+ prob 0.000092 delay 22200us avg_dq_rate 10742Kbit
pkts_in 41 overlimit 343 dropped 0 maxq 50 ecn_mark 0
# tc qdisc add dev eth0 root pie limit 100 target 20ms tupdate 30ms ecn
diff --git a/tc/q_fq_pie.c b/tc/q_fq_pie.c
index dc2710cd..678f045f 100644
--- a/tc/q_fq_pie.c
+++ b/tc/q_fq_pie.c
@@ -274,6 +274,8 @@ static int fq_pie_print_xstats(const struct qdisc_util *qu, FILE *f,
{
struct tc_fq_pie_xstats _st = {}, *st;
+ SPRINT_BUF(b1);
+
if (xstats == NULL)
return 0;
@@ -283,25 +285,43 @@ static int fq_pie_print_xstats(const struct qdisc_util *qu, FILE *f,
st = &_st;
}
- print_uint(PRINT_ANY, "pkts_in", " pkts_in %u",
- st->packets_in);
- print_uint(PRINT_ANY, "overlimit", " overlimit %u",
- st->overlimit);
- print_uint(PRINT_ANY, "overmemory", " overmemory %u",
- st->overmemory);
- print_uint(PRINT_ANY, "dropped", " dropped %u",
- st->dropped);
- print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u",
- st->ecn_mark);
+ if (!st->type || st->type == TCA_FQ_PIE_XSTATS_QDISC) {
+ print_uint(PRINT_ANY, "pkts_in", " pkts_in %u",
+ st->packets_in);
+ print_uint(PRINT_ANY, "overlimit", " overlimit %u",
+ st->overlimit);
+ print_uint(PRINT_ANY, "overmemory", " overmemory %u",
+ st->overmemory);
+ print_uint(PRINT_ANY, "dropped", " dropped %u",
+ st->dropped);
+ print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u",
+ st->ecn_mark);
+ print_nl();
+ print_uint(PRINT_ANY, "new_flow_count", " new_flow_count %u",
+ st->new_flow_count);
+ print_uint(PRINT_ANY, "new_flows_len", " new_flows_len %u",
+ st->new_flows_len);
+ print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u",
+ st->old_flows_len);
+ print_uint(PRINT_ANY, "memory_used", " memory_used %u",
+ st->memory_usage);
+ }
+
+ if (st->type == TCA_FQ_PIE_XSTATS_CLASS) {
+ print_float(PRINT_ANY, "prob", " prob %lg",
+ (double)st->class_stats.prob / (double)UINT64_MAX);
+ print_uint(PRINT_JSON, "delay", NULL, st->class_stats.delay);
+ print_string(PRINT_FP, NULL, " delay %s",
+ sprint_time(st->class_stats.delay, b1));
+ print_int(PRINT_ANY, "deficit", " deficit %d",
+ st->class_stats.deficit);
+
+ if (st->class_stats.dq_rate_estimating) {
+ tc_print_rate(PRINT_ANY, "avg_dq_rate", " avg_dq_rate %s",
+ st->class_stats.avg_dq_rate);
+ }
+ }
print_nl();
- print_uint(PRINT_ANY, "new_flow_count", " new_flow_count %u",
- st->new_flow_count);
- print_uint(PRINT_ANY, "new_flows_len", " new_flows_len %u",
- st->new_flows_len);
- print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u",
- st->old_flows_len);
- print_uint(PRINT_ANY, "memory_used", " memory_used %u",
- st->memory_usage);
return 0;
diff --git a/tc/q_pie.c b/tc/q_pie.c
index 04c9aa61..abae1ced 100644
--- a/tc/q_pie.c
+++ b/tc/q_pie.c
@@ -220,8 +220,8 @@ static int pie_print_xstats(const struct qdisc_util *qu, FILE *f,
print_string(PRINT_FP, NULL, " delay %s", sprint_time(st->delay, b1));
if (st->dq_rate_estimating)
- print_uint(PRINT_ANY, "avg_dq_rate", " avg_dq_rate %u",
- st->avg_dq_rate);
+ tc_print_rate(PRINT_ANY, "avg_dq_rate", " avg_dq_rate %s",
+ st->avg_dq_rate);
print_nl();
print_uint(PRINT_ANY, "pkts_in", " pkts_in %u", st->packets_in);
--
2.34.1
next reply other threads:[~2026-06-14 13:08 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-14 13:07 Hemendra M. Naik [this message]
2026-06-14 15:43 ` [PATCH iproute2-next v2] tc: fq_pie: add support for printing per-flow PIE statistics Stephen Hemminger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260614130729.10076-1-hemendranaik@gmail.com \
--to=hemendranaik@gmail.com \
--cc=jhs@mojatatu.com \
--cc=jiri@resnulli.us \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=tahiliani@nitk.edu.in \
--cc=vishy0777@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox