From: Hagen Paul Pfeifer Date: Thu, 19 Jan 2012 22:28:27 +0000 (-0800) Subject: tc: netem rate shaping and cell extension X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lisovros/iproute2_canprio.git/commitdiff_plain/6b8dc4deea219d6c4392707bb647cc49cdc46da7 tc: netem rate shaping and cell extension This patch add rate shaping as well as cell support. The link-rate can be specified via rate options. Three optional arguments control the cell knobs: packet-overhead, cell-size, cell-overhead. To ratelimit eth0 root queue to 5kbit/s, with a 20 byte packet overhead, 100 byte cell size and a 5 byte per cell overhead: tc qdisc add dev eth0 root netem rate 5kbit 20 100 5 Signed-off-by: Hagen Paul Pfeifer --- diff --git a/tc/q_netem.c b/tc/q_netem.c index b1fd452..cb0c8a4 100644 --- a/tc/q_netem.c +++ b/tc/q_netem.c @@ -38,7 +38,8 @@ static void explain(void) " [ loss random PERCENT [CORRELATION]]\n" \ " [ loss state P13 [P31 [P32 [P23 P14]]]\n" \ " [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \ -" [ reorder PERCENT [CORRELATION] [ gap DISTANCE ]]\n"); +" [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \ +" [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n"); } static void explain1(const char *arg) @@ -175,6 +176,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct tc_netem_corrupt corrupt; struct tc_netem_gimodel gimodel; struct tc_netem_gemodel gemodel; + struct tc_netem_rate rate; __s16 *dist_data = NULL; __u16 loss_type = NETEM_LOSS_UNSPEC; int present[__TCA_NETEM_MAX]; @@ -182,6 +184,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, memset(&cor, 0, sizeof(cor)); memset(&reorder, 0, sizeof(reorder)); memset(&corrupt, 0, sizeof(corrupt)); + memset(&rate, 0, sizeof(rate)); memset(present, 0, sizeof(present)); for( ; argc > 0; --argc, ++argv) { @@ -380,6 +383,34 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, free(dist_data); return -1; } + } else if (matches(*argv, "rate") == 0) { + ++present[TCA_NETEM_RATE]; + NEXT_ARG(); + if (get_rate(&rate.rate, *argv)) { + explain1("rate"); + return -1; + } + if (NEXT_IS_NUMBER()) { + NEXT_ARG(); + if (get_s32(&rate.packet_overhead, *argv, 0)) { + explain1("rate"); + return -1; + } + } + if (NEXT_IS_NUMBER()) { + NEXT_ARG(); + if (get_u32(&rate.cell_size, *argv, 0)) { + explain1("rate"); + return -1; + } + } + if (NEXT_IS_NUMBER()) { + NEXT_ARG(); + if (get_s32(&rate.cell_overhead, *argv, 0)) { + explain1("rate"); + return -1; + } + } } else if (strcmp(*argv, "help") == 0) { explain(); return -1; @@ -445,6 +476,10 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, addattr_nest_end(n, start); } + if (present[TCA_NETEM_RATE] && + addattr_l(n, 1024, TCA_NETEM_RATE, &rate, sizeof(rate)) < 0) + return -1; + if (dist_data) { if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]), TCA_NETEM_DELAY_DIST, @@ -464,6 +499,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) const struct tc_netem_gimodel *gimodel = NULL; const struct tc_netem_gemodel *gemodel = NULL; struct tc_netem_qopt qopt; + const struct tc_netem_rate *rate = NULL; int len = RTA_PAYLOAD(opt) - sizeof(qopt); SPRINT_BUF(b1); @@ -505,6 +541,11 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (lb[NETEM_LOSS_GE]) gemodel = RTA_DATA(lb[NETEM_LOSS_GE]); } + if (tb[TCA_NETEM_RATE]) { + if (RTA_PAYLOAD(tb[TCA_NETEM_RATE]) < sizeof(*rate)) + return -1; + rate = RTA_DATA(tb[TCA_NETEM_RATE]); + } } fprintf(f, "limit %d", qopt.limit); @@ -564,6 +605,16 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) sprint_percent(corrupt->correlation, b1)); } + if (rate && rate->rate) { + fprintf(f, " rate %s", sprint_rate(rate->rate, b1)); + if (rate->packet_overhead) + fprintf(f, " packetoverhead %d", rate->packet_overhead); + if (rate->cell_size) + fprintf(f, " cellsize %u", rate->cell_size); + if (rate->cell_overhead) + fprintf(f, " celloverhead %d", rate->cell_overhead); + } + if (qopt.gap) fprintf(f, " gap %lu", (unsigned long)qopt.gap);