iproute2/tc/q_sfq.c
<<
>>
Prefs
   1/*
   2 * q_sfq.c              SFQ.
   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#include "tc_red.h"
  26
  27static void explain(void)
  28{
  29        fprintf(stderr,
  30                "Usage: ... sfq [ limit NUMBER ] [ perturb SECS ] [ quantum BYTES ]\n"
  31                "               [ divisor NUMBER ] [ flows NUMBER] [ depth NUMBER ]\n"
  32                "               [ headdrop ]\n"
  33                "               [ redflowlimit BYTES ] [ min BYTES ] [ max BYTES ]\n"
  34                "               [ avpkt BYTES ] [ burst PACKETS ] [ probability P ]\n"
  35                "               [ ecn ] [ harddrop ]\n");
  36}
  37
  38static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
  39{
  40        int ok = 0, red = 0;
  41        struct tc_sfq_qopt_v1 opt = {};
  42        unsigned int burst = 0;
  43        int wlog;
  44        unsigned int avpkt = 1000;
  45        double probability = 0.02;
  46
  47        while (argc > 0) {
  48                if (strcmp(*argv, "quantum") == 0) {
  49                        NEXT_ARG();
  50                        if (get_size(&opt.v0.quantum, *argv)) {
  51                                fprintf(stderr, "Illegal \"limit\"\n");
  52                                return -1;
  53                        }
  54                        ok++;
  55                } else if (strcmp(*argv, "perturb") == 0) {
  56                        NEXT_ARG();
  57                        if (get_integer(&opt.v0.perturb_period, *argv, 0)) {
  58                                fprintf(stderr, "Illegal \"perturb\"\n");
  59                                return -1;
  60                        }
  61                        ok++;
  62                } else if (strcmp(*argv, "limit") == 0) {
  63                        NEXT_ARG();
  64                        if (get_u32(&opt.v0.limit, *argv, 0)) {
  65                                fprintf(stderr, "Illegal \"limit\"\n");
  66                                return -1;
  67                        }
  68                        if (opt.v0.limit < 2) {
  69                                fprintf(stderr, "Illegal \"limit\", must be > 1\n");
  70                                return -1;
  71                        }
  72                        ok++;
  73                } else if (strcmp(*argv, "divisor") == 0) {
  74                        NEXT_ARG();
  75                        if (get_u32(&opt.v0.divisor, *argv, 0)) {
  76                                fprintf(stderr, "Illegal \"divisor\"\n");
  77                                return -1;
  78                        }
  79                        ok++;
  80                } else if (strcmp(*argv, "flows") == 0) {
  81                        NEXT_ARG();
  82                        if (get_u32(&opt.v0.flows, *argv, 0)) {
  83                                fprintf(stderr, "Illegal \"flows\"\n");
  84                                return -1;
  85                        }
  86                        ok++;
  87                } else if (strcmp(*argv, "depth") == 0) {
  88                        NEXT_ARG();
  89                        if (get_u32(&opt.depth, *argv, 0)) {
  90                                fprintf(stderr, "Illegal \"flows\"\n");
  91                                return -1;
  92                        }
  93                        ok++;
  94                } else if (strcmp(*argv, "headdrop") == 0) {
  95                        opt.headdrop = 1;
  96                        ok++;
  97                } else if (strcmp(*argv, "redflowlimit") == 0) {
  98                        NEXT_ARG();
  99                        if (get_u32(&opt.limit, *argv, 0)) {
 100                                fprintf(stderr, "Illegal \"redflowlimit\"\n");
 101                                return -1;
 102                        }
 103                        red++;
 104                } else if (strcmp(*argv, "min") == 0) {
 105                        NEXT_ARG();
 106                        if (get_u32(&opt.qth_min, *argv, 0)) {
 107                                fprintf(stderr, "Illegal \"min\"\n");
 108                                return -1;
 109                        }
 110                        red++;
 111                } else if (strcmp(*argv, "max") == 0) {
 112                        NEXT_ARG();
 113                        if (get_u32(&opt.qth_max, *argv, 0)) {
 114                                fprintf(stderr, "Illegal \"max\"\n");
 115                                return -1;
 116                        }
 117                        red++;
 118                } else if (strcmp(*argv, "burst") == 0) {
 119                        NEXT_ARG();
 120                        if (get_unsigned(&burst, *argv, 0)) {
 121                                fprintf(stderr, "Illegal \"burst\"\n");
 122                                return -1;
 123                        }
 124                        red++;
 125                } else if (strcmp(*argv, "avpkt") == 0) {
 126                        NEXT_ARG();
 127                        if (get_size(&avpkt, *argv)) {
 128                                fprintf(stderr, "Illegal \"avpkt\"\n");
 129                                return -1;
 130                        }
 131                        red++;
 132                } else if (strcmp(*argv, "probability") == 0) {
 133                        NEXT_ARG();
 134                        if (sscanf(*argv, "%lg", &probability) != 1) {
 135                                fprintf(stderr, "Illegal \"probability\"\n");
 136                                return -1;
 137                        }
 138                        red++;
 139                } else if (strcmp(*argv, "ecn") == 0) {
 140                        opt.flags |= TC_RED_ECN;
 141                        red++;
 142                } else if (strcmp(*argv, "harddrop") == 0) {
 143                        opt.flags |= TC_RED_HARDDROP;
 144                        red++;
 145                } else if (strcmp(*argv, "help") == 0) {
 146                        explain();
 147                        return -1;
 148                } else {
 149                        fprintf(stderr, "What is \"%s\"?\n", *argv);
 150                        explain();
 151                        return -1;
 152                }
 153                argc--; argv++;
 154        }
 155        if (red) {
 156                if (!opt.limit) {
 157                        fprintf(stderr, "Required parameter (redflowlimit) is missing\n");
 158                        return -1;
 159                }
 160                /* Compute default min/max thresholds based on
 161                   Sally Floyd's recommendations:
 162                   http://www.icir.org/floyd/REDparameters.txt
 163                */
 164                if (!opt.qth_max)
 165                        opt.qth_max = opt.limit / 4;
 166                if (!opt.qth_min)
 167                        opt.qth_min = opt.qth_max / 3;
 168                if (!burst)
 169                        burst = (2 * opt.qth_min + opt.qth_max) / (3 * avpkt);
 170
 171                if (opt.qth_max > opt.limit) {
 172                        fprintf(stderr, "\"max\" is larger than \"limit\"\n");
 173                        return -1;
 174                }
 175
 176                if (opt.qth_min >= opt.qth_max) {
 177                        fprintf(stderr, "\"min\" is not smaller than \"max\"\n");
 178                        return -1;
 179                }
 180
 181                wlog = tc_red_eval_ewma(opt.qth_min, burst, avpkt);
 182                if (wlog < 0) {
 183                        fprintf(stderr, "SFQ: failed to calculate EWMA constant.\n");
 184                        return -1;
 185                }
 186                if (wlog >= 10)
 187                        fprintf(stderr, "SFQ: WARNING. Burst %u seems to be too large.\n", burst);
 188                opt.Wlog = wlog;
 189
 190                wlog = tc_red_eval_P(opt.qth_min, opt.qth_max, probability);
 191                if (wlog < 0) {
 192                        fprintf(stderr, "SFQ: failed to calculate probability.\n");
 193                        return -1;
 194                }
 195                opt.Plog = wlog;
 196                opt.max_P = probability * pow(2, 32);
 197        }
 198
 199        if (ok || red)
 200                addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
 201        return 0;
 202}
 203
 204static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 205{
 206        struct tc_sfq_qopt *qopt;
 207        struct tc_sfq_qopt_v1 *qopt_ext = NULL;
 208
 209        SPRINT_BUF(b1);
 210        SPRINT_BUF(b2);
 211        SPRINT_BUF(b3);
 212        if (opt == NULL)
 213                return 0;
 214
 215        if (RTA_PAYLOAD(opt)  < sizeof(*qopt))
 216                return -1;
 217        if (RTA_PAYLOAD(opt) >= sizeof(*qopt_ext))
 218                qopt_ext = RTA_DATA(opt);
 219        qopt = RTA_DATA(opt);
 220
 221        print_uint(PRINT_ANY, "limit", "limit %up ", qopt->limit);
 222        print_uint(PRINT_JSON, "quantum", NULL, qopt->quantum);
 223        print_string(PRINT_FP, NULL, "quantum %s ",
 224                     sprint_size(qopt->quantum, b1));
 225
 226        if (qopt_ext && qopt_ext->depth)
 227                print_uint(PRINT_ANY, "depth", "depth %u ", qopt_ext->depth);
 228        if (qopt_ext && qopt_ext->headdrop)
 229                print_bool(PRINT_ANY, "headdrop", "headdrop ", true);
 230        if (show_details)
 231                print_uint(PRINT_ANY, "flows", "flows %u ", qopt->flows);
 232
 233        print_uint(PRINT_ANY, "divisor", "divisor %u ", qopt->divisor);
 234
 235        if (qopt->perturb_period)
 236                print_int(PRINT_ANY, "perturb", "perturb %dsec ",
 237                           qopt->perturb_period);
 238        if (qopt_ext && qopt_ext->qth_min) {
 239                print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt_ext->Wlog);
 240                print_uint(PRINT_JSON, "min", NULL, qopt_ext->qth_min);
 241                print_string(PRINT_FP, NULL, "min %s ",
 242                             sprint_size(qopt_ext->qth_min, b2));
 243                print_uint(PRINT_JSON, "max", NULL, qopt_ext->qth_max);
 244                print_string(PRINT_FP, NULL, "max %s ",
 245                             sprint_size(qopt_ext->qth_max, b3));
 246                print_float(PRINT_ANY, "probability", "probability %lg ",
 247                            qopt_ext->max_P / pow(2, 32));
 248                tc_red_print_flags(qopt_ext->flags);
 249                if (show_stats) {
 250                        print_nl();
 251                        print_uint(PRINT_ANY, "prob_mark", "  prob_mark %u",
 252                                   qopt_ext->stats.prob_mark);
 253                        print_uint(PRINT_ANY, "prob_mark_head",
 254                                   " prob_mark_head %u",
 255                                   qopt_ext->stats.prob_mark_head);
 256                        print_uint(PRINT_ANY, "prob_drop", " prob_drop %u",
 257                                   qopt_ext->stats.prob_drop);
 258                        print_nl();
 259                        print_uint(PRINT_ANY, "forced_mark",
 260                                   "  forced_mark %u",
 261                                   qopt_ext->stats.forced_mark);
 262                        print_uint(PRINT_ANY, "forced_mark_head",
 263                                   " forced_mark_head %u",
 264                                   qopt_ext->stats.forced_mark_head);
 265                        print_uint(PRINT_ANY, "forced_drop", " forced_drop %u",
 266                                   qopt_ext->stats.forced_drop);
 267                }
 268        }
 269        return 0;
 270}
 271
 272static int sfq_print_xstats(struct qdisc_util *qu, FILE *f,
 273                            struct rtattr *xstats)
 274{
 275        struct tc_sfq_xstats *st;
 276
 277        if (xstats == NULL)
 278                return 0;
 279        if (RTA_PAYLOAD(xstats) < sizeof(*st))
 280                return -1;
 281        st = RTA_DATA(xstats);
 282
 283        print_int(PRINT_ANY, "allot", "  allot %d", st->allot);
 284
 285        return 0;
 286}
 287
 288struct qdisc_util sfq_qdisc_util = {
 289        .id             = "sfq",
 290        .parse_qopt     = sfq_parse_opt,
 291        .print_qopt     = sfq_print_opt,
 292        .print_xstats   = sfq_print_xstats,
 293};
 294