iproute2/tc/q_mqprio.c
<<
>>
Prefs
   1/*
   2 * q_mqprio.c   MQ prio qdisc
   3 *
   4 *              This program is free software; you can redistribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Author:      John Fastabend, <john.r.fastabend@intel.com>
  10 */
  11
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <unistd.h>
  15#include <fcntl.h>
  16#include <sys/socket.h>
  17#include <netinet/in.h>
  18#include <arpa/inet.h>
  19#include <string.h>
  20
  21#include "utils.h"
  22#include "tc_util.h"
  23
  24static void explain(void)
  25{
  26        fprintf(stderr,
  27                "Usage: ... mqprio      [num_tc NUMBER] [map P0 P1 ...]\n"
  28                "                       [queues count1@offset1 count2@offset2 ...] "
  29                "[hw 1|0]\n"
  30                "                       [mode dcb|channel]\n"
  31                "                       [shaper bw_rlimit SHAPER_PARAMS]\n"
  32                "Where: SHAPER_PARAMS := { min_rate MIN_RATE1 MIN_RATE2 ...|\n"
  33                "                         max_rate MAX_RATE1 MAX_RATE2 ... }\n");
  34}
  35
  36static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
  37                            char **argv, struct nlmsghdr *n, const char *dev)
  38{
  39        int idx;
  40        struct tc_mqprio_qopt opt = {
  41                .num_tc = 8,
  42                .prio_tc_map = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 1, 3, 3, 3, 3 },
  43                .hw = 1,
  44                .count = { },
  45                .offset = { },
  46        };
  47        __u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
  48        __u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
  49        __u16 shaper = TC_MQPRIO_SHAPER_DCB;
  50        __u16 mode = TC_MQPRIO_MODE_DCB;
  51        int cnt_off_pairs = 0;
  52        struct rtattr *tail;
  53        __u32 flags = 0;
  54
  55        while (argc > 0) {
  56                idx = 0;
  57                if (strcmp(*argv, "num_tc") == 0) {
  58                        NEXT_ARG();
  59                        if (get_u8(&opt.num_tc, *argv, 10)) {
  60                                fprintf(stderr, "Illegal \"num_tc\"\n");
  61                                return -1;
  62                        }
  63                } else if (strcmp(*argv, "map") == 0) {
  64                        while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
  65                                NEXT_ARG();
  66                                if (get_u8(&opt.prio_tc_map[idx], *argv, 10)) {
  67                                        PREV_ARG();
  68                                        break;
  69                                }
  70                                idx++;
  71                        }
  72                        for ( ; idx < TC_QOPT_MAX_QUEUE; idx++)
  73                                opt.prio_tc_map[idx] = 0;
  74                } else if (strcmp(*argv, "queues") == 0) {
  75                        char *tmp, *tok;
  76
  77                        while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
  78                                NEXT_ARG();
  79
  80                                tmp = strdup(*argv);
  81                                if (!tmp)
  82                                        break;
  83
  84                                tok = strtok(tmp, "@");
  85                                if (get_u16(&opt.count[idx], tok, 10)) {
  86                                        free(tmp);
  87                                        PREV_ARG();
  88                                        break;
  89                                }
  90                                tok = strtok(NULL, "@");
  91                                if (get_u16(&opt.offset[idx], tok, 10)) {
  92                                        free(tmp);
  93                                        PREV_ARG();
  94                                        break;
  95                                }
  96                                free(tmp);
  97                                idx++;
  98                                cnt_off_pairs++;
  99                        }
 100                } else if (strcmp(*argv, "hw") == 0) {
 101                        NEXT_ARG();
 102                        if (get_u8(&opt.hw, *argv, 10)) {
 103                                fprintf(stderr, "Illegal \"hw\"\n");
 104                                return -1;
 105                        }
 106                        idx++;
 107                } else if (opt.hw && strcmp(*argv, "mode") == 0) {
 108                        NEXT_ARG();
 109                        if (matches(*argv, "dcb") == 0) {
 110                                mode = TC_MQPRIO_MODE_DCB;
 111                        } else if (matches(*argv, "channel") == 0) {
 112                                mode = TC_MQPRIO_MODE_CHANNEL;
 113                        }  else {
 114                                fprintf(stderr, "Illegal mode (%s)\n",
 115                                        *argv);
 116                                return -1;
 117                        }
 118                        if (mode != TC_MQPRIO_MODE_DCB)
 119                                flags |= TC_MQPRIO_F_MODE;
 120                        idx++;
 121                } else if (opt.hw && strcmp(*argv, "shaper") == 0) {
 122                        NEXT_ARG();
 123                        if (matches(*argv, "dcb") == 0) {
 124                                shaper = TC_MQPRIO_SHAPER_DCB;
 125                        } else if (matches(*argv, "bw_rlimit") == 0) {
 126                                shaper = TC_MQPRIO_SHAPER_BW_RATE;
 127                                if (!NEXT_ARG_OK()) {
 128                                        fprintf(stderr, "Incomplete shaper arguments\n");
 129                                        return -1;
 130                                }
 131                        }  else {
 132                                fprintf(stderr, "Illegal shaper (%s)\n",
 133                                        *argv);
 134                                return -1;
 135                        }
 136                        if (shaper != TC_MQPRIO_SHAPER_DCB)
 137                                flags |= TC_MQPRIO_F_SHAPER;
 138                        idx++;
 139                } else if ((shaper == TC_MQPRIO_SHAPER_BW_RATE) &&
 140                           strcmp(*argv, "min_rate") == 0) {
 141                        while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
 142                                NEXT_ARG();
 143                                if (get_rate64(&min_rate64[idx], *argv)) {
 144                                        PREV_ARG();
 145                                        break;
 146                                }
 147                                idx++;
 148                        }
 149                        if (idx < opt.num_tc && !NEXT_ARG_OK()) {
 150                                fprintf(stderr, "Incomplete arguments, min_rate values expected\n");
 151                                return -1;
 152                        }
 153                        flags |= TC_MQPRIO_F_MIN_RATE;
 154                } else if ((shaper == TC_MQPRIO_SHAPER_BW_RATE) &&
 155                           strcmp(*argv, "max_rate") == 0) {
 156                        while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
 157                                NEXT_ARG();
 158                                if (get_rate64(&max_rate64[idx], *argv)) {
 159                                        PREV_ARG();
 160                                        break;
 161                                }
 162                                idx++;
 163                        }
 164                        if (idx < opt.num_tc && !NEXT_ARG_OK()) {
 165                                fprintf(stderr, "Incomplete arguments, max_rate values expected\n");
 166                                return -1;
 167                        }
 168                        flags |= TC_MQPRIO_F_MAX_RATE;
 169                } else if (strcmp(*argv, "help") == 0) {
 170                        explain();
 171                        return -1;
 172                } else {
 173                        invarg("unknown argument", *argv);
 174                }
 175                argc--; argv++;
 176        }
 177
 178        if (cnt_off_pairs > opt.num_tc) {
 179                fprintf(stderr, "queues count/offset pair count %d can not be higher than given num_tc %d\n",
 180                        cnt_off_pairs, opt.num_tc);
 181                return -1;
 182        }
 183
 184        tail = NLMSG_TAIL(n);
 185        addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
 186
 187        if (flags & TC_MQPRIO_F_MODE)
 188                addattr_l(n, 1024, TCA_MQPRIO_MODE,
 189                          &mode, sizeof(mode));
 190        if (flags & TC_MQPRIO_F_SHAPER)
 191                addattr_l(n, 1024, TCA_MQPRIO_SHAPER,
 192                          &shaper, sizeof(shaper));
 193
 194        if (flags & TC_MQPRIO_F_MIN_RATE) {
 195                struct rtattr *start;
 196
 197                start = addattr_nest(n, 1024,
 198                                     TCA_MQPRIO_MIN_RATE64 | NLA_F_NESTED);
 199
 200                for (idx = 0; idx < TC_QOPT_MAX_QUEUE; idx++)
 201                        addattr_l(n, 1024, TCA_MQPRIO_MIN_RATE64,
 202                                  &min_rate64[idx], sizeof(min_rate64[idx]));
 203
 204                addattr_nest_end(n, start);
 205        }
 206
 207        if (flags & TC_MQPRIO_F_MAX_RATE) {
 208                struct rtattr *start;
 209
 210                start = addattr_nest(n, 1024,
 211                                     TCA_MQPRIO_MAX_RATE64 | NLA_F_NESTED);
 212
 213                for (idx = 0; idx < TC_QOPT_MAX_QUEUE; idx++)
 214                        addattr_l(n, 1024, TCA_MQPRIO_MAX_RATE64,
 215                                  &max_rate64[idx], sizeof(max_rate64[idx]));
 216
 217                addattr_nest_end(n, start);
 218        }
 219
 220        tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
 221
 222        return 0;
 223}
 224
 225static int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 226{
 227        int i;
 228        struct tc_mqprio_qopt *qopt;
 229        __u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
 230        __u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
 231        int len;
 232
 233        if (opt == NULL)
 234                return 0;
 235
 236        len = RTA_PAYLOAD(opt) - RTA_ALIGN(sizeof(*qopt));
 237        if (len < 0) {
 238                fprintf(stderr, "options size error\n");
 239                return -1;
 240        }
 241
 242        qopt = RTA_DATA(opt);
 243
 244        print_uint(PRINT_ANY, "tc", "tc %u ", qopt->num_tc);
 245        open_json_array(PRINT_ANY, is_json_context() ? "map" : "map ");
 246        for (i = 0; i <= TC_PRIO_MAX; i++)
 247                print_uint(PRINT_ANY, NULL, "%u ", qopt->prio_tc_map[i]);
 248        close_json_array(PRINT_ANY, "");
 249        open_json_array(PRINT_ANY, is_json_context() ? "queues" : "\n             queues:");
 250        for (i = 0; i < qopt->num_tc; i++) {
 251                open_json_array(PRINT_JSON, NULL);
 252                print_uint(PRINT_ANY, NULL, "(%u:", qopt->offset[i]);
 253                print_uint(PRINT_ANY, NULL, "%u) ", qopt->offset[i] + qopt->count[i] - 1);
 254                close_json_array(PRINT_JSON, NULL);
 255        }
 256        close_json_array(PRINT_ANY, "");
 257
 258        if (len > 0) {
 259                struct rtattr *tb[TCA_MQPRIO_MAX + 1];
 260
 261                parse_rtattr(tb, TCA_MQPRIO_MAX,
 262                             RTA_DATA(opt) + RTA_ALIGN(sizeof(*qopt)),
 263                             len);
 264
 265                if (tb[TCA_MQPRIO_MODE]) {
 266                        __u16 *mode = RTA_DATA(tb[TCA_MQPRIO_MODE]);
 267
 268                        if (*mode == TC_MQPRIO_MODE_CHANNEL)
 269                                print_string(PRINT_ANY, "mode", "\n             mode:%s", "channel");
 270                } else {
 271                        print_string(PRINT_ANY, "mode", "\n             mode:%s", "dcb");
 272                }
 273
 274                if (tb[TCA_MQPRIO_SHAPER]) {
 275                        __u16 *shaper = RTA_DATA(tb[TCA_MQPRIO_SHAPER]);
 276
 277                        if (*shaper == TC_MQPRIO_SHAPER_BW_RATE)
 278                                print_string(PRINT_ANY, "shaper", "\n             shaper:%s", "bw_rlimit");
 279                } else {
 280                        print_string(PRINT_ANY, "shaper", "\n             shaper:%s", "dcb");
 281                }
 282
 283                if (tb[TCA_MQPRIO_MIN_RATE64]) {
 284                        struct rtattr *r;
 285                        int rem = RTA_PAYLOAD(tb[TCA_MQPRIO_MIN_RATE64]);
 286                        __u64 *min = min_rate64;
 287
 288                        for (r = RTA_DATA(tb[TCA_MQPRIO_MIN_RATE64]);
 289                             RTA_OK(r, rem); r = RTA_NEXT(r, rem)) {
 290                                if (r->rta_type != TCA_MQPRIO_MIN_RATE64)
 291                                        return -1;
 292                                *(min++) = rta_getattr_u64(r);
 293                        }
 294                        open_json_array(PRINT_ANY, is_json_context() ? "min_rate" : "   min_rate:");
 295                        for (i = 0; i < qopt->num_tc; i++)
 296                                tc_print_rate(PRINT_ANY, NULL, "%s ", min_rate64[i]);
 297                        close_json_array(PRINT_ANY, "");
 298                }
 299
 300                if (tb[TCA_MQPRIO_MAX_RATE64]) {
 301                        struct rtattr *r;
 302                        int rem = RTA_PAYLOAD(tb[TCA_MQPRIO_MAX_RATE64]);
 303                        __u64 *max = max_rate64;
 304
 305                        for (r = RTA_DATA(tb[TCA_MQPRIO_MAX_RATE64]);
 306                             RTA_OK(r, rem); r = RTA_NEXT(r, rem)) {
 307                                if (r->rta_type != TCA_MQPRIO_MAX_RATE64)
 308                                        return -1;
 309                                *(max++) = rta_getattr_u64(r);
 310                        }
 311                        open_json_array(PRINT_ANY, is_json_context() ? "max_rate" : "   max_rate:");
 312                        for (i = 0; i < qopt->num_tc; i++)
 313                                tc_print_rate(PRINT_ANY, NULL, "%s ", max_rate64[i]);
 314                        close_json_array(PRINT_ANY, "");
 315                }
 316        }
 317        return 0;
 318}
 319
 320struct qdisc_util mqprio_qdisc_util = {
 321        .id             = "mqprio",
 322        .parse_qopt     = mqprio_parse_opt,
 323        .print_qopt     = mqprio_print_opt,
 324};
 325