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