From 09dbdf28f9f9fa27e16895c67fbd94ff36124766 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 16 Feb 2023 00:46:30 +0200 Subject: net/sched: taprio: fix calculation of maximum gate durations taprio_calculate_gate_durations() depends on netdev_get_num_tc() and this returns 0. So it calculates the maximum gate durations for no traffic class. I had tested the blamed commit only with another patch in my tree, one which in the end I decided isn't valuable enough to submit ("net/sched: taprio: mask off bits in gate mask that exceed number of TCs"). The problem is that having this patch threw off my testing. By moving the netdev_set_num_tc() call earlier, we implicitly gave to taprio_calculate_gate_durations() the information it needed. Extract only the portion from the unsubmitted change which applies the mqprio configuration to the netdev earlier. Link: https://patchwork.kernel.org/project/netdevbpf/patch/20230130173145.475943-15-vladimir.oltean@nxp.com/ Fixes: a306a90c8ffe ("net/sched: taprio: calculate tc gate durations") Signed-off-by: Vladimir Oltean Reviewed-by: Kurt Kanzenbach Signed-off-by: Paolo Abeni --- net/sched/sch_taprio.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 9781b47962bbde..556e72ec0f38d2 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -1833,23 +1833,6 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, goto free_sched; } - err = parse_taprio_schedule(q, tb, new_admin, extack); - if (err < 0) - goto free_sched; - - if (new_admin->num_entries == 0) { - NL_SET_ERR_MSG(extack, "There should be at least one entry in the schedule"); - err = -EINVAL; - goto free_sched; - } - - err = taprio_parse_clockid(sch, tb, extack); - if (err < 0) - goto free_sched; - - taprio_set_picos_per_byte(dev, q); - taprio_update_queue_max_sdu(q, new_admin, stab); - if (mqprio) { err = netdev_set_num_tc(dev, mqprio->num_tc); if (err) @@ -1867,6 +1850,23 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, mqprio->prio_tc_map[i]); } + err = parse_taprio_schedule(q, tb, new_admin, extack); + if (err < 0) + goto free_sched; + + if (new_admin->num_entries == 0) { + NL_SET_ERR_MSG(extack, "There should be at least one entry in the schedule"); + err = -EINVAL; + goto free_sched; + } + + err = taprio_parse_clockid(sch, tb, extack); + if (err < 0) + goto free_sched; + + taprio_set_picos_per_byte(dev, q); + taprio_update_queue_max_sdu(q, new_admin, stab); + if (FULL_OFFLOAD_IS_ENABLED(q->flags)) err = taprio_enable_offload(dev, q, new_admin, extack); else -- cgit 1.2.3-korg From bdf366bd867c4565b535a5825df7ddcb4773fc28 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 16 Feb 2023 00:46:31 +0200 Subject: net/sched: taprio: don't allow dynamic max_sdu to go negative after stab adjustment The overhead specified in the size table comes from the user. With small time intervals (or gates always closed), the overhead can be larger than the max interval for that traffic class, and their difference is negative. What we want to happen is for max_sdu_dynamic to have the smallest non-zero value possible (1) which means that all packets on that traffic class are dropped on enqueue. However, since max_sdu_dynamic is u32, a negative is represented as a large value and oversized dropping never happens. Use max_t with int to force a truncation of max_frm_len to no smaller than dev->hard_header_len + 1, which in turn makes max_sdu_dynamic no smaller than 1. Fixes: fed87cc6718a ("net/sched: taprio: automatically calculate queueMaxSDU based on TC gate durations") Signed-off-by: Vladimir Oltean Reviewed-by: Kurt Kanzenbach Signed-off-by: Paolo Abeni --- net/sched/sch_taprio.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 556e72ec0f38d2..53ba4d6b021826 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -279,8 +279,14 @@ static void taprio_update_queue_max_sdu(struct taprio_sched *q, u32 max_frm_len; max_frm_len = duration_to_length(q, sched->max_open_gate_duration[tc]); - if (stab) + /* Compensate for L1 overhead from size table, + * but don't let the frame size go negative + */ + if (stab) { max_frm_len -= stab->szopts.overhead; + max_frm_len = max_t(int, max_frm_len, + dev->hard_header_len + 1); + } max_sdu_dynamic = max_frm_len - dev->hard_header_len; } -- cgit 1.2.3-korg From 64cb6aad12328015202af5b2a9623c6bcc021855 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 16 Feb 2023 00:46:32 +0200 Subject: net/sched: taprio: dynamic max_sdu larger than the max_mtu is unlimited It makes no sense to keep randomly large max_sdu values, especially if larger than the device's max_mtu. These are visible in "tc qdisc show". Such a max_sdu is practically unlimited and will cause no packets for that traffic class to be dropped on enqueue. Just set max_sdu_dynamic to U32_MAX, which in the logic below causes taprio to save a max_frm_len of U32_MAX and a max_sdu presented to user space of 0 (unlimited). Signed-off-by: Vladimir Oltean Reviewed-by: Kurt Kanzenbach Signed-off-by: Paolo Abeni --- net/sched/sch_taprio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 53ba4d6b021826..1f469861eae327 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -288,6 +288,8 @@ static void taprio_update_queue_max_sdu(struct taprio_sched *q, dev->hard_header_len + 1); } max_sdu_dynamic = max_frm_len - dev->hard_header_len; + if (max_sdu_dynamic > dev->max_mtu) + max_sdu_dynamic = U32_MAX; } max_sdu = min(max_sdu_dynamic, max_sdu_from_user); -- cgit 1.2.3-korg