X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=tc%2Fq_netem.c;h=757edcaee717e9ddd5fc1c2e5e4a05ca1a46da98;hb=fcabec0aee42af28e2846ef3674ed7ba7be72c42;hp=f696cc3231f4edd6810b8ff2c5c3c6340c047669;hpb=cb820e861caa85bb3942ab0c673e04b9408be0ad;p=iproute2.git diff --git a/tc/q_netem.c b/tc/q_netem.c index f696cc3..757edca 100644 --- a/tc/q_netem.c +++ b/tc/q_netem.c @@ -29,11 +29,12 @@ static void explain(void) { fprintf(stderr, "Usage: ... netem [ limit PACKETS ] \n" \ -" [ delay TIME [ JITTER [CORRELATION]]]\n" \ +" [ delay TIME [ JITTER [CORRELATION]]]\n" \ +" [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ " [ drop PERCENT [CORRELATION]] \n" \ +" [ corrupt PERCENT [CORRELATION]] \n" \ " [ duplicate PERCENT [CORRELATION]]\n" \ -" [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ -" [ gap PACKETS ]\n"); +" [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n"); } static void explain1(const char *arg) @@ -127,11 +128,15 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct rtattr *tail; struct tc_netem_qopt opt; struct tc_netem_corr cor; - __s16 dist_data[MAXDIST]; + 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) { @@ -178,6 +183,32 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, 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)) { @@ -199,6 +230,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, } } 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; @@ -215,12 +247,44 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, tail = NLMSG_TAIL(n); - addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); - addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)); + 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_size > 0) { - addattr_l(n, 32768, TCA_NETEM_DELAY_DIST, - dist_data, dist_size*sizeof(dist_data[0])); + 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; @@ -229,6 +293,8 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, 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); @@ -252,6 +318,16 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 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); @@ -278,6 +354,22 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 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);