]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
taprio: Add support for changing schedules
authorVinicius Costa Gomes <vinicius.gomes@intel.com>
Mon, 29 Apr 2019 22:52:18 +0000 (15:52 -0700)
committerDavid Ahern <dsahern@gmail.com>
Sat, 4 May 2019 16:22:15 +0000 (09:22 -0700)
This allows for a new schedule to be specified during runtime, without
removing the current one.

For that, the semantics of the 'tc qdisc change' operation in the
context of taprio is that if "change" is called and there is a running
schedule, a new schedule is created and the base-time (let's call it
X) of this new schedule is used so at instant X, it becomes the
"current" schedule. So, in short, "change" doesn't change the current
schedule, it creates a new one and sets it up to it becomes the
current one at some point.

In IEEE 802.1Q terms, it means that we have support for the
"Oper" (current and read-only) and "Admin" (future and mutable)
schedules.

Example of creating the first schedule, then adding a new one:

(1)
tc qdisc add dev IFACE parent root handle 100 taprio \
             num_tc 1 \
      map 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \
      queues 1@0 \
      sched-entry S 0x1 1000000 \
      sched-entry S 0x0 2000000 \
      sched-entry S 0x1 3000000 \
      sched-entry S 0x0 4000000 \
      base-time 100000000 \
      clockid CLOCK_TAI

(2)
tc qdisc change dev IFACE parent root handle 100 taprio \
      base-time 7500000000000 \
      sched-entry S 0x0 5000000 \
              sched-entry S 0x1 5000000 \

It was necessary to fix a bug, so the clockid doesn't need to be
specified when changing the schedule.

Most of the changes are related to make it easier to reuse the same
function for printing the "admin" and "oper" schedules.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
tc/q_taprio.c

index 8f6b263a4141f341094bde76ddfeeb0cf86759aa..336bb2456cf839a7bd1f6822f68eb0fd5c8911cc 100644 (file)
@@ -268,14 +268,15 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
        tail = NLMSG_TAIL(n);
        addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
 
+       if (clockid != CLOCKID_INVALID)
+               addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_CLOCKID, &clockid, sizeof(clockid));
+
        if (opt.num_tc > 0)
                addattr_l(n, 1024, TCA_TAPRIO_ATTR_PRIOMAP, &opt, sizeof(opt));
 
        if (base_time)
                addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_BASE_TIME, &base_time, sizeof(base_time));
 
-       addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_CLOCKID, &clockid, sizeof(clockid));
-
        if (!list_empty(&sched_entries)) {
                struct rtattr *entry_list;
                entry_list = addattr_nest(n, 1024, TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST | NLA_F_NESTED);
@@ -306,6 +307,8 @@ static int print_sched_list(FILE *f, struct rtattr *list)
 
        open_json_array(PRINT_JSON, "schedule");
 
+       print_string(PRINT_FP, NULL, "%s", _SL_);
+
        for (item = RTA_DATA(list); RTA_OK(item, rem); item = RTA_NEXT(item, rem)) {
                struct rtattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1];
                __u32 index = 0, gatemask = 0, interval = 0;
@@ -340,12 +343,25 @@ static int print_sched_list(FILE *f, struct rtattr *list)
        return 0;
 }
 
+static int print_schedule(FILE *f, struct rtattr **tb)
+{
+       int64_t base_time = 0;
+
+       if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME])
+               base_time = rta_getattr_s64(tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]);
+
+       print_lluint(PRINT_ANY, "base_time", "\tbase-time %lld", base_time);
+
+       print_sched_list(f, tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST]);
+
+       return 0;
+}
+
 static int taprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 {
        struct rtattr *tb[TCA_TAPRIO_ATTR_MAX + 1];
        struct tc_mqprio_qopt *qopt = 0;
        __s32 clockid = CLOCKID_INVALID;
-       __s64 base_time = 0;
        int i;
 
        if (opt == NULL)
@@ -378,19 +394,27 @@ static int taprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 
        print_string(PRINT_FP, NULL, "%s", _SL_);
 
-       if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME])
-               base_time = rta_getattr_s64(tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]);
-
        if (tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID])
                clockid = rta_getattr_s32(tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]);
 
        print_string(PRINT_ANY, "clockid", "clockid %s", get_clock_name(clockid));
 
-       print_lluint(PRINT_ANY, "base_time", " base-time %lld", base_time);
+       print_schedule(f, tb);
 
-       print_string(PRINT_FP, NULL, "%s", _SL_);
+       if (tb[TCA_TAPRIO_ATTR_ADMIN_SCHED]) {
+               struct rtattr *t[TCA_TAPRIO_ATTR_MAX + 1];
+
+               parse_rtattr_nested(t, TCA_TAPRIO_ATTR_MAX,
+                                   tb[TCA_TAPRIO_ATTR_ADMIN_SCHED]);
 
-       return print_sched_list(f, tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST]);
+               open_json_object(NULL);
+
+               print_schedule(f, t);
+
+               close_json_object();
+       }
+
+       return 0;
 }
 
 struct qdisc_util taprio_qdisc_util = {