[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230418113953.818831-11-vladimir.oltean@nxp.com>
Date: Tue, 18 Apr 2023 14:39:53 +0300
From: Vladimir Oltean <vladimir.oltean@....com>
To: netdev@...r.kernel.org
Cc: David Ahern <dsahern@...nel.org>,
Stephen Hemminger <stephen@...workplumber.org>
Subject: [PATCH v2 iproute2-next 10/10] tc/taprio: add support for preemptible traffic classes
Add support for the same kind of "fp" array argument as in mqprio,
except here we already have some handling for per-tc entries (max-sdu).
We just need to expand that logic such that we also add (and parse) the
FP adminStatus property of each traffic class.
Signed-off-by: Vladimir Oltean <vladimir.oltean@....com>
---
v1->v2: amended help text so that user space (kselftests) could detect
the presence of the new feature
man/man8/tc-taprio.8 | 11 +++++
tc/q_taprio.c | 100 ++++++++++++++++++++++++++++++++-----------
2 files changed, 87 insertions(+), 24 deletions(-)
diff --git a/man/man8/tc-taprio.8 b/man/man8/tc-taprio.8
index c3ccefea9c8a..bf489b032a7e 100644
--- a/man/man8/tc-taprio.8
+++ b/man/man8/tc-taprio.8
@@ -36,6 +36,10 @@ clockid
[
.B max-sdu
<queueMaxSDU[TC 0]> <queueMaxSDU[TC 1]> <queueMaxSDU[TC N]> ]
+.ti +8
+[
+.B fp
+<adminStatus[TC 0]> <adminStatus[TC 1]> <adminStatus[TC N]> ]
.SH DESCRIPTION
The TAPRIO qdisc implements a simplified version of the scheduling
@@ -163,6 +167,13 @@ represents the maximum L2 payload size that can egress that traffic class.
Elements that are not filled in default to 0. The value 0 means that the
traffic class can send packets up to the port's maximum MTU in size.
+.TP
+fp
+.br
+Selects whether traffic classes are express or preemptible. See
+.BR tc-mqprio(8)
+for details.
+
.SH EXAMPLES
The following example shows how an traffic schedule with three traffic
diff --git a/tc/q_taprio.c b/tc/q_taprio.c
index c0da65fe3744..bc29710c4686 100644
--- a/tc/q_taprio.c
+++ b/tc/q_taprio.c
@@ -49,6 +49,7 @@ static void explain(void)
" [queues COUNT@...SET COUNT@...SET COUNT@...SET ...]\n"
" [ [sched-entry index cmd gate-mask interval] ... ]\n"
" [base-time time] [txtime-delay delay]\n"
+ " [fp FP0 FP1 FP2 ...]\n"
"\n"
"CLOCKID must be a valid SYS-V id (i.e. CLOCK_TAI)\n");
}
@@ -148,17 +149,29 @@ static struct sched_entry *create_entry(uint32_t gatemask, uint32_t interval, ui
}
static void add_tc_entries(struct nlmsghdr *n, __u32 max_sdu[TC_QOPT_MAX_QUEUE],
- int num_max_sdu_entries)
+ int num_max_sdu_entries, __u32 fp[TC_QOPT_MAX_QUEUE],
+ int num_fp_entries)
{
struct rtattr *l;
+ int num_tc;
__u32 tc;
- for (tc = 0; tc < num_max_sdu_entries; tc++) {
+ num_tc = max(num_max_sdu_entries, num_fp_entries);
+
+ for (tc = 0; tc < num_tc; tc++) {
l = addattr_nest(n, 1024, TCA_TAPRIO_ATTR_TC_ENTRY | NLA_F_NESTED);
addattr_l(n, 1024, TCA_TAPRIO_TC_ENTRY_INDEX, &tc, sizeof(tc));
- addattr_l(n, 1024, TCA_TAPRIO_TC_ENTRY_MAX_SDU,
- &max_sdu[tc], sizeof(max_sdu[tc]));
+
+ if (tc < num_max_sdu_entries) {
+ addattr_l(n, 1024, TCA_TAPRIO_TC_ENTRY_MAX_SDU,
+ &max_sdu[tc], sizeof(max_sdu[tc]));
+ }
+
+ if (tc < num_fp_entries) {
+ addattr_l(n, 1024, TCA_TAPRIO_TC_ENTRY_FP, &fp[tc],
+ sizeof(fp[tc]));
+ }
addattr_nest_end(n, l);
}
@@ -168,6 +181,7 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
char **argv, struct nlmsghdr *n, const char *dev)
{
__u32 max_sdu[TC_QOPT_MAX_QUEUE] = { };
+ __u32 fp[TC_QOPT_MAX_QUEUE] = { };
__s32 clockid = CLOCKID_INVALID;
struct tc_mqprio_qopt opt = { };
__s64 cycle_time_extension = 0;
@@ -175,6 +189,7 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
bool have_tc_entries = false;
int num_max_sdu_entries = 0;
struct rtattr *tail, *l;
+ int num_fp_entries = 0;
__u32 taprio_flags = 0;
__u32 txtime_delay = 0;
__s64 cycle_time = 0;
@@ -227,6 +242,23 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
free(tmp);
idx++;
}
+ } else if (strcmp(*argv, "fp") == 0) {
+ while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+ NEXT_ARG();
+ if (strcmp(*argv, "E") == 0) {
+ fp[idx] = TC_FP_EXPRESS;
+ } else if (strcmp(*argv, "P") == 0) {
+ fp[idx] = TC_FP_PREEMPTIBLE;
+ } else {
+ fprintf(stderr,
+ "Illegal \"fp\" value \"%s\", expected \"E\" or \"P\"\n",
+ *argv);
+ return -1;
+ }
+ num_fp_entries++;
+ idx++;
+ }
+ have_tc_entries = true;
} else if (strcmp(*argv, "max-sdu") == 0) {
while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
NEXT_ARG();
@@ -369,7 +401,7 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
&cycle_time_extension, sizeof(cycle_time_extension));
if (have_tc_entries)
- add_tc_entries(n, max_sdu, num_max_sdu_entries);
+ add_tc_entries(n, max_sdu, num_max_sdu_entries, fp, num_fp_entries);
l = addattr_nest(n, 1024, TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST | NLA_F_NESTED);
@@ -460,9 +492,10 @@ static int print_schedule(FILE *f, struct rtattr **tb)
return 0;
}
-static void dump_tc_entry(__u32 max_sdu[TC_QOPT_MAX_QUEUE],
- struct rtattr *item, bool *have_tc_entries,
- int *max_tc_index)
+static void dump_tc_entry(struct rtattr *item,
+ __u32 max_sdu[TC_QOPT_MAX_QUEUE],
+ __u32 fp[TC_QOPT_MAX_QUEUE],
+ int *max_tc_max_sdu, int *max_tc_fp)
{
struct rtattr *tb[TCA_TAPRIO_TC_ENTRY_MAX + 1];
__u32 tc, val = 0;
@@ -481,23 +514,30 @@ static void dump_tc_entry(__u32 max_sdu[TC_QOPT_MAX_QUEUE],
return;
}
- if (*max_tc_index < tc)
- *max_tc_index = tc;
-
- if (tb[TCA_TAPRIO_TC_ENTRY_MAX_SDU])
+ if (tb[TCA_TAPRIO_TC_ENTRY_MAX_SDU]) {
val = rta_getattr_u32(tb[TCA_TAPRIO_TC_ENTRY_MAX_SDU]);
+ max_sdu[tc] = val;
+ if (*max_tc_max_sdu < (int)tc)
+ *max_tc_max_sdu = tc;
+ }
- max_sdu[tc] = val;
+ if (tb[TCA_TAPRIO_TC_ENTRY_FP]) {
+ val = rta_getattr_u32(tb[TCA_TAPRIO_TC_ENTRY_FP]);
+ fp[tc] = val;
- *have_tc_entries = true;
+ if (*max_tc_fp < (int)tc)
+ *max_tc_fp = tc;
+ }
}
static void dump_tc_entries(FILE *f, struct rtattr *opt)
{
__u32 max_sdu[TC_QOPT_MAX_QUEUE] = {};
- int tc, rem, max_tc_index = 0;
- bool have_tc_entries = false;
+ __u32 fp[TC_QOPT_MAX_QUEUE] = {};
+ int max_tc_max_sdu = -1;
+ int max_tc_fp = -1;
struct rtattr *i;
+ int tc, rem;
rem = RTA_PAYLOAD(opt);
@@ -505,18 +545,30 @@ static void dump_tc_entries(FILE *f, struct rtattr *opt)
if (i->rta_type != (TCA_TAPRIO_ATTR_TC_ENTRY | NLA_F_NESTED))
continue;
- dump_tc_entry(max_sdu, i, &have_tc_entries, &max_tc_index);
+ dump_tc_entry(i, max_sdu, fp, &max_tc_max_sdu, &max_tc_fp);
}
- if (!have_tc_entries)
- return;
+ if (max_tc_max_sdu >= 0) {
+ open_json_array(PRINT_ANY, "max-sdu");
+ for (tc = 0; tc <= max_tc_max_sdu; tc++)
+ print_uint(PRINT_ANY, NULL, " %u", max_sdu[tc]);
+ close_json_array(PRINT_ANY, "");
- open_json_array(PRINT_ANY, "max-sdu");
- for (tc = 0; tc <= max_tc_index; tc++)
- print_uint(PRINT_ANY, NULL, " %u", max_sdu[tc]);
- close_json_array(PRINT_ANY, "");
+ print_nl();
+ }
- print_nl();
+ if (max_tc_fp >= 0) {
+ open_json_array(PRINT_ANY, "fp");
+ for (tc = 0; tc <= max_tc_fp; tc++) {
+ print_string(PRINT_ANY, NULL, " %s",
+ fp[tc] == TC_FP_PREEMPTIBLE ? "P" :
+ fp[tc] == TC_FP_EXPRESS ? "E" :
+ "?");
+ }
+ close_json_array(PRINT_ANY, "");
+
+ print_nl();
+ }
}
static int taprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
--
2.34.1
Powered by blists - more mailing lists