]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
tc/taprio: add support for preemptible traffic classes
authorVladimir Oltean <vladimir.oltean@nxp.com>
Tue, 18 Apr 2023 11:39:53 +0000 (14:39 +0300)
committerDavid Ahern <dsahern@kernel.org>
Tue, 25 Apr 2023 01:43:26 +0000 (19:43 -0600)
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@nxp.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
man/man8/tc-taprio.8
tc/q_taprio.c

index c3ccefea9c8a62af6de213c7994378813d4e8b99..bf489b032a7eb3205a458b804288602497fc5b68 100644 (file)
@@ -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
index c0da65fe37446f074e394730d452c08371558482..bc29710c46869f0d7e265e773dd819f7283cd42b 100644 (file)
@@ -49,6 +49,7 @@ static void explain(void)
                "               [queues COUNT@OFFSET COUNT@OFFSET COUNT@OFFSET ...]\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)