X-Git-Url: http://git.onelab.eu/?p=iproute2.git;a=blobdiff_plain;f=tc%2Fq_netem.c;fp=tc%2Fq_netem.c;h=0000000000000000000000000000000000000000;hp=757edcaee717e9ddd5fc1c2e5e4a05ca1a46da98;hb=3331a68859fd71047bb1f309048960b48eab2d83;hpb=2bd4a72f2100be7ad7d9518cb1d49bb2a5b71994 diff --git a/tc/q_netem.c b/tc/q_netem.c deleted file mode 100644 index 757edca..0000000 --- a/tc/q_netem.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * q_netem.c NETEM. - * - * 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: Stephen Hemminger - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils.h" -#include "tc_util.h" -#include "tc_common.h" - -static void explain(void) -{ - fprintf(stderr, -"Usage: ... netem [ limit PACKETS ] \n" \ -" [ delay TIME [ JITTER [CORRELATION]]]\n" \ -" [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ -" [ drop PERCENT [CORRELATION]] \n" \ -" [ corrupt PERCENT [CORRELATION]] \n" \ -" [ duplicate PERCENT [CORRELATION]]\n" \ -" [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n"); -} - -static void explain1(const char *arg) -{ - fprintf(stderr, "Illegal \"%s\"\n", arg); -} - -#define usage() return(-1) - -/* - * Simplistic file parser for distrbution data. - * Format is: - * # comment line(s) - * data0 data1 - */ -#define MAXDIST 65536 -static int get_distribution(const char *type, __s16 *data) -{ - FILE *f; - int n; - long x; - size_t len; - char *line = NULL; - char name[128]; - - snprintf(name, sizeof(name), "/usr/lib/tc/%s.dist", type); - if ((f = fopen(name, "r")) == NULL) { - fprintf(stderr, "No distribution data for %s (%s: %s)\n", - type, name, strerror(errno)); - return -1; - } - - n = 0; - while (getline(&line, &len, f) != -1) { - char *p, *endp; - if (*line == '\n' || *line == '#') - continue; - - for (p = line; ; p = endp) { - x = strtol(p, &endp, 0); - if (endp == p) - break; - - if (n >= MAXDIST) { - fprintf(stderr, "%s: too much data\n", - name); - n = -1; - goto error; - } - data[n++] = x; - } - } - error: - free(line); - fclose(f); - return n; -} - -static int isnumber(const char *arg) -{ - char *p; - (void) strtod(arg, &p); - return (p != arg); -} - -#define NEXT_IS_NUMBER() (NEXT_ARG_OK() && isnumber(argv[1])) - -/* Adjust for the fact that psched_ticks aren't always usecs - (based on kernel PSCHED_CLOCK configuration */ -static int get_ticks(__u32 *ticks, const char *str) -{ - unsigned t; - - if(get_usecs(&t, str)) - return -1; - - *ticks = tc_core_usec2tick(t); - return 0; -} - -static char *sprint_ticks(__u32 ticks, char *buf) -{ - return sprint_usecs(tc_core_tick2usec(ticks), buf); -} - - -static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, - struct nlmsghdr *n) -{ - size_t dist_size = 0; - struct rtattr *tail; - struct tc_netem_qopt opt; - struct tc_netem_corr cor; - struct tc_netem_reorder reorder; - struct tc_netem_corrupt corrupt; - __s16 *dist_data = NULL; - - memset(&opt, 0, sizeof(opt)); - opt.limit = 1000; - memset(&cor, 0, sizeof(cor)); - memset(&reorder, 0, sizeof(reorder)); - memset(&corrupt, 0, sizeof(corrupt)); - - while (argc > 0) { - if (matches(*argv, "limit") == 0) { - NEXT_ARG(); - if (get_size(&opt.limit, *argv)) { - explain1("limit"); - return -1; - } - } else if (matches(*argv, "latency") == 0 || - matches(*argv, "delay") == 0) { - NEXT_ARG(); - if (get_ticks(&opt.latency, *argv)) { - explain1("latency"); - return -1; - } - - if (NEXT_IS_NUMBER()) { - NEXT_ARG(); - if (get_ticks(&opt.jitter, *argv)) { - explain1("latency"); - return -1; - } - - if (NEXT_IS_NUMBER()) { - NEXT_ARG(); - if (get_percent(&cor.delay_corr, - *argv)) { - explain1("latency"); - return -1; - } - } - } - } else if (matches(*argv, "loss") == 0 || - matches(*argv, "drop") == 0) { - NEXT_ARG(); - if (get_percent(&opt.loss, *argv)) { - explain1("loss"); - return -1; - } - if (NEXT_IS_NUMBER()) { - NEXT_ARG(); - if (get_percent(&cor.loss_corr, *argv)) { - explain1("loss"); - return -1; - } - } - } else if (matches(*argv, "reorder") == 0) { - NEXT_ARG(); - if (get_percent(&reorder.probability, *argv)) { - explain1("reorder"); - return -1; - } - if (NEXT_IS_NUMBER()) { - NEXT_ARG(); - if (get_percent(&reorder.correlation, *argv)) { - explain1("reorder"); - return -1; - } - } - } else if (matches(*argv, "corrupt") == 0) { - NEXT_ARG(); - if (get_percent(&corrupt.probability, *argv)) { - explain1("corrupt"); - return -1; - } - if (NEXT_IS_NUMBER()) { - NEXT_ARG(); - if (get_percent(&corrupt.correlation, *argv)) { - explain1("corrupt"); - return -1; - } - } - } else if (matches(*argv, "gap") == 0) { - NEXT_ARG(); - if (get_u32(&opt.gap, *argv, 0)) { - explain1("gap"); - return -1; - } - } else if (matches(*argv, "duplicate") == 0) { - NEXT_ARG(); - if (get_percent(&opt.duplicate, *argv)) { - explain1("duplicate"); - return -1; - } - if (NEXT_IS_NUMBER()) { - NEXT_ARG(); - if (get_percent(&cor.dup_corr, *argv)) { - explain1("duplicate"); - return -1; - } - } - } else if (matches(*argv, "distribution") == 0) { - NEXT_ARG(); - dist_data = alloca(MAXDIST); - dist_size = get_distribution(*argv, dist_data); - if (dist_size < 0) - return -1; - } else if (strcmp(*argv, "help") == 0) { - explain(); - return -1; - } else { - fprintf(stderr, "What is \"%s\"?\n", *argv); - explain(); - return -1; - } - argc--; argv++; - } - - tail = NLMSG_TAIL(n); - - if (reorder.probability) { - if (opt.latency == 0) { - fprintf(stderr, "reordering not possible without specifying some delay\n"); - } - if (opt.gap == 0) - opt.gap = 1; - } else if (opt.gap > 0) { - fprintf(stderr, "gap specified without reorder probability\n"); - explain(); - return -1; - } - - if (dist_data && (opt.latency == 0 || opt.jitter == 0)) { - fprintf(stderr, "distribution specified but no latency and jitter values\n"); - explain(); - return -1; - } - - if (addattr_l(n, TCA_BUF_MAX, TCA_OPTIONS, &opt, sizeof(opt)) < 0) - return -1; - - if (cor.delay_corr || cor.loss_corr || cor.dup_corr) { - if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0) - return -1; - } - - if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0) - return -1; - - if (corrupt.probability) { - if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0) - return -1; - } - - if (dist_data) { - if (addattr_l(n, 32768, TCA_NETEM_DELAY_DIST, - dist_data, dist_size*sizeof(dist_data[0])) < 0) - return -1; - } - tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; - return 0; -} - -static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -{ - const struct tc_netem_corr *cor = NULL; - const struct tc_netem_reorder *reorder = NULL; - const struct tc_netem_corrupt *corrupt = NULL; - struct tc_netem_qopt qopt; - int len = RTA_PAYLOAD(opt) - sizeof(qopt); - SPRINT_BUF(b1); - - if (opt == NULL) - return 0; - - if (len < 0) { - fprintf(stderr, "options size error\n"); - return -1; - } - memcpy(&qopt, RTA_DATA(opt), sizeof(qopt)); - - if (len > 0) { - struct rtattr *tb[TCA_NETEM_MAX+1]; - parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt), - len); - - if (tb[TCA_NETEM_CORR]) { - if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor)) - return -1; - cor = RTA_DATA(tb[TCA_NETEM_CORR]); - } - if (tb[TCA_NETEM_REORDER]) { - if (RTA_PAYLOAD(tb[TCA_NETEM_REORDER]) < sizeof(*reorder)) - return -1; - reorder = RTA_DATA(tb[TCA_NETEM_REORDER]); - } - if (tb[TCA_NETEM_CORRUPT]) { - if (RTA_PAYLOAD(tb[TCA_NETEM_CORRUPT]) < sizeof(*corrupt)) - return -1; - corrupt = RTA_DATA(tb[TCA_NETEM_CORRUPT]); - } - } - - fprintf(f, "limit %d", qopt.limit); - - if (qopt.latency) { - fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1)); - - if (qopt.jitter) { - fprintf(f, " %s", sprint_ticks(qopt.jitter, b1)); - if (cor && cor->delay_corr) - fprintf(f, " %s", sprint_percent(cor->delay_corr, b1)); - } - } - - if (qopt.loss) { - fprintf(f, " loss %s", sprint_percent(qopt.loss, b1)); - if (cor && cor->loss_corr) - fprintf(f, " %s", sprint_percent(cor->loss_corr, b1)); - } - - if (qopt.duplicate) { - fprintf(f, " duplicate %s", - sprint_percent(qopt.duplicate, b1)); - if (cor && cor->dup_corr) - fprintf(f, " %s", sprint_percent(cor->dup_corr, b1)); - } - - if (reorder && reorder->probability) { - fprintf(f, " reorder %s", - sprint_percent(reorder->probability, b1)); - if (reorder->correlation) - fprintf(f, " %s", - sprint_percent(reorder->correlation, b1)); - } - - if (corrupt && corrupt->probability) { - fprintf(f, " corrupt %s", - sprint_percent(corrupt->probability, b1)); - if (corrupt->correlation) - fprintf(f, " %s", - sprint_percent(corrupt->correlation, b1)); - } - - if (qopt.gap) - fprintf(f, " gap %lu", (unsigned long)qopt.gap); - - return 0; -} - -struct qdisc_util netem_qdisc_util = { - .id = "netem", - .parse_qopt = netem_parse_opt, - .print_qopt = netem_print_opt, -}; -