mirror_iproute2/tc/q_red.c
Matteo Croce 8589eb4efd treewide: refactor help messages
Every tool in the iproute2 package have one or more function to show
an help message to the user. Some of these functions print the help
line by line with a series of printf call, e.g. ip/xfrm_state.c does
60 fprintf calls.
If we group all the calls to a single one and just concatenate strings,
we save a lot of libc calls and thus object size. The size difference
of the compiled binaries calculated with bloat-o-meter is:

        ip/ip:
        add/remove: 0/0 grow/shrink: 5/15 up/down: 103/-4796 (-4693)
        Total: Before=672591, After=667898, chg -0.70%
        ip/rtmon:
        add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-54 (-54)
        Total: Before=48879, After=48825, chg -0.11%
        tc/tc:
        add/remove: 0/2 grow/shrink: 31/10 up/down: 882/-6133 (-5251)
        Total: Before=351912, After=346661, chg -1.49%
        bridge/bridge:
        add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-459 (-459)
        Total: Before=70502, After=70043, chg -0.65%
        misc/lnstat:
        add/remove: 0/1 grow/shrink: 1/0 up/down: 48/-486 (-438)
        Total: Before=9960, After=9522, chg -4.40%
        tipc/tipc:
        add/remove: 0/0 grow/shrink: 1/1 up/down: 18/-62 (-44)
        Total: Before=79182, After=79138, chg -0.06%

While at it, indent some strings which were starting at column 0,
and use tabs where possible, to have a consistent style across helps.

Signed-off-by: Matteo Croce <mcroce@redhat.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
2019-05-20 14:35:07 -07:00

235 lines
6.2 KiB
C

/*
* q_red.c RED.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <math.h>
#include "utils.h"
#include "tc_util.h"
#include "tc_red.h"
static void explain(void)
{
fprintf(stderr,
"Usage: ... red limit BYTES [min BYTES] [max BYTES] avpkt BYTES [burst PACKETS]\n"
" [adaptive] [probability PROBABILITY] [bandwidth KBPS]\n"
" [ecn] [harddrop]\n");
}
static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv,
struct nlmsghdr *n, const char *dev)
{
struct tc_red_qopt opt = {};
unsigned int burst = 0;
unsigned int avpkt = 0;
double probability = 0.02;
unsigned int rate = 0;
int parm;
__u8 sbuf[256];
__u32 max_P;
struct rtattr *tail;
while (argc > 0) {
if (strcmp(*argv, "limit") == 0) {
NEXT_ARG();
if (get_size(&opt.limit, *argv)) {
fprintf(stderr, "Illegal \"limit\"\n");
return -1;
}
} else if (strcmp(*argv, "min") == 0) {
NEXT_ARG();
if (get_size(&opt.qth_min, *argv)) {
fprintf(stderr, "Illegal \"min\"\n");
return -1;
}
} else if (strcmp(*argv, "max") == 0) {
NEXT_ARG();
if (get_size(&opt.qth_max, *argv)) {
fprintf(stderr, "Illegal \"max\"\n");
return -1;
}
} else if (strcmp(*argv, "burst") == 0) {
NEXT_ARG();
if (get_unsigned(&burst, *argv, 0)) {
fprintf(stderr, "Illegal \"burst\"\n");
return -1;
}
} else if (strcmp(*argv, "avpkt") == 0) {
NEXT_ARG();
if (get_size(&avpkt, *argv)) {
fprintf(stderr, "Illegal \"avpkt\"\n");
return -1;
}
} else if (strcmp(*argv, "probability") == 0) {
NEXT_ARG();
if (sscanf(*argv, "%lg", &probability) != 1) {
fprintf(stderr, "Illegal \"probability\"\n");
return -1;
}
} else if (strcmp(*argv, "bandwidth") == 0) {
NEXT_ARG();
if (strchr(*argv, '%')) {
if (get_percent_rate(&rate, *argv, dev)) {
fprintf(stderr, "Illegal \"bandwidth\"\n");
return -1;
}
} else if (get_rate(&rate, *argv)) {
fprintf(stderr, "Illegal \"bandwidth\"\n");
return -1;
}
} else if (strcmp(*argv, "ecn") == 0) {
opt.flags |= TC_RED_ECN;
} else if (strcmp(*argv, "harddrop") == 0) {
opt.flags |= TC_RED_HARDDROP;
} else if (strcmp(*argv, "adaptative") == 0) {
opt.flags |= TC_RED_ADAPTATIVE;
} else if (strcmp(*argv, "adaptive") == 0) {
opt.flags |= TC_RED_ADAPTATIVE;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
} else {
fprintf(stderr, "What is \"%s\"?\n", *argv);
explain();
return -1;
}
argc--; argv++;
}
if (!opt.limit || !avpkt) {
fprintf(stderr, "RED: Required parameter (limit, avpkt) is missing\n");
return -1;
}
/* Compute default min/max thresholds based on
* Sally Floyd's recommendations:
* http://www.icir.org/floyd/REDparameters.txt
*/
if (!opt.qth_max)
opt.qth_max = opt.qth_min ? opt.qth_min * 3 : opt.limit / 4;
if (!opt.qth_min)
opt.qth_min = opt.qth_max / 3;
if (!burst)
burst = (2 * opt.qth_min + opt.qth_max) / (3 * avpkt);
if (!rate) {
get_rate(&rate, "10Mbit");
fprintf(stderr, "RED: set bandwidth to 10Mbit\n");
}
if ((parm = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) {
fprintf(stderr, "RED: failed to calculate EWMA constant.\n");
return -1;
}
if (parm >= 10)
fprintf(stderr, "RED: WARNING. Burst %u seems to be too large.\n", burst);
opt.Wlog = parm;
if ((parm = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) {
fprintf(stderr, "RED: failed to calculate probability.\n");
return -1;
}
opt.Plog = parm;
if ((parm = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) {
fprintf(stderr, "RED: failed to calculate idle damping table.\n");
return -1;
}
opt.Scell_log = parm;
tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_RED_PARMS, &opt, sizeof(opt));
addattr_l(n, 1024, TCA_RED_STAB, sbuf, 256);
max_P = probability * pow(2, 32);
addattr_l(n, 1024, TCA_RED_MAX_P, &max_P, sizeof(max_P));
addattr_nest_end(n, tail);
return 0;
}
static int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
struct rtattr *tb[TCA_RED_MAX + 1];
struct tc_red_qopt *qopt;
__u32 max_P = 0;
SPRINT_BUF(b1);
SPRINT_BUF(b2);
SPRINT_BUF(b3);
if (opt == NULL)
return 0;
parse_rtattr_nested(tb, TCA_RED_MAX, opt);
if (tb[TCA_RED_PARMS] == NULL)
return -1;
qopt = RTA_DATA(tb[TCA_RED_PARMS]);
if (RTA_PAYLOAD(tb[TCA_RED_PARMS]) < sizeof(*qopt))
return -1;
if (tb[TCA_RED_MAX_P] &&
RTA_PAYLOAD(tb[TCA_RED_MAX_P]) >= sizeof(__u32))
max_P = rta_getattr_u32(tb[TCA_RED_MAX_P]);
print_uint(PRINT_JSON, "limit", NULL, qopt->limit);
print_string(PRINT_FP, NULL, "limit %s ", sprint_size(qopt->limit, b1));
print_uint(PRINT_JSON, "min", NULL, qopt->qth_min);
print_string(PRINT_FP, NULL, "min %s ", sprint_size(qopt->qth_min, b2));
print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
print_string(PRINT_FP, NULL, "max %s ", sprint_size(qopt->qth_max, b3));
tc_red_print_flags(qopt->flags);
if (show_details) {
print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
if (max_P)
print_float(PRINT_ANY, "probability",
"probability %lg ", max_P / pow(2, 32));
else
print_uint(PRINT_ANY, "Plog", "Plog %u ", qopt->Plog);
print_uint(PRINT_ANY, "Scell_log", "Scell_log %u",
qopt->Scell_log);
}
return 0;
}
static int red_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
{
#ifdef TC_RED_ECN
struct tc_red_xstats *st;
if (xstats == NULL)
return 0;
if (RTA_PAYLOAD(xstats) < sizeof(*st))
return -1;
st = RTA_DATA(xstats);
print_uint(PRINT_ANY, "marked", " marked %u ", st->marked);
print_uint(PRINT_ANY, "early", "early %u ", st->early);
print_uint(PRINT_ANY, "pdrop", "pdrop %u ", st->pdrop);
print_uint(PRINT_ANY, "other", "other %u ", st->other);
#endif
return 0;
}
struct qdisc_util red_qdisc_util = {
.id = "red",
.parse_qopt = red_parse_opt,
.print_qopt = red_print_opt,
.print_xstats = red_print_xstats,
};