Thread (7 messages) flat view 7 messages, 2 authors, 1d ago

Re: [PATCH net v2 2/3] net/sched: taprio: enforce a minimum interval for software schedules

From: Jakub Kicinski <kuba@kernel.org>
Date: 2026-08-24 18:53:38
Also in: linux-kselftest, lkml

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
net/sched: taprio: enforce a minimum interval for software schedules

This adds taprio_min_interval() which raises the accepted minimum
per-entry interval to 100us for schedules that are neither fully
offloaded nor txtime-assisted, on the grounds that each entry expiry
costs an hrtimer callback. The same minimum is applied to the
cycle_time sanity check.

Link: https://lore.kernel.org/all/afe041f6-ef7d-4434-b2d0-096be49b5bcb@mail.kernel.org/ (local)
quoted hunk ↗ jump to hunk
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index 0d566c934b2f3..91a7f7f17462b 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -259,6 +259,26 @@ static int length_to_duration(struct taprio_sched *q, int len)
 	return div_u64(len * atomic64_read(&q->picos_per_byte), PSEC_PER_NSEC);
 }
 
+/* Software schedules service one hrtimer expiry per entry; intervals
+ * shorter than the expiry service cost rearm the timer with an expiry
+ * already in the past and storm the CPU. 100us leaves margin above the
+ * measured cost on debug configurations.
+ */
+#define TAPRIO_MIN_SW_INTERVAL_NS	(100 * NSEC_PER_USEC)
+
+static s64 taprio_min_interval(struct taprio_sched *q)
+{
+	s64 min_interval = length_to_duration(q, ETH_ZLEN);
+
+	/* Only pure software schedules arm the per-entry hrtimer. */
+	if (!FULL_OFFLOAD_IS_ENABLED(q->flags) &&
+	    !TXTIME_ASSIST_IS_ENABLED(q->flags))
+		min_interval = max_t(s64, min_interval,
+				     TAPRIO_MIN_SW_INTERVAL_NS);
+
+	return min_interval;
+}
+
[Severity: High]
Does this narrow the range of schedules that userspace can install on
existing setups?

Before this patch, fill_sched_entry() only required
length_to_duration(q, ETH_ZLEN). At 1 Gb/s picos_per_byte is 8000, so the
bound was 60 * 8 = 480ns; at 100 Mb/s it was about 4.8us. With
taprio_min_interval() the bound for software mode becomes a flat 100000ns,
and parse_taprio_schedule() additionally requires:

	if (new->cycle_time < (s64)new->num_entries * taprio_min_interval(q)) {
		NL_SET_ERR_MSG(extack, "'cycle_time' is too small");
		return -EINVAL;
	}

So a 250us cycle split into 4 x 62.5us windows, or a 1ms cycle containing a
20us guard window, is now rejected with -EINVAL by tc qdisc add/replace on a
real NIC in software mode. Any 8-entry schedule with a cycle below 800us is
rejected as well.

The commit message says the hrtimer expiry costs "on the order of 10us on a
debug configuration and about a microsecond on a release build", yet the
constant is 100us for all configurations. Is a 100x margin over the
release-build cost intended as a hard limit on PREEMPT_RT and production
kernels, where sub-100us gating on isolated CPUs is the reason software
taprio exists?

Since the change carries a Fixes: tag it will be picked up for stable, so
working 802.1Qbv configurations would stop loading after a stable update.
Would it make sense to make the floor tunable (module parameter, sysctl or
netlink attribute) and document it, rather than a compile-time constant?

Was flooring the rearm interval at runtime in advance_sched() considered as
an alternative, so that the schedule is still accepted but the timer is not
rearmed in the past? As a mitigation for the reported stalls the constant is
also only a constant factor: a CAP_NET_ADMIN user in a netns can still
create many veth or bonding devices, each running a 100us cycle.
quoted hunk ↗ jump to hunk
 static int duration_to_length(struct taprio_sched *q, u64 duration)
 {
 	return div_u64(duration * PSEC_PER_NSEC, atomic64_read(&q->picos_per_byte));
@@ -1088,7 +1108,7 @@ static int fill_sched_entry(struct taprio_sched *q, struct nlattr **tb,
 			    struct sched_entry *entry,
 			    struct netlink_ext_ack *extack)
 {
-	int min_duration = length_to_duration(q, ETH_ZLEN);
+	s64 min_duration = taprio_min_interval(q);
 	u32 interval = 0;
 
[Severity: Low]
This isn't a bug, but the comment and the extack string further down in
fill_sched_entry() no longer describe what is enforced:

	/* The interval should allow at least the minimum ethernet
	 * frame to go out.
	 */
	if (interval < min_duration) {
		NL_SET_ERR_MSG(extack, "Invalid interval for schedule entry");
		return -EINVAL;
	}

For any link at 1 Gb/s or faster the ETH_ZLEN term is a few hundred
nanoseconds, so the frame-length rule the comment names never wins and the
rule actually applied is the 100us hrtimer-cost floor documented only at the
taprio_min_interval() definition. Could the comment be updated, and could
the extack message mention the minimum so a user whose 5us interval is
rejected after an upgrade can tell why?
quoted hunk ↗ jump to hunk
 	if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD])
@@ -1216,7 +1236,7 @@ static int parse_taprio_schedule(struct taprio_sched *q, struct nlattr **tb,
 		new->cycle_time = cycle;
 	}
 
-	if (new->cycle_time < new->num_entries * length_to_duration(q, ETH_ZLEN)) {
+	if (new->cycle_time < (s64)new->num_entries * taprio_min_interval(q)) {
 		NL_SET_ERR_MSG(extack, "'cycle_time' is too small");
 		return -EINVAL;
 	}
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help