All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v4 0/3] net/sched: sch_fq_pie: add per-flow class statistics
@ 2026-07-27 16:40 Hemendra M. Naik
  2026-07-27 16:40 ` [PATCH net-next v4 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Hemendra M. Naik @ 2026-07-27 16:40 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:

v4:
- 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                |  29 ++++-
 net/sched/sch_fq_pie.c                        | 109 +++++++++++++++++-
 tools/include/uapi/linux/pkt_sched.h          |   4 +-
 .../tc-testing/tc-tests/qdiscs/fq_pie.json    |  22 ++++
 4 files changed, 159 insertions(+), 5 deletions(-)

--
2.34.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net-next v4 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops
  2026-07-27 16:40 [PATCH net-next v4 0/3] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik
@ 2026-07-27 16:40 ` Hemendra M. Naik
  2026-07-31  9:56   ` Simon Horman
  2026-07-27 16:40 ` [PATCH net-next v4 2/3] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik
  2026-07-27 16:40 ` [PATCH net-next v4 3/3] net/sched: pie: correct tc_pie_xstats field documentation Hemendra M. Naik
  2 siblings, 1 reply; 5+ messages in thread
From: Hemendra M. Naik @ 2026-07-27 16:40 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 whether avg_dq_rate
		     is being calculated

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 |  25 ++++++++
 net/sched/sch_fq_pie.c         | 109 ++++++++++++++++++++++++++++++++-
 2 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 490efd288526..9a86fa4d6846 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -953,6 +953,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 */
@@ -963,6 +982,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 72f48fa4010b..664fef18568b 100644
--- a/net/sched/sch_fq_pie.c
+++ b/net/sched/sch_fq_pie.c
@@ -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);
@@ -561,7 +563,112 @@ 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,
--
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net-next v4 2/3] selftests: tc-testing: add fq_pie per-flow class stats test
  2026-07-27 16:40 [PATCH net-next v4 0/3] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik
  2026-07-27 16:40 ` [PATCH net-next v4 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
@ 2026-07-27 16:40 ` Hemendra M. Naik
  2026-07-27 16:40 ` [PATCH net-next v4 3/3] net/sched: pie: correct tc_pie_xstats field documentation Hemendra M. Naik
  2 siblings, 0 replies; 5+ messages in thread
From: Hemendra M. Naik @ 2026-07-27 16:40 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>
---
 .../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] 5+ messages in thread

* [PATCH net-next v4 3/3] net/sched: pie: correct tc_pie_xstats field documentation
  2026-07-27 16:40 [PATCH net-next v4 0/3] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik
  2026-07-27 16:40 ` [PATCH net-next v4 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
  2026-07-27 16:40 ` [PATCH net-next v4 2/3] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik
@ 2026-07-27 16:40 ` Hemendra M. Naik
  2 siblings, 0 replies; 5+ messages in thread
From: Hemendra M. Naik @ 2026-07-27 16:40 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 indicate that the value is reported
in microseconds, matching the `PSCHED_TICKS2NS() / NSEC_PER_USEC`
conversion.

Similarly, update the `avg_dq_rate` field comment to indicate that the
value is reported in bytes/second, matching the conversion performed by
`avg_dq_rate * PSCHED_TICKS_PER_SEC >> PIE_SCALE`.

These are documentation-only changes and do not modify the UAPI layout
or runtime behavior.

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 ++--
 tools/include/uapi/linux/pkt_sched.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 9a86fa4d6846..26b7e6964adb 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 */
diff --git a/tools/include/uapi/linux/pkt_sched.h b/tools/include/uapi/linux/pkt_sched.h
index 587481a19433..9bc190f0b3cf 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 microseconds */
+	__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] 5+ messages in thread

* Re: [PATCH net-next v4 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops
  2026-07-27 16:40 ` [PATCH net-next v4 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
@ 2026-07-31  9:56   ` Simon Horman
  0 siblings, 0 replies; 5+ messages in thread
From: Simon Horman @ 2026-07-31  9:56 UTC (permalink / raw)
  To: Hemendra M. Naik
  Cc: netdev, davem, edumazet, kuba, pabeni, jiri, jhs, shuah,
	linux-kernel, linux-kselftest, vishy0777, tahiliani

On Mon, Jul 27, 2026 at 10:10:54PM +0530, Hemendra M. Naik wrote:

...

> +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;
> +}

Hi,

The AI-generated review of this patch on netdev-ai [1] reports several
findings. And while I'd appreciate it if you could look over each of them
the one below seems to warrant highlighting here.

[1] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260727164056.106203-1-hemendranaik%40gmail.com?part=1

   Is the side effect of making fq_pie filter-capable intended, and should
   it be described in the commit message?

   Before this patch fq_pie_qdisc_ops had no .cl_ops, so filter attachment
   was rejected in net/sched/cls_api.c:__tcf_qdisc_find():

	cops = (*q)->ops->cl_ops;
	if (!cops) {
		NL_SET_ERR_MSG(extack, "Qdisc not classful");
		err = -EINVAL;

   q->filter_list was therefore always NULL and the filter branch of
   fq_pie_classify() was unreachable since fq_pie was added.  With .cl_ops
   present and fq_pie_tcf_block() returning q->block, 'tc filter add ...
   parent <fq_pie handle>' now succeeds and classifier verdicts plus
   classid-driven flow selection become live in the enqueue fast path.

   That newly reachable code does not handle TC_ACT_CONSUMED:

   net/sched/sch_fq_pie.c:fq_pie_classify() {
	result = tcf_classify_qdisc(skb, filter, &res, false);
	if (result >= 0) {
		switch (result) {
		case TC_ACT_STOLEN:
		case TC_ACT_QUEUED:
		case TC_ACT_TRAP:
			*qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
			fallthrough;
		case TC_ACT_SHOT:
			return 0;
		}
		if (TC_H_MIN(res.classid) <= q->flows_cnt)
			return TC_H_MIN(res.classid);
	}

   TC_ACT_CONSUMED is TC_ACT_VALUE_MAX + 1, so it is >= 0 and matches no
   case arm, and control reaches the classid path.  act_ct produces it
   after the skb ownership has already been handed away:

   net/sched/act_ct.c:tcf_ct_act() {
   out_frag:
	if (err != -EINPROGRESS)
		tcf_action_inc_drop_qstats(&c->common);
	return TC_ACT_CONSUMED;

   tcf_action_exec() propagates any value != TC_ACT_PIPE and
   __tcf_classify() returns it verbatim.  For a filter such as
	tc filter add dev eth0 parent 1: matchall action ct

   with no flowid, res.classid is 0, TC_H_MIN(0) <= flows_cnt holds and 0
   is returned, so fq_pie_qdisc_enqueue() frees the consumed skb a second
   time:

	idx = fq_pie_classify(skb, sch, &ret);
	if (idx == 0) {
		if (ret & __NET_XMIT_BYPASS)
			qdisc_qstats_drop(sch);
		__qdisc_drop(skb, to_free);

   and with 'flowid 1:N' a valid flow index is returned instead, so
   flow_queue_add() links the already freed skb into q->flows[idx].  Can
   fragmented traffic hitting that qdisc then cause a double free or
   use-after-free?

   That TC_ACT_CONSUMED is expected from qdisc-attached filter chains is
   also visible in net/sched/cls_api.c:tcf_qevent_handle(), which has an
   explicit case TC_ACT_CONSUMED: arm that must not free the skb.

   fq_codel, sfq and cake have the same missing arm, but for fq_pie the
   path only becomes reachable with this patch.

...

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-07-31  9:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-27 16:40 [PATCH net-next v4 0/3] net/sched: sch_fq_pie: add per-flow class statistics Hemendra M. Naik
2026-07-27 16:40 ` [PATCH net-next v4 1/3] net/sched: sch_fq_pie: add per-flow statistics via class ops Hemendra M. Naik
2026-07-31  9:56   ` Simon Horman
2026-07-27 16:40 ` [PATCH net-next v4 2/3] selftests: tc-testing: add fq_pie per-flow class stats test Hemendra M. Naik
2026-07-27 16:40 ` [PATCH net-next v4 3/3] net/sched: pie: correct tc_pie_xstats field documentation Hemendra M. Naik

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.