iproute2/tc/q_red.c
<<
>>
Prefs
   1/*
   2 * q_red.c              RED.
   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:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  10 *
  11 */
  12
  13#include <stdio.h>
  14#include <stdlib.h>
  15#include <unistd.h>
  16#include <fcntl.h>
  17#include <sys/socket.h>
  18#include <netinet/in.h>
  19#include <arpa/inet.h>
  20#include <string.h>
  21#include <math.h>
  22
  23#include "utils.h"
  24#include "tc_util.h"
  25
  26#include "tc_red.h"
  27
  28static void explain(void)
  29{
  30        fprintf(stderr,
  31                "Usage: ... red limit BYTES [min BYTES] [max BYTES] avpkt BYTES [burst PACKETS]\n"
  32                "               [adaptive] [probability PROBABILITY] [bandwidth KBPS]\n"
  33                "               [ecn] [harddrop] [nodrop]\n");
  34}
  35
  36#define RED_SUPPORTED_FLAGS (TC_RED_HISTORIC_FLAGS | TC_RED_NODROP)
  37
  38static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv,
  39                         struct nlmsghdr *n, const char *dev)
  40{
  41        struct nla_bitfield32 flags_bf = {
  42                .selector = RED_SUPPORTED_FLAGS,
  43        };
  44        struct tc_red_qopt opt = {};
  45        unsigned int burst = 0;
  46        unsigned int avpkt = 0;
  47        double probability = 0.02;
  48        unsigned int rate = 0;
  49        int parm;
  50        __u8 sbuf[256];
  51        __u32 max_P;
  52        struct rtattr *tail;
  53
  54        while (argc > 0) {
  55                if (strcmp(*argv, "limit") == 0) {
  56                        NEXT_ARG();
  57                        if (get_size(&opt.limit, *argv)) {
  58                                fprintf(stderr, "Illegal \"limit\"\n");
  59                                return -1;
  60                        }
  61                } else if (strcmp(*argv, "min") == 0) {
  62                        NEXT_ARG();
  63                        if (get_size(&opt.qth_min, *argv)) {
  64                                fprintf(stderr, "Illegal \"min\"\n");
  65                                return -1;
  66                        }
  67                } else if (strcmp(*argv, "max") == 0) {
  68                        NEXT_ARG();
  69                        if (get_size(&opt.qth_max, *argv)) {
  70                                fprintf(stderr, "Illegal \"max\"\n");
  71                                return -1;
  72                        }
  73                } else if (strcmp(*argv, "burst") == 0) {
  74                        NEXT_ARG();
  75                        if (get_unsigned(&burst, *argv, 0)) {
  76                                fprintf(stderr, "Illegal \"burst\"\n");
  77                                return -1;
  78                        }
  79                } else if (strcmp(*argv, "avpkt") == 0) {
  80                        NEXT_ARG();
  81                        if (get_size(&avpkt, *argv)) {
  82                                fprintf(stderr, "Illegal \"avpkt\"\n");
  83                                return -1;
  84                        }
  85                } else if (strcmp(*argv, "probability") == 0) {
  86                        NEXT_ARG();
  87                        if (sscanf(*argv, "%lg", &probability) != 1) {
  88                                fprintf(stderr, "Illegal \"probability\"\n");
  89                                return -1;
  90                        }
  91                } else if (strcmp(*argv, "bandwidth") == 0) {
  92                        NEXT_ARG();
  93                        if (strchr(*argv, '%')) {
  94                                if (get_percent_rate(&rate, *argv, dev)) {
  95                                        fprintf(stderr, "Illegal \"bandwidth\"\n");
  96                                        return -1;
  97                                }
  98                        } else if (get_rate(&rate, *argv)) {
  99                                fprintf(stderr, "Illegal \"bandwidth\"\n");
 100                                return -1;
 101                        }
 102                } else if (strcmp(*argv, "ecn") == 0) {
 103                        flags_bf.value |= TC_RED_ECN;
 104                } else if (strcmp(*argv, "harddrop") == 0) {
 105                        flags_bf.value |= TC_RED_HARDDROP;
 106                } else if (strcmp(*argv, "nodrop") == 0) {
 107                        flags_bf.value |= TC_RED_NODROP;
 108                } else if (strcmp(*argv, "adaptative") == 0) {
 109                        flags_bf.value |= TC_RED_ADAPTATIVE;
 110                } else if (strcmp(*argv, "adaptive") == 0) {
 111                        flags_bf.value |= TC_RED_ADAPTATIVE;
 112                } else if (strcmp(*argv, "help") == 0) {
 113                        explain();
 114                        return -1;
 115                } else {
 116                        fprintf(stderr, "What is \"%s\"?\n", *argv);
 117                        explain();
 118                        return -1;
 119                }
 120                argc--; argv++;
 121        }
 122
 123        if (!opt.limit || !avpkt) {
 124                fprintf(stderr, "RED: Required parameter (limit, avpkt) is missing\n");
 125                return -1;
 126        }
 127        /* Compute default min/max thresholds based on
 128         * Sally Floyd's recommendations:
 129         * http://www.icir.org/floyd/REDparameters.txt
 130         */
 131        if (!opt.qth_max)
 132                opt.qth_max = opt.qth_min ? opt.qth_min * 3 : opt.limit / 4;
 133        if (!opt.qth_min)
 134                opt.qth_min = opt.qth_max / 3;
 135        if (!burst)
 136                burst = (2 * opt.qth_min + opt.qth_max) / (3 * avpkt);
 137        if (!rate) {
 138                get_rate(&rate, "10Mbit");
 139                fprintf(stderr, "RED: set bandwidth to 10Mbit\n");
 140        }
 141        if ((parm = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) {
 142                fprintf(stderr, "RED: failed to calculate EWMA constant.\n");
 143                return -1;
 144        }
 145        if (parm >= 10)
 146                fprintf(stderr, "RED: WARNING. Burst %u seems to be too large.\n", burst);
 147        opt.Wlog = parm;
 148        if ((parm = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) {
 149                fprintf(stderr, "RED: failed to calculate probability.\n");
 150                return -1;
 151        }
 152        opt.Plog = parm;
 153        if ((parm = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) {
 154                fprintf(stderr, "RED: failed to calculate idle damping table.\n");
 155                return -1;
 156        }
 157        opt.Scell_log = parm;
 158
 159        tail = addattr_nest(n, 1024, TCA_OPTIONS);
 160        addattr_l(n, 1024, TCA_RED_PARMS, &opt, sizeof(opt));
 161        addattr_l(n, 1024, TCA_RED_STAB, sbuf, 256);
 162        max_P = probability * pow(2, 32);
 163        addattr_l(n, 1024, TCA_RED_MAX_P, &max_P, sizeof(max_P));
 164        addattr_l(n, 1024, TCA_RED_FLAGS, &flags_bf, sizeof(flags_bf));
 165        addattr_nest_end(n, tail);
 166        return 0;
 167}
 168
 169static int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 170{
 171        struct rtattr *tb[TCA_RED_MAX + 1];
 172        struct nla_bitfield32 *flags_bf;
 173        struct tc_red_qopt *qopt;
 174        __u32 max_P = 0;
 175
 176        SPRINT_BUF(b1);
 177        SPRINT_BUF(b2);
 178        SPRINT_BUF(b3);
 179
 180        if (opt == NULL)
 181                return 0;
 182
 183        parse_rtattr_nested(tb, TCA_RED_MAX, opt);
 184
 185        if (tb[TCA_RED_PARMS] == NULL)
 186                return -1;
 187        qopt = RTA_DATA(tb[TCA_RED_PARMS]);
 188        if (RTA_PAYLOAD(tb[TCA_RED_PARMS])  < sizeof(*qopt))
 189                return -1;
 190
 191        if (tb[TCA_RED_MAX_P] &&
 192            RTA_PAYLOAD(tb[TCA_RED_MAX_P]) >= sizeof(__u32))
 193                max_P = rta_getattr_u32(tb[TCA_RED_MAX_P]);
 194
 195        if (tb[TCA_RED_FLAGS] &&
 196            RTA_PAYLOAD(tb[TCA_RED_FLAGS]) >= sizeof(*flags_bf)) {
 197                flags_bf = RTA_DATA(tb[TCA_RED_FLAGS]);
 198                qopt->flags = flags_bf->value;
 199        }
 200
 201        print_uint(PRINT_JSON, "limit", NULL, qopt->limit);
 202        print_string(PRINT_FP, NULL, "limit %s ", sprint_size(qopt->limit, b1));
 203        print_uint(PRINT_JSON, "min", NULL, qopt->qth_min);
 204        print_string(PRINT_FP, NULL, "min %s ", sprint_size(qopt->qth_min, b2));
 205        print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
 206        print_string(PRINT_FP, NULL, "max %s ", sprint_size(qopt->qth_max, b3));
 207
 208        tc_red_print_flags(qopt->flags);
 209
 210        if (show_details) {
 211                print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
 212                if (max_P)
 213                        print_float(PRINT_ANY, "probability",
 214                                    "probability %lg ", max_P / pow(2, 32));
 215                else
 216                        print_uint(PRINT_ANY, "Plog", "Plog %u ", qopt->Plog);
 217                print_uint(PRINT_ANY, "Scell_log", "Scell_log %u",
 218                           qopt->Scell_log);
 219        }
 220        return 0;
 221}
 222
 223static int red_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
 224{
 225#ifdef TC_RED_ECN
 226        struct tc_red_xstats *st;
 227
 228        if (xstats == NULL)
 229                return 0;
 230
 231        if (RTA_PAYLOAD(xstats) < sizeof(*st))
 232                return -1;
 233
 234        st = RTA_DATA(xstats);
 235        print_uint(PRINT_ANY, "marked", "  marked %u ", st->marked);
 236        print_uint(PRINT_ANY, "early", "early %u ", st->early);
 237        print_uint(PRINT_ANY, "pdrop", "pdrop %u ", st->pdrop);
 238        print_uint(PRINT_ANY, "other", "other %u ", st->other);
 239#endif
 240        return 0;
 241}
 242
 243
 244struct qdisc_util red_qdisc_util = {
 245        .id             = "red",
 246        .parse_qopt     = red_parse_opt,
 247        .print_qopt     = red_print_opt,
 248        .print_xstats   = red_print_xstats,
 249};
 250