This commit was generated by cvs2svn to compensate for changes in r2587,
[iproute2.git] / tc / q_netem.c
index f696cc3..757edca 100644 (file)
@@ -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);