iproute2/tc/q_fq.c
<<
>>
Prefs
   1/*
   2 * Fair Queue
   3 *
   4 *  Copyright (C) 2013-2015 Eric Dumazet <edumazet@google.com>
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions
   8 * are met:
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions, and the following disclaimer,
  11 *    without modification.
  12 * 2. Redistributions in binary form must reproduce the above copyright
  13 *    notice, this list of conditions and the following disclaimer in the
  14 *    documentation and/or other materials provided with the distribution.
  15 * 3. The names of the authors may not be used to endorse or promote products
  16 *    derived from this software without specific prior written permission.
  17 *
  18 * Alternatively, provided that this notice is retained in full, this
  19 * software may be distributed under the terms of the GNU General
  20 * Public License ("GPL") version 2, in which case the provisions of the
  21 * GPL apply INSTEAD OF those given above.
  22 *
  23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  34 * DAMAGE.
  35 *
  36 */
  37
  38#include <stdio.h>
  39#include <stdlib.h>
  40#include <unistd.h>
  41#include <fcntl.h>
  42#include <sys/socket.h>
  43#include <netinet/in.h>
  44#include <arpa/inet.h>
  45#include <string.h>
  46#include <stdbool.h>
  47
  48#include "utils.h"
  49#include "tc_util.h"
  50
  51static void explain(void)
  52{
  53        fprintf(stderr,
  54                "Usage: ... fq  [ limit PACKETS ] [ flow_limit PACKETS ]\n"
  55                "               [ quantum BYTES ] [ initial_quantum BYTES ]\n"
  56                "               [ maxrate RATE  ] [ buckets NUMBER ]\n"
  57                "               [ [no]pacing ] [ refill_delay TIME ]\n"
  58                "               [ low_rate_threshold RATE ]\n"
  59                "               [ orphan_mask MASK]\n"
  60                "               [ timer_slack TIME]\n"
  61                "               [ ce_threshold TIME ]\n"
  62                "               [ horizon TIME ]\n"
  63                "               [ horizon_{cap|drop} ]\n");
  64}
  65
  66static unsigned int ilog2(unsigned int val)
  67{
  68        unsigned int res = 0;
  69
  70        val--;
  71        while (val) {
  72                res++;
  73                val >>= 1;
  74        }
  75        return res;
  76}
  77
  78static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
  79                        struct nlmsghdr *n, const char *dev)
  80{
  81        unsigned int plimit;
  82        unsigned int flow_plimit;
  83        unsigned int quantum;
  84        unsigned int initial_quantum;
  85        unsigned int buckets = 0;
  86        unsigned int maxrate;
  87        unsigned int low_rate_threshold;
  88        unsigned int defrate;
  89        unsigned int refill_delay;
  90        unsigned int orphan_mask;
  91        unsigned int ce_threshold;
  92        unsigned int timer_slack;
  93        unsigned int horizon;
  94        __u8 horizon_drop = 255;
  95        bool set_plimit = false;
  96        bool set_flow_plimit = false;
  97        bool set_quantum = false;
  98        bool set_initial_quantum = false;
  99        bool set_maxrate = false;
 100        bool set_defrate = false;
 101        bool set_refill_delay = false;
 102        bool set_orphan_mask = false;
 103        bool set_low_rate_threshold = false;
 104        bool set_ce_threshold = false;
 105        bool set_timer_slack = false;
 106        bool set_horizon = false;
 107        int pacing = -1;
 108        struct rtattr *tail;
 109
 110        while (argc > 0) {
 111                if (strcmp(*argv, "limit") == 0) {
 112                        NEXT_ARG();
 113                        if (get_unsigned(&plimit, *argv, 0)) {
 114                                fprintf(stderr, "Illegal \"limit\"\n");
 115                                return -1;
 116                        }
 117                        set_plimit = true;
 118                } else if (strcmp(*argv, "flow_limit") == 0) {
 119                        NEXT_ARG();
 120                        if (get_unsigned(&flow_plimit, *argv, 0)) {
 121                                fprintf(stderr, "Illegal \"flow_limit\"\n");
 122                                return -1;
 123                        }
 124                        set_flow_plimit = true;
 125                } else if (strcmp(*argv, "buckets") == 0) {
 126                        NEXT_ARG();
 127                        if (get_unsigned(&buckets, *argv, 0)) {
 128                                fprintf(stderr, "Illegal \"buckets\"\n");
 129                                return -1;
 130                        }
 131                } else if (strcmp(*argv, "maxrate") == 0) {
 132                        NEXT_ARG();
 133                        if (strchr(*argv, '%')) {
 134                                if (get_percent_rate(&maxrate, *argv, dev)) {
 135                                        fprintf(stderr, "Illegal \"maxrate\"\n");
 136                                        return -1;
 137                                }
 138                        } else if (get_rate(&maxrate, *argv)) {
 139                                fprintf(stderr, "Illegal \"maxrate\"\n");
 140                                return -1;
 141                        }
 142                        set_maxrate = true;
 143                } else if (strcmp(*argv, "low_rate_threshold") == 0) {
 144                        NEXT_ARG();
 145                        if (get_rate(&low_rate_threshold, *argv)) {
 146                                fprintf(stderr, "Illegal \"low_rate_threshold\"\n");
 147                                return -1;
 148                        }
 149                        set_low_rate_threshold = true;
 150                } else if (strcmp(*argv, "ce_threshold") == 0) {
 151                        NEXT_ARG();
 152                        if (get_time(&ce_threshold, *argv)) {
 153                                fprintf(stderr, "Illegal \"ce_threshold\"\n");
 154                                return -1;
 155                        }
 156                        set_ce_threshold = true;
 157                } else if (strcmp(*argv, "timer_slack") == 0) {
 158                        __s64 t64;
 159
 160                        NEXT_ARG();
 161                        if (get_time64(&t64, *argv)) {
 162                                fprintf(stderr, "Illegal \"timer_slack\"\n");
 163                                return -1;
 164                        }
 165                        timer_slack = t64;
 166                        if (timer_slack != t64) {
 167                                fprintf(stderr, "Illegal (out of range) \"timer_slack\"\n");
 168                                return -1;
 169                        }
 170                        set_timer_slack = true;
 171                } else if (strcmp(*argv, "horizon_drop") == 0) {
 172                        horizon_drop = 1;
 173                } else if (strcmp(*argv, "horizon_cap") == 0) {
 174                        horizon_drop = 0;
 175                } else if (strcmp(*argv, "horizon") == 0) {
 176                        NEXT_ARG();
 177                        if (get_time(&horizon, *argv)) {
 178                                fprintf(stderr, "Illegal \"horizon\"\n");
 179                                return -1;
 180                        }
 181                        set_horizon = true;
 182                } else if (strcmp(*argv, "defrate") == 0) {
 183                        NEXT_ARG();
 184                        if (strchr(*argv, '%')) {
 185                                if (get_percent_rate(&defrate, *argv, dev)) {
 186                                        fprintf(stderr, "Illegal \"defrate\"\n");
 187                                        return -1;
 188                                }
 189                        } else if (get_rate(&defrate, *argv)) {
 190                                fprintf(stderr, "Illegal \"defrate\"\n");
 191                                return -1;
 192                        }
 193                        set_defrate = true;
 194                } else if (strcmp(*argv, "quantum") == 0) {
 195                        NEXT_ARG();
 196                        if (get_unsigned(&quantum, *argv, 0)) {
 197                                fprintf(stderr, "Illegal \"quantum\"\n");
 198                                return -1;
 199                        }
 200                        set_quantum = true;
 201                } else if (strcmp(*argv, "initial_quantum") == 0) {
 202                        NEXT_ARG();
 203                        if (get_unsigned(&initial_quantum, *argv, 0)) {
 204                                fprintf(stderr, "Illegal \"initial_quantum\"\n");
 205                                return -1;
 206                        }
 207                        set_initial_quantum = true;
 208                } else if (strcmp(*argv, "orphan_mask") == 0) {
 209                        NEXT_ARG();
 210                        if (get_unsigned(&orphan_mask, *argv, 0)) {
 211                                fprintf(stderr, "Illegal \"initial_quantum\"\n");
 212                                return -1;
 213                        }
 214                        set_orphan_mask = true;
 215                } else if (strcmp(*argv, "refill_delay") == 0) {
 216                        NEXT_ARG();
 217                        if (get_time(&refill_delay, *argv)) {
 218                                fprintf(stderr, "Illegal \"refill_delay\"\n");
 219                                return -1;
 220                        }
 221                        set_refill_delay = true;
 222                } else if (strcmp(*argv, "pacing") == 0) {
 223                        pacing = 1;
 224                } else if (strcmp(*argv, "nopacing") == 0) {
 225                        pacing = 0;
 226                } else if (strcmp(*argv, "help") == 0) {
 227                        explain();
 228                        return -1;
 229                } else {
 230                        fprintf(stderr, "What is \"%s\"?\n", *argv);
 231                        explain();
 232                        return -1;
 233                }
 234                argc--; argv++;
 235        }
 236
 237        tail = addattr_nest(n, 1024, TCA_OPTIONS);
 238        if (buckets) {
 239                unsigned int log = ilog2(buckets);
 240
 241                addattr_l(n, 1024, TCA_FQ_BUCKETS_LOG,
 242                          &log, sizeof(log));
 243        }
 244        if (set_plimit)
 245                addattr_l(n, 1024, TCA_FQ_PLIMIT,
 246                          &plimit, sizeof(plimit));
 247        if (set_flow_plimit)
 248                addattr_l(n, 1024, TCA_FQ_FLOW_PLIMIT,
 249                          &flow_plimit, sizeof(flow_plimit));
 250        if (set_quantum)
 251                addattr_l(n, 1024, TCA_FQ_QUANTUM, &quantum, sizeof(quantum));
 252        if (set_initial_quantum)
 253                addattr_l(n, 1024, TCA_FQ_INITIAL_QUANTUM,
 254                          &initial_quantum, sizeof(initial_quantum));
 255        if (pacing != -1)
 256                addattr_l(n, 1024, TCA_FQ_RATE_ENABLE,
 257                          &pacing, sizeof(pacing));
 258        if (set_maxrate)
 259                addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE,
 260                          &maxrate, sizeof(maxrate));
 261        if (set_low_rate_threshold)
 262                addattr_l(n, 1024, TCA_FQ_LOW_RATE_THRESHOLD,
 263                          &low_rate_threshold, sizeof(low_rate_threshold));
 264        if (set_defrate)
 265                addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE,
 266                          &defrate, sizeof(defrate));
 267        if (set_refill_delay)
 268                addattr_l(n, 1024, TCA_FQ_FLOW_REFILL_DELAY,
 269                          &refill_delay, sizeof(refill_delay));
 270        if (set_orphan_mask)
 271                addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
 272                          &orphan_mask, sizeof(orphan_mask));
 273        if (set_ce_threshold)
 274                addattr_l(n, 1024, TCA_FQ_CE_THRESHOLD,
 275                          &ce_threshold, sizeof(ce_threshold));
 276    if (set_timer_slack)
 277                addattr_l(n, 1024, TCA_FQ_TIMER_SLACK,
 278                          &timer_slack, sizeof(timer_slack));
 279    if (set_horizon)
 280                addattr_l(n, 1024, TCA_FQ_HORIZON,
 281                          &horizon, sizeof(horizon));
 282    if (horizon_drop != 255)
 283                addattr_l(n, 1024, TCA_FQ_HORIZON_DROP,
 284                          &horizon_drop, sizeof(horizon_drop));
 285        addattr_nest_end(n, tail);
 286        return 0;
 287}
 288
 289static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 290{
 291        struct rtattr *tb[TCA_FQ_MAX + 1];
 292        unsigned int plimit, flow_plimit;
 293        unsigned int buckets_log;
 294        int pacing;
 295        unsigned int rate, quantum;
 296        unsigned int refill_delay;
 297        unsigned int orphan_mask;
 298        unsigned int ce_threshold;
 299        unsigned int timer_slack;
 300        unsigned int horizon;
 301        __u8 horizon_drop;
 302
 303        SPRINT_BUF(b1);
 304
 305        if (opt == NULL)
 306                return 0;
 307
 308        parse_rtattr_nested(tb, TCA_FQ_MAX, opt);
 309
 310        if (tb[TCA_FQ_PLIMIT] &&
 311            RTA_PAYLOAD(tb[TCA_FQ_PLIMIT]) >= sizeof(__u32)) {
 312                plimit = rta_getattr_u32(tb[TCA_FQ_PLIMIT]);
 313                print_uint(PRINT_ANY, "limit", "limit %up ", plimit);
 314        }
 315        if (tb[TCA_FQ_FLOW_PLIMIT] &&
 316            RTA_PAYLOAD(tb[TCA_FQ_FLOW_PLIMIT]) >= sizeof(__u32)) {
 317                flow_plimit = rta_getattr_u32(tb[TCA_FQ_FLOW_PLIMIT]);
 318                print_uint(PRINT_ANY, "flow_limit", "flow_limit %up ",
 319                           flow_plimit);
 320        }
 321        if (tb[TCA_FQ_BUCKETS_LOG] &&
 322            RTA_PAYLOAD(tb[TCA_FQ_BUCKETS_LOG]) >= sizeof(__u32)) {
 323                buckets_log = rta_getattr_u32(tb[TCA_FQ_BUCKETS_LOG]);
 324                print_uint(PRINT_ANY, "buckets", "buckets %u ",
 325                           1U << buckets_log);
 326        }
 327        if (tb[TCA_FQ_ORPHAN_MASK] &&
 328            RTA_PAYLOAD(tb[TCA_FQ_ORPHAN_MASK]) >= sizeof(__u32)) {
 329                orphan_mask = rta_getattr_u32(tb[TCA_FQ_ORPHAN_MASK]);
 330                print_uint(PRINT_ANY, "orphan_mask", "orphan_mask %u ",
 331                           orphan_mask);
 332        }
 333        if (tb[TCA_FQ_RATE_ENABLE] &&
 334            RTA_PAYLOAD(tb[TCA_FQ_RATE_ENABLE]) >= sizeof(int)) {
 335                pacing = rta_getattr_u32(tb[TCA_FQ_RATE_ENABLE]);
 336                if (pacing == 0)
 337                        print_bool(PRINT_ANY, "pacing", "nopacing ", false);
 338        }
 339        if (tb[TCA_FQ_QUANTUM] &&
 340            RTA_PAYLOAD(tb[TCA_FQ_QUANTUM]) >= sizeof(__u32)) {
 341                quantum = rta_getattr_u32(tb[TCA_FQ_QUANTUM]);
 342                print_size(PRINT_ANY, "quantum", "quantum %s ", quantum);
 343        }
 344        if (tb[TCA_FQ_INITIAL_QUANTUM] &&
 345            RTA_PAYLOAD(tb[TCA_FQ_INITIAL_QUANTUM]) >= sizeof(__u32)) {
 346                quantum = rta_getattr_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
 347                print_size(PRINT_ANY, "initial_quantum", "initial_quantum %s ",
 348                           quantum);
 349        }
 350        if (tb[TCA_FQ_FLOW_MAX_RATE] &&
 351            RTA_PAYLOAD(tb[TCA_FQ_FLOW_MAX_RATE]) >= sizeof(__u32)) {
 352                rate = rta_getattr_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
 353
 354                if (rate != ~0U)
 355                        tc_print_rate(PRINT_ANY,
 356                                      "maxrate", "maxrate %s ", rate);
 357        }
 358        if (tb[TCA_FQ_FLOW_DEFAULT_RATE] &&
 359            RTA_PAYLOAD(tb[TCA_FQ_FLOW_DEFAULT_RATE]) >= sizeof(__u32)) {
 360                rate = rta_getattr_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]);
 361
 362                if (rate != 0)
 363                        tc_print_rate(PRINT_ANY,
 364                                      "defrate", "defrate %s ", rate);
 365        }
 366        if (tb[TCA_FQ_LOW_RATE_THRESHOLD] &&
 367            RTA_PAYLOAD(tb[TCA_FQ_LOW_RATE_THRESHOLD]) >= sizeof(__u32)) {
 368                rate = rta_getattr_u32(tb[TCA_FQ_LOW_RATE_THRESHOLD]);
 369
 370                if (rate != 0)
 371                        tc_print_rate(PRINT_ANY, "low_rate_threshold",
 372                                      "low_rate_threshold %s ", rate);
 373        }
 374        if (tb[TCA_FQ_FLOW_REFILL_DELAY] &&
 375            RTA_PAYLOAD(tb[TCA_FQ_FLOW_REFILL_DELAY]) >= sizeof(__u32)) {
 376                refill_delay = rta_getattr_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]);
 377                print_uint(PRINT_JSON, "refill_delay", NULL, refill_delay);
 378                print_string(PRINT_FP, NULL, "refill_delay %s ",
 379                             sprint_time(refill_delay, b1));
 380        }
 381
 382        if (tb[TCA_FQ_CE_THRESHOLD] &&
 383            RTA_PAYLOAD(tb[TCA_FQ_CE_THRESHOLD]) >= sizeof(__u32)) {
 384                ce_threshold = rta_getattr_u32(tb[TCA_FQ_CE_THRESHOLD]);
 385                if (ce_threshold != ~0U) {
 386                        print_uint(PRINT_JSON, "ce_threshold", NULL,
 387                                   ce_threshold);
 388                        print_string(PRINT_FP, NULL, "ce_threshold %s ",
 389                                     sprint_time(ce_threshold, b1));
 390                }
 391        }
 392
 393        if (tb[TCA_FQ_TIMER_SLACK] &&
 394            RTA_PAYLOAD(tb[TCA_FQ_TIMER_SLACK]) >= sizeof(__u32)) {
 395                timer_slack = rta_getattr_u32(tb[TCA_FQ_TIMER_SLACK]);
 396                print_uint(PRINT_JSON, "timer_slack", NULL, timer_slack);
 397                print_string(PRINT_FP, NULL, "timer_slack %s ",
 398                             sprint_time64(timer_slack, b1));
 399        }
 400
 401        if (tb[TCA_FQ_HORIZON] &&
 402            RTA_PAYLOAD(tb[TCA_FQ_HORIZON]) >= sizeof(__u32)) {
 403                horizon = rta_getattr_u32(tb[TCA_FQ_HORIZON]);
 404                print_uint(PRINT_JSON, "horizon", NULL, horizon);
 405                print_string(PRINT_FP, NULL, "horizon %s ",
 406                             sprint_time(horizon, b1));
 407        }
 408
 409        if (tb[TCA_FQ_HORIZON_DROP] &&
 410            RTA_PAYLOAD(tb[TCA_FQ_HORIZON_DROP]) >= sizeof(__u8)) {
 411                horizon_drop = rta_getattr_u8(tb[TCA_FQ_HORIZON_DROP]);
 412                if (!horizon_drop)
 413                        print_null(PRINT_ANY, "horizon_cap", "horizon_cap ", NULL);
 414                else
 415                        print_null(PRINT_ANY, "horizon_drop", "horizon_drop ", NULL);
 416        }
 417
 418        return 0;
 419}
 420
 421static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
 422                           struct rtattr *xstats)
 423{
 424        struct tc_fq_qd_stats *st, _st;
 425
 426        SPRINT_BUF(b1);
 427
 428        if (xstats == NULL)
 429                return 0;
 430
 431        memset(&_st, 0, sizeof(_st));
 432        memcpy(&_st, RTA_DATA(xstats), min(RTA_PAYLOAD(xstats), sizeof(*st)));
 433
 434        st = &_st;
 435
 436        print_uint(PRINT_ANY, "flows", "  flows %u", st->flows);
 437        print_uint(PRINT_ANY, "inactive", " (inactive %u", st->inactive_flows);
 438        print_uint(PRINT_ANY, "throttled", " throttled %u)",
 439                   st->throttled_flows);
 440
 441        if (st->time_next_delayed_flow > 0) {
 442                print_lluint(PRINT_JSON, "next_packet_delay", NULL,
 443                             st->time_next_delayed_flow);
 444                print_string(PRINT_FP, NULL, " next_packet_delay %s",
 445                             sprint_time64(st->time_next_delayed_flow, b1));
 446        }
 447
 448        print_nl();
 449        print_lluint(PRINT_ANY, "gc", "  gc %llu", st->gc_flows);
 450        print_lluint(PRINT_ANY, "highprio", " highprio %llu",
 451                     st->highprio_packets);
 452
 453        if (st->tcp_retrans)
 454                print_lluint(PRINT_ANY, "retrans", " retrans %llu",
 455                             st->tcp_retrans);
 456
 457        print_lluint(PRINT_ANY, "throttled", " throttled %llu", st->throttled);
 458
 459        if (st->unthrottle_latency_ns) {
 460                print_uint(PRINT_JSON, "latency", NULL,
 461                           st->unthrottle_latency_ns);
 462                print_string(PRINT_FP, NULL, " latency %s",
 463                             sprint_time64(st->unthrottle_latency_ns, b1));
 464        }
 465
 466        if (st->ce_mark)
 467                print_lluint(PRINT_ANY, "ce_mark", " ce_mark %llu",
 468                             st->ce_mark);
 469
 470        if (st->flows_plimit)
 471                print_lluint(PRINT_ANY, "flows_plimit", " flows_plimit %llu",
 472                             st->flows_plimit);
 473
 474        if (st->pkts_too_long || st->allocation_errors ||
 475            st->horizon_drops || st->horizon_caps) {
 476                print_nl();
 477                if (st->pkts_too_long)
 478                        print_lluint(PRINT_ANY, "pkts_too_long",
 479                                     " pkts_too_long %llu",
 480                                     st->pkts_too_long);
 481                if (st->allocation_errors)
 482                        print_lluint(PRINT_ANY, "alloc_errors",
 483                                     " alloc_errors %llu",
 484                                     st->allocation_errors);
 485                if (st->horizon_drops)
 486                        print_lluint(PRINT_ANY, "horizon_drops",
 487                                     " horizon_drops %llu",
 488                                     st->horizon_drops);
 489                if (st->horizon_caps)
 490                        print_lluint(PRINT_ANY, "horizon_caps",
 491                                     "  horizon_caps %llu",
 492                                     st->horizon_caps);
 493        }
 494
 495        return 0;
 496}
 497
 498struct qdisc_util fq_qdisc_util = {
 499        .id             = "fq",
 500        .parse_qopt     = fq_parse_opt,
 501        .print_qopt     = fq_print_opt,
 502        .print_xstats   = fq_print_xstats,
 503};
 504