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/[email protected]/

> 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.

>  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?

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

Reply via email to