iproute2/tc/q_choke.c
<<
>>
Prefs
   1/*
   2 * q_choke.c            CHOKE.
   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 * Authors:     Stephen Hemminger <shemminger@vyatta.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#include <math.h>
  21
  22#include "utils.h"
  23#include "tc_util.h"
  24
  25#include "tc_red.h"
  26
  27static void explain(void)
  28{
  29        fprintf(stderr,
  30                "Usage: ... choke limit PACKETS bandwidth KBPS [ecn]\n"
  31                "                [ min PACKETS ] [ max PACKETS ] [ burst PACKETS ]\n");
  32}
  33
  34static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv,
  35                           struct nlmsghdr *n, const char *dev)
  36{
  37        struct tc_red_qopt opt = {};
  38        unsigned int burst = 0;
  39        unsigned int avpkt = 1000;
  40        double probability = 0.02;
  41        unsigned int rate = 0;
  42        int ecn_ok = 0;
  43        int wlog;
  44        __u8 sbuf[256];
  45        __u32 max_P;
  46        struct rtattr *tail;
  47
  48        while (argc > 0) {
  49                if (strcmp(*argv, "limit") == 0) {
  50                        NEXT_ARG();
  51                        if (get_unsigned(&opt.limit, *argv, 0)) {
  52                                fprintf(stderr, "Illegal \"limit\"\n");
  53                                return -1;
  54                        }
  55                } else if (strcmp(*argv, "bandwidth") == 0) {
  56                        NEXT_ARG();
  57                        if (strchr(*argv, '%')) {
  58                                if (get_percent_rate(&rate, *argv, dev)) {
  59                                        fprintf(stderr, "Illegal \"bandwidth\"\n");
  60                                        return -1;
  61                                }
  62                        } else if (get_rate(&rate, *argv)) {
  63                                fprintf(stderr, "Illegal \"bandwidth\"\n");
  64                                return -1;
  65                        }
  66                } else if (strcmp(*argv, "ecn") == 0) {
  67                        ecn_ok = 1;
  68                } else if (strcmp(*argv, "min") == 0) {
  69                        NEXT_ARG();
  70                        if (get_unsigned(&opt.qth_min, *argv, 0)) {
  71                                fprintf(stderr, "Illegal \"min\"\n");
  72                                return -1;
  73                        }
  74                } else if (strcmp(*argv, "max") == 0) {
  75                        NEXT_ARG();
  76                        if (get_unsigned(&opt.qth_max, *argv, 0)) {
  77                                fprintf(stderr, "Illegal \"max\"\n");
  78                                return -1;
  79                        }
  80                } else if (strcmp(*argv, "burst") == 0) {
  81                        NEXT_ARG();
  82                        if (get_unsigned(&burst, *argv, 0)) {
  83                                fprintf(stderr, "Illegal \"burst\"\n");
  84                                return -1;
  85                        }
  86                } else if (strcmp(*argv, "avpkt") == 0) {
  87                        NEXT_ARG();
  88                        if (get_size(&avpkt, *argv)) {
  89                                fprintf(stderr, "Illegal \"avpkt\"\n");
  90                                return -1;
  91                        }
  92                } else if (strcmp(*argv, "probability") == 0) {
  93                        NEXT_ARG();
  94                        if (sscanf(*argv, "%lg", &probability) != 1) {
  95                                fprintf(stderr, "Illegal \"probability\"\n");
  96                                return -1;
  97                        }
  98                } else if (strcmp(*argv, "help") == 0) {
  99                        explain();
 100                        return -1;
 101                } else {
 102                        fprintf(stderr, "What is \"%s\"?\n", *argv);
 103                        explain();
 104                        return -1;
 105                }
 106                argc--; argv++;
 107        }
 108
 109        if (!rate || !opt.limit) {
 110                fprintf(stderr, "Required parameter (bandwidth, limit) is missing\n");
 111                return -1;
 112        }
 113
 114        /* Compute default min/max thresholds based on
 115           Sally Floyd's recommendations:
 116           http://www.icir.org/floyd/REDparameters.txt
 117        */
 118        if (!opt.qth_max)
 119                opt.qth_max = opt.limit / 4;
 120        if (!opt.qth_min)
 121                opt.qth_min = opt.qth_max / 3;
 122        if (!burst)
 123                burst = (2 * opt.qth_min + opt.qth_max) / 3;
 124
 125        if (opt.qth_max > opt.limit) {
 126                fprintf(stderr, "\"max\" is larger than \"limit\"\n");
 127                return -1;
 128        }
 129
 130        if (opt.qth_min >= opt.qth_max) {
 131                fprintf(stderr, "\"min\" is not smaller than \"max\"\n");
 132                return -1;
 133        }
 134
 135        wlog = tc_red_eval_ewma(opt.qth_min*avpkt, burst, avpkt);
 136        if (wlog < 0) {
 137                fprintf(stderr, "CHOKE: failed to calculate EWMA constant.\n");
 138                return -1;
 139        }
 140        if (wlog >= 10)
 141                fprintf(stderr, "CHOKE: WARNING. Burst %d seems to be too large.\n", burst);
 142        opt.Wlog = wlog;
 143
 144        wlog = tc_red_eval_P(opt.qth_min*avpkt, opt.qth_max*avpkt, probability);
 145        if (wlog < 0) {
 146                fprintf(stderr, "CHOKE: failed to calculate probability.\n");
 147                return -1;
 148        }
 149        opt.Plog = wlog;
 150
 151        wlog = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf);
 152        if (wlog < 0) {
 153                fprintf(stderr, "CHOKE: failed to calculate idle damping table.\n");
 154                return -1;
 155        }
 156        opt.Scell_log = wlog;
 157        if (ecn_ok)
 158                opt.flags |= TC_RED_ECN;
 159
 160        tail = addattr_nest(n, 1024, TCA_OPTIONS);
 161        addattr_l(n, 1024, TCA_CHOKE_PARMS, &opt, sizeof(opt));
 162        addattr_l(n, 1024, TCA_CHOKE_STAB, sbuf, 256);
 163        max_P = probability * pow(2, 32);
 164        addattr_l(n, 1024, TCA_CHOKE_MAX_P, &max_P, sizeof(max_P));
 165        addattr_nest_end(n, tail);
 166        return 0;
 167}
 168
 169static int choke_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 170{
 171        struct rtattr *tb[TCA_CHOKE_MAX+1];
 172        const struct tc_red_qopt *qopt;
 173        __u32 max_P = 0;
 174
 175        if (opt == NULL)
 176                return 0;
 177
 178        parse_rtattr_nested(tb, TCA_CHOKE_MAX, opt);
 179
 180        if (tb[TCA_CHOKE_PARMS] == NULL)
 181                return -1;
 182        qopt = RTA_DATA(tb[TCA_CHOKE_PARMS]);
 183        if (RTA_PAYLOAD(tb[TCA_CHOKE_PARMS])  < sizeof(*qopt))
 184                return -1;
 185        if (tb[TCA_CHOKE_MAX_P] &&
 186            RTA_PAYLOAD(tb[TCA_CHOKE_MAX_P]) >= sizeof(__u32))
 187                max_P = rta_getattr_u32(tb[TCA_CHOKE_MAX_P]);
 188
 189        print_uint(PRINT_ANY, "limit", "limit %up ", qopt->limit);
 190        print_uint(PRINT_ANY, "min", "min %up ", qopt->qth_min);
 191        print_uint(PRINT_ANY, "max", "max %up ", qopt->qth_max);
 192
 193        tc_red_print_flags(qopt->flags);
 194
 195        if (show_details) {
 196                print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
 197
 198                if (max_P)
 199                        print_float(PRINT_ANY, "probability",
 200                                    "probability %lg ", max_P / pow(2, 32));
 201                else
 202                        print_uint(PRINT_ANY, "Plog", "Plog %u ", qopt->Plog);
 203
 204                print_uint(PRINT_ANY, "Scell_log", "Scell_log %u",
 205                           qopt->Scell_log);
 206        }
 207        return 0;
 208}
 209
 210static int choke_print_xstats(struct qdisc_util *qu, FILE *f,
 211                              struct rtattr *xstats)
 212{
 213        struct tc_choke_xstats *st;
 214
 215        if (xstats == NULL)
 216                return 0;
 217
 218        if (RTA_PAYLOAD(xstats) < sizeof(*st))
 219                return -1;
 220
 221        st = RTA_DATA(xstats);
 222
 223        print_uint(PRINT_ANY, "marked", "  marked %u", st->marked);
 224        print_uint(PRINT_ANY, "early", " early %u", st->early);
 225        print_uint(PRINT_ANY, "pdrop", " pdrop %u", st->pdrop);
 226        print_uint(PRINT_ANY, "other", " other %u", st->other);
 227        print_uint(PRINT_ANY, "matched", " matched %u", st->matched);
 228
 229        return 0;
 230
 231}
 232
 233struct qdisc_util choke_qdisc_util = {
 234        .id             = "choke",
 235        .parse_qopt     = choke_parse_opt,
 236        .print_qopt     = choke_print_opt,
 237        .print_xstats   = choke_print_xstats,
 238};
 239