]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
tc/mqprio: Offload mode and shaper options in mqprio
authorAmritha Nambiar <amritha.nambiar@intel.com>
Wed, 1 Nov 2017 07:45:42 +0000 (00:45 -0700)
committerStephen Hemminger <stephen@networkplumber.org>
Wed, 1 Nov 2017 21:20:06 +0000 (22:20 +0100)
This patch was previously submitted as RFC. Submitting this as
non-RFC now that the tc/mqprio changes are accepted in net-next.

Adds new mqprio options for 'mode' and 'shaper'. The mode
option can take values for offload modes such as 'dcb' (default),
'channel' with the 'hw' option set to 1. The new 'channel' mode
supports offloading TCs and other queue configurations. The
'shaper' option is to support HW shapers ('dcb' default) and
takes the value 'bw_rlimit' for bandwidth rate limiting. The
parameters to the bw_rlimit shaper are minimum and maximum
bandwidth rates. New HW shapers in future can be supported
through the shaper attribute.

# tc qdisc add dev eth0 root mqprio num_tc 2  map 0 0 0 0 1 1 1 1\
  queues 4@0 4@4 hw 1 mode channel shaper bw_rlimit\
  min_rate 1Gbit 2Gbit max_rate 4Gbit 5Gbit

# tc qdisc show dev eth0

qdisc mqprio 804a: root  tc 2 map 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0
             queues:(0:3) (4:7)
             mode:channel
             shaper:bw_rlimit   min_rate:1Gbit 2Gbit   max_rate:4Gbit 5Gbit

v2: Avoid buffer overrun and minor cleanup.

Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
tc/q_mqprio.c

index d6718fb1c2bed00002ce11e270daa37e6dd9a027..b57351c2be6e86587e884a682d6b4810f15bba19 100644 (file)
@@ -27,6 +27,10 @@ static void explain(void)
        fprintf(stderr, "Usage: ... mqprio [num_tc NUMBER] [map P0 P1 ...]\n");
        fprintf(stderr, "                  [queues count1@offset1 count2@offset2 ...] ");
        fprintf(stderr, "[hw 1|0]\n");
+       fprintf(stderr, "                  [mode dcb|channel]\n");
+       fprintf(stderr, "                  [shaper bw_rlimit SHAPER_PARAMS]\n"
+               "Where: SHAPER_PARAMS := { min_rate MIN_RATE1 MIN_RATE2 ...|\n"
+               "                          max_rate MAX_RATE1 MAX_RATE2 ... }\n");
 }
 
 static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
@@ -40,6 +44,12 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
                .count = { },
                .offset = { },
        };
+       __u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
+       __u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
+       __u16 shaper = TC_MQPRIO_SHAPER_DCB;
+       __u16 mode = TC_MQPRIO_MODE_DCB;
+       struct rtattr *tail;
+       __u32 flags = 0;
 
        while (argc > 0) {
                idx = 0;
@@ -92,6 +102,68 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
                                return -1;
                        }
                        idx++;
+               } else if (opt.hw && strcmp(*argv, "mode") == 0) {
+                       NEXT_ARG();
+                       if (matches(*argv, "dcb") == 0) {
+                               mode = TC_MQPRIO_MODE_DCB;
+                       } else if (matches(*argv, "channel") == 0) {
+                               mode = TC_MQPRIO_MODE_CHANNEL;
+                       }  else {
+                               fprintf(stderr, "Illegal mode (%s)\n",
+                                       *argv);
+                               return -1;
+                       }
+                       if (mode != TC_MQPRIO_MODE_DCB)
+                               flags |= TC_MQPRIO_F_MODE;
+                       idx++;
+               } else if (opt.hw && strcmp(*argv, "shaper") == 0) {
+                       NEXT_ARG();
+                       if (matches(*argv, "dcb") == 0) {
+                               shaper = TC_MQPRIO_SHAPER_DCB;
+                       } else if (matches(*argv, "bw_rlimit") == 0) {
+                               shaper = TC_MQPRIO_SHAPER_BW_RATE;
+                               if (!NEXT_ARG_OK()) {
+                                       fprintf(stderr, "Incomplete shaper arguments\n");
+                                       return -1;
+                               }
+                       }  else {
+                               fprintf(stderr, "Illegal shaper (%s)\n",
+                                       *argv);
+                               return -1;
+                       }
+                       if (shaper != TC_MQPRIO_SHAPER_DCB)
+                               flags |= TC_MQPRIO_F_SHAPER;
+                       idx++;
+               } else if ((shaper == TC_MQPRIO_SHAPER_BW_RATE) &&
+                          strcmp(*argv, "min_rate") == 0) {
+                       while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+                               NEXT_ARG();
+                               if (get_rate64(&min_rate64[idx], *argv)) {
+                                       PREV_ARG();
+                                       break;
+                               }
+                               idx++;
+                       }
+                       if (idx < opt.num_tc && !NEXT_ARG_OK()) {
+                               fprintf(stderr, "Incomplete arguments, min_rate values expected\n");
+                               return -1;
+                       }
+                       flags |= TC_MQPRIO_F_MIN_RATE;
+               } else if ((shaper == TC_MQPRIO_SHAPER_BW_RATE) &&
+                          strcmp(*argv, "max_rate") == 0) {
+                       while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+                               NEXT_ARG();
+                               if (get_rate64(&max_rate64[idx], *argv)) {
+                                       PREV_ARG();
+                                       break;
+                               }
+                               idx++;
+                       }
+                       if (idx < opt.num_tc && !NEXT_ARG_OK()) {
+                               fprintf(stderr, "Incomplete arguments, max_rate values expected\n");
+                               return -1;
+                       }
+                       flags |= TC_MQPRIO_F_MAX_RATE;
                } else if (strcmp(*argv, "help") == 0) {
                        explain();
                        return -1;
@@ -102,7 +174,44 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
                argc--; argv++;
        }
 
+       tail = NLMSG_TAIL(n);
        addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+
+       if (flags & TC_MQPRIO_F_MODE)
+               addattr_l(n, 1024, TCA_MQPRIO_MODE,
+                         &mode, sizeof(mode));
+       if (flags & TC_MQPRIO_F_SHAPER)
+               addattr_l(n, 1024, TCA_MQPRIO_SHAPER,
+                         &shaper, sizeof(shaper));
+
+       if (flags & TC_MQPRIO_F_MIN_RATE) {
+               struct rtattr *start;
+
+               start = addattr_nest(n, 1024,
+                                    TCA_MQPRIO_MIN_RATE64 | NLA_F_NESTED);
+
+               for (idx = 0; idx < TC_QOPT_MAX_QUEUE; idx++)
+                       addattr_l(n, 1024, TCA_MQPRIO_MIN_RATE64,
+                                 &min_rate64[idx], sizeof(min_rate64[idx]));
+
+               addattr_nest_end(n, start);
+       }
+
+       if (flags & TC_MQPRIO_F_MAX_RATE) {
+               struct rtattr *start;
+
+               start = addattr_nest(n, 1024,
+                                    TCA_MQPRIO_MAX_RATE64 | NLA_F_NESTED);
+
+               for (idx = 0; idx < TC_QOPT_MAX_QUEUE; idx++)
+                       addattr_l(n, 1024, TCA_MQPRIO_MAX_RATE64,
+                                 &max_rate64[idx], sizeof(max_rate64[idx]));
+
+               addattr_nest_end(n, start);
+       }
+
+       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+
        return 0;
 }
 
@@ -110,10 +219,21 @@ static int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 {
        int i;
        struct tc_mqprio_qopt *qopt;
+       __u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
+       __u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
+       int len;
+
+       SPRINT_BUF(b1);
 
        if (opt == NULL)
                return 0;
 
+       len = RTA_PAYLOAD(opt) - RTA_ALIGN(sizeof(*qopt));
+       if (len < 0) {
+               fprintf(stderr, "options size error\n");
+               return -1;
+       }
+
        qopt = RTA_DATA(opt);
 
        fprintf(f, " tc %u map ", qopt->num_tc);
@@ -123,6 +243,64 @@ static int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        for (i = 0; i < qopt->num_tc; i++)
                fprintf(f, "(%u:%u) ", qopt->offset[i],
                        qopt->offset[i] + qopt->count[i] - 1);
+
+       if (len > 0) {
+               struct rtattr *tb[TCA_MQPRIO_MAX + 1];
+
+               parse_rtattr(tb, TCA_MQPRIO_MAX,
+                            RTA_DATA(opt) + RTA_ALIGN(sizeof(*qopt)),
+                            len);
+
+               if (tb[TCA_MQPRIO_MODE]) {
+                       __u16 *mode = RTA_DATA(tb[TCA_MQPRIO_MODE]);
+
+                       if (*mode == TC_MQPRIO_MODE_CHANNEL)
+                               fprintf(f, "\n             mode:channel");
+               } else {
+                       fprintf(f, "\n             mode:dcb");
+               }
+
+               if (tb[TCA_MQPRIO_SHAPER]) {
+                       __u16 *shaper = RTA_DATA(tb[TCA_MQPRIO_SHAPER]);
+
+                       if (*shaper == TC_MQPRIO_SHAPER_BW_RATE)
+                               fprintf(f, "\n             shaper:bw_rlimit");
+               } else {
+                       fprintf(f, "\n             shaper:dcb");
+               }
+
+               if (tb[TCA_MQPRIO_MIN_RATE64]) {
+                       struct rtattr *r;
+                       int rem = RTA_PAYLOAD(tb[TCA_MQPRIO_MIN_RATE64]);
+                       __u64 *min = min_rate64;
+
+                       for (r = RTA_DATA(tb[TCA_MQPRIO_MIN_RATE64]);
+                            RTA_OK(r, rem); r = RTA_NEXT(r, rem)) {
+                               if (r->rta_type != TCA_MQPRIO_MIN_RATE64)
+                                       return -1;
+                               *(min++) = rta_getattr_u64(r);
+                       }
+                       fprintf(f, "    min_rate:");
+                       for (i = 0; i < qopt->num_tc; i++)
+                               fprintf(f, "%s ", sprint_rate(min_rate64[i], b1));
+               }
+
+               if (tb[TCA_MQPRIO_MAX_RATE64]) {
+                       struct rtattr *r;
+                       int rem = RTA_PAYLOAD(tb[TCA_MQPRIO_MAX_RATE64]);
+                       __u64 *max = max_rate64;
+
+                       for (r = RTA_DATA(tb[TCA_MQPRIO_MAX_RATE64]);
+                            RTA_OK(r, rem); r = RTA_NEXT(r, rem)) {
+                               if (r->rta_type != TCA_MQPRIO_MAX_RATE64)
+                                       return -1;
+                               *(max++) = rta_getattr_u64(r);
+                       }
+                       fprintf(f, "    max_rate:");
+                       for (i = 0; i < qopt->num_tc; i++)
+                               fprintf(f, "%s ", sprint_rate(max_rate64[i], b1));
+               }
+       }
        return 0;
 }