iproute2/tc/q_ets.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2
   3/*
   4 * Enhanced Transmission Selection - 802.1Qaz-based Qdisc
   5 */
   6
   7#include <stdio.h>
   8#include <stdlib.h>
   9#include <unistd.h>
  10#include <fcntl.h>
  11#include <sys/socket.h>
  12#include <netinet/in.h>
  13#include <arpa/inet.h>
  14#include <string.h>
  15
  16#include "utils.h"
  17#include "tc_util.h"
  18
  19static void explain(void)
  20{
  21        fprintf(stderr, "Usage: ... ets [bands NUMBER] [strict NUMBER] [quanta Q1 Q2...] [priomap P1 P2...]\n");
  22}
  23
  24static void cexplain(void)
  25{
  26        fprintf(stderr, "Usage: ... ets [quantum Q1]\n");
  27}
  28
  29static unsigned int parse_quantum(const char *arg)
  30{
  31        unsigned int quantum;
  32
  33        if (get_unsigned(&quantum, arg, 10)) {
  34                fprintf(stderr, "Illegal \"quanta\" element\n");
  35                return 0;
  36        }
  37        if (!quantum)
  38                fprintf(stderr, "\"quanta\" must be > 0\n");
  39        return quantum;
  40}
  41
  42static int parse_nbands(const char *arg, __u8 *pnbands, const char *what)
  43{
  44        unsigned int tmp;
  45
  46        if (get_unsigned(&tmp, arg, 10)) {
  47                fprintf(stderr, "Illegal \"%s\"\n", what);
  48                return -1;
  49        }
  50        if (tmp > TCQ_ETS_MAX_BANDS) {
  51                fprintf(stderr, "The number of \"%s\" must be <= %d\n",
  52                        what, TCQ_ETS_MAX_BANDS);
  53                return -1;
  54        }
  55
  56        *pnbands = tmp;
  57        return 0;
  58}
  59
  60static int ets_parse_opt(struct qdisc_util *qu, int argc, char **argv,
  61                         struct nlmsghdr *n, const char *dev)
  62{
  63        __u8 nbands = 0;
  64        __u8 nstrict = 0;
  65        bool quanta_mode = false;
  66        unsigned int nquanta = 0;
  67        __u32 quanta[TCQ_ETS_MAX_BANDS];
  68        bool priomap_mode = false;
  69        unsigned int nprio = 0;
  70        __u8 priomap[TC_PRIO_MAX + 1];
  71        unsigned int tmp;
  72        struct rtattr *tail, *nest;
  73
  74        while (argc > 0) {
  75                if (strcmp(*argv, "bands") == 0) {
  76                        if (nbands) {
  77                                fprintf(stderr, "Duplicate \"bands\"\n");
  78                                return -1;
  79                        }
  80                        NEXT_ARG();
  81                        if (parse_nbands(*argv, &nbands, "bands"))
  82                                return -1;
  83                        priomap_mode = quanta_mode = false;
  84                } else if (strcmp(*argv, "strict") == 0) {
  85                        if (nstrict) {
  86                                fprintf(stderr, "Duplicate \"strict\"\n");
  87                                return -1;
  88                        }
  89                        NEXT_ARG();
  90                        if (parse_nbands(*argv, &nstrict, "strict"))
  91                                return -1;
  92                        priomap_mode = quanta_mode = false;
  93                } else if (strcmp(*argv, "quanta") == 0) {
  94                        if (nquanta) {
  95                                fprintf(stderr, "Duplicate \"quanta\"\n");
  96                                return -1;
  97                        }
  98                        NEXT_ARG();
  99                        priomap_mode = false;
 100                        quanta_mode = true;
 101                        goto parse_quantum;
 102                } else if (strcmp(*argv, "priomap") == 0) {
 103                        if (nprio) {
 104                                fprintf(stderr, "Duplicate \"priomap\"\n");
 105                                return -1;
 106                        }
 107                        NEXT_ARG();
 108                        priomap_mode = true;
 109                        quanta_mode = false;
 110                        goto parse_priomap;
 111                } else if (strcmp(*argv, "help") == 0) {
 112                        explain();
 113                        return -1;
 114                } else if (quanta_mode) {
 115                        unsigned int quantum;
 116
 117parse_quantum:
 118                        quantum = parse_quantum(*argv);
 119                        if (!quantum)
 120                                return -1;
 121                        quanta[nquanta++] = quantum;
 122                } else if (priomap_mode) {
 123                        unsigned int band;
 124
 125parse_priomap:
 126                        if (get_unsigned(&band, *argv, 10)) {
 127                                fprintf(stderr, "Illegal \"priomap\" element\n");
 128                                return -1;
 129                        }
 130                        if (nprio > TC_PRIO_MAX) {
 131                                fprintf(stderr, "\"priomap\" index cannot be higher than %u\n", TC_PRIO_MAX);
 132                                return -1;
 133                        }
 134                        priomap[nprio++] = band;
 135                } else {
 136                        fprintf(stderr, "What is \"%s\"?\n", *argv);
 137                        explain();
 138                        return -1;
 139                }
 140                argc--; argv++;
 141        }
 142
 143        if (!nbands)
 144                nbands = nquanta + nstrict;
 145        if (!nbands) {
 146                fprintf(stderr, "One of \"bands\", \"quanta\" or \"strict\" needs to be specified\n");
 147                explain();
 148                return -1;
 149        }
 150        if (nstrict + nquanta > nbands) {
 151                fprintf(stderr, "Not enough total bands to cover all the strict bands and quanta\n");
 152                explain();
 153                return -1;
 154        }
 155        for (tmp = 0; tmp < nprio; tmp++) {
 156                if (priomap[tmp] >= nbands) {
 157                        fprintf(stderr, "\"priomap\" element is out of bounds\n");
 158                        return -1;
 159                }
 160        }
 161
 162        tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED);
 163        addattr_l(n, 1024, TCA_ETS_NBANDS, &nbands, sizeof(nbands));
 164        if (nstrict)
 165                addattr_l(n, 1024, TCA_ETS_NSTRICT, &nstrict, sizeof(nstrict));
 166        if (nquanta) {
 167                nest = addattr_nest(n, 1024, TCA_ETS_QUANTA | NLA_F_NESTED);
 168                for (tmp = 0; tmp < nquanta; tmp++)
 169                        addattr_l(n, 1024, TCA_ETS_QUANTA_BAND,
 170                                  &quanta[tmp], sizeof(quanta[0]));
 171                addattr_nest_end(n, nest);
 172        }
 173        if (nprio) {
 174                nest = addattr_nest(n, 1024, TCA_ETS_PRIOMAP | NLA_F_NESTED);
 175                for (tmp = 0; tmp < nprio; tmp++)
 176                        addattr_l(n, 1024, TCA_ETS_PRIOMAP_BAND,
 177                                  &priomap[tmp], sizeof(priomap[0]));
 178                addattr_nest_end(n, nest);
 179        }
 180        addattr_nest_end(n, tail);
 181
 182        return 0;
 183}
 184
 185static int ets_parse_copt(struct qdisc_util *qu, int argc, char **argv,
 186                          struct nlmsghdr *n, const char *dev)
 187{
 188        unsigned int quantum = 0;
 189        struct rtattr *tail;
 190
 191        while (argc > 0) {
 192                if (strcmp(*argv, "quantum") == 0) {
 193                        if (quantum) {
 194                                fprintf(stderr, "Duplicate \"quantum\"\n");
 195                                return -1;
 196                        }
 197                        NEXT_ARG();
 198                        quantum = parse_quantum(*argv);
 199                        if (!quantum)
 200                                return -1;
 201                } else if (strcmp(*argv, "help") == 0) {
 202                        cexplain();
 203                        return -1;
 204                } else {
 205                        fprintf(stderr, "What is \"%s\"?\n", *argv);
 206                        cexplain();
 207                        return -1;
 208                }
 209                argc--; argv++;
 210        }
 211
 212        tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED);
 213        if (quantum)
 214                addattr_l(n, 1024, TCA_ETS_QUANTA_BAND, &quantum,
 215                          sizeof(quantum));
 216        addattr_nest_end(n, tail);
 217
 218        return 0;
 219}
 220
 221static int ets_print_opt_quanta(struct rtattr *opt)
 222{
 223        int len = RTA_PAYLOAD(opt);
 224        unsigned int offset;
 225
 226        open_json_array(PRINT_ANY, "quanta");
 227        for (offset = 0; offset < len; ) {
 228                struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL};
 229                struct rtattr *attr;
 230                __u32 quantum;
 231
 232                attr = RTA_DATA(opt) + offset;
 233                parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset);
 234                offset += RTA_LENGTH(RTA_PAYLOAD(attr));
 235
 236                if (!tb[TCA_ETS_QUANTA_BAND]) {
 237                        fprintf(stderr, "No ETS band quantum\n");
 238                        return -1;
 239                }
 240
 241                quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]);
 242                print_uint(PRINT_ANY, NULL, " %u", quantum);
 243
 244        }
 245        close_json_array(PRINT_ANY, " ");
 246
 247        return 0;
 248}
 249
 250static int ets_print_opt_priomap(struct rtattr *opt)
 251{
 252        int len = RTA_PAYLOAD(opt);
 253        unsigned int offset;
 254
 255        open_json_array(PRINT_ANY, "priomap");
 256        for (offset = 0; offset < len; ) {
 257                struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL};
 258                struct rtattr *attr;
 259                __u8 band;
 260
 261                attr = RTA_DATA(opt) + offset;
 262                parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset);
 263                offset += RTA_LENGTH(RTA_PAYLOAD(attr)) + 3 /* padding */;
 264
 265                if (!tb[TCA_ETS_PRIOMAP_BAND]) {
 266                        fprintf(stderr, "No ETS priomap band\n");
 267                        return -1;
 268                }
 269
 270                band = rta_getattr_u8(tb[TCA_ETS_PRIOMAP_BAND]);
 271                print_uint(PRINT_ANY, NULL, " %u", band);
 272
 273        }
 274        close_json_array(PRINT_ANY, " ");
 275
 276        return 0;
 277}
 278
 279static int ets_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 280{
 281        struct rtattr *tb[TCA_ETS_MAX + 1];
 282        __u8 nbands;
 283        __u8 nstrict;
 284        int err;
 285
 286        if (opt == NULL)
 287                return 0;
 288
 289        parse_rtattr_nested(tb, TCA_ETS_MAX, opt);
 290
 291        if (!tb[TCA_ETS_NBANDS] || !tb[TCA_ETS_PRIOMAP]) {
 292                fprintf(stderr, "Incomplete ETS options\n");
 293                return -1;
 294        }
 295
 296        nbands = rta_getattr_u8(tb[TCA_ETS_NBANDS]);
 297        print_uint(PRINT_ANY, "bands", "bands %u ", nbands);
 298
 299        if (tb[TCA_ETS_NSTRICT]) {
 300                nstrict = rta_getattr_u8(tb[TCA_ETS_NSTRICT]);
 301                print_uint(PRINT_ANY, "strict", "strict %u ", nstrict);
 302        }
 303
 304        if (tb[TCA_ETS_QUANTA]) {
 305                err = ets_print_opt_quanta(tb[TCA_ETS_QUANTA]);
 306                if (err)
 307                        return err;
 308        }
 309
 310        return ets_print_opt_priomap(tb[TCA_ETS_PRIOMAP]);
 311}
 312
 313static int ets_print_copt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 314{
 315        struct rtattr *tb[TCA_ETS_MAX + 1];
 316        __u32 quantum;
 317
 318        if (opt == NULL)
 319                return 0;
 320
 321        parse_rtattr_nested(tb, TCA_ETS_MAX, opt);
 322
 323        if (tb[TCA_ETS_QUANTA_BAND]) {
 324                quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]);
 325                print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum);
 326        }
 327
 328        return 0;
 329}
 330
 331struct qdisc_util ets_qdisc_util = {
 332        .id             = "ets",
 333        .parse_qopt     = ets_parse_opt,
 334        .parse_copt     = ets_parse_copt,
 335        .print_qopt     = ets_print_opt,
 336        .print_copt     = ets_print_copt,
 337};
 338