diff options
-rw-r--r-- | include/linux/pkt_sched.h | 7 | ||||
-rw-r--r-- | net/sched/sch_netem.c | 49 |
2 files changed, 53 insertions, 3 deletions
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index e87b233615b3..d10f35338507 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h | |||
@@ -429,6 +429,7 @@ enum | |||
429 | TCA_NETEM_CORR, | 429 | TCA_NETEM_CORR, |
430 | TCA_NETEM_DELAY_DIST, | 430 | TCA_NETEM_DELAY_DIST, |
431 | TCA_NETEM_REORDER, | 431 | TCA_NETEM_REORDER, |
432 | TCA_NETEM_CORRUPT, | ||
432 | __TCA_NETEM_MAX, | 433 | __TCA_NETEM_MAX, |
433 | }; | 434 | }; |
434 | 435 | ||
@@ -457,6 +458,12 @@ struct tc_netem_reorder | |||
457 | __u32 correlation; | 458 | __u32 correlation; |
458 | }; | 459 | }; |
459 | 460 | ||
461 | struct tc_netem_corrupt | ||
462 | { | ||
463 | __u32 probability; | ||
464 | __u32 correlation; | ||
465 | }; | ||
466 | |||
460 | #define NETEM_DIST_SCALE 8192 | 467 | #define NETEM_DIST_SCALE 8192 |
461 | 468 | ||
462 | #endif | 469 | #endif |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 82fb07aa06a5..ba5283204837 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include <net/pkt_sched.h> | 26 | #include <net/pkt_sched.h> |
27 | 27 | ||
28 | #define VERSION "1.1" | 28 | #define VERSION "1.2" |
29 | 29 | ||
30 | /* Network Emulation Queuing algorithm. | 30 | /* Network Emulation Queuing algorithm. |
31 | ==================================== | 31 | ==================================== |
@@ -65,11 +65,12 @@ struct netem_sched_data { | |||
65 | u32 jitter; | 65 | u32 jitter; |
66 | u32 duplicate; | 66 | u32 duplicate; |
67 | u32 reorder; | 67 | u32 reorder; |
68 | u32 corrupt; | ||
68 | 69 | ||
69 | struct crndstate { | 70 | struct crndstate { |
70 | unsigned long last; | 71 | unsigned long last; |
71 | unsigned long rho; | 72 | unsigned long rho; |
72 | } delay_cor, loss_cor, dup_cor, reorder_cor; | 73 | } delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor; |
73 | 74 | ||
74 | struct disttable { | 75 | struct disttable { |
75 | u32 size; | 76 | u32 size; |
@@ -183,6 +184,23 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
183 | q->duplicate = dupsave; | 184 | q->duplicate = dupsave; |
184 | } | 185 | } |
185 | 186 | ||
187 | /* | ||
188 | * Randomized packet corruption. | ||
189 | * Make copy if needed since we are modifying | ||
190 | * If packet is going to be hardware checksummed, then | ||
191 | * do it now in software before we mangle it. | ||
192 | */ | ||
193 | if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) { | ||
194 | if (!(skb = skb_unshare(skb, GFP_ATOMIC)) | ||
195 | || (skb->ip_summed == CHECKSUM_HW | ||
196 | && skb_checksum_help(skb, 0))) { | ||
197 | sch->qstats.drops++; | ||
198 | return NET_XMIT_DROP; | ||
199 | } | ||
200 | |||
201 | skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8); | ||
202 | } | ||
203 | |||
186 | if (q->gap == 0 /* not doing reordering */ | 204 | if (q->gap == 0 /* not doing reordering */ |
187 | || q->counter < q->gap /* inside last reordering gap */ | 205 | || q->counter < q->gap /* inside last reordering gap */ |
188 | || q->reorder < get_crandom(&q->reorder_cor)) { | 206 | || q->reorder < get_crandom(&q->reorder_cor)) { |
@@ -382,6 +400,20 @@ static int get_reorder(struct Qdisc *sch, const struct rtattr *attr) | |||
382 | return 0; | 400 | return 0; |
383 | } | 401 | } |
384 | 402 | ||
403 | static int get_corrupt(struct Qdisc *sch, const struct rtattr *attr) | ||
404 | { | ||
405 | struct netem_sched_data *q = qdisc_priv(sch); | ||
406 | const struct tc_netem_corrupt *r = RTA_DATA(attr); | ||
407 | |||
408 | if (RTA_PAYLOAD(attr) != sizeof(*r)) | ||
409 | return -EINVAL; | ||
410 | |||
411 | q->corrupt = r->probability; | ||
412 | init_crandom(&q->corrupt_cor, r->correlation); | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | /* Parse netlink message to set options */ | ||
385 | static int netem_change(struct Qdisc *sch, struct rtattr *opt) | 417 | static int netem_change(struct Qdisc *sch, struct rtattr *opt) |
386 | { | 418 | { |
387 | struct netem_sched_data *q = qdisc_priv(sch); | 419 | struct netem_sched_data *q = qdisc_priv(sch); |
@@ -432,13 +464,19 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt) | |||
432 | if (ret) | 464 | if (ret) |
433 | return ret; | 465 | return ret; |
434 | } | 466 | } |
467 | |||
435 | if (tb[TCA_NETEM_REORDER-1]) { | 468 | if (tb[TCA_NETEM_REORDER-1]) { |
436 | ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]); | 469 | ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]); |
437 | if (ret) | 470 | if (ret) |
438 | return ret; | 471 | return ret; |
439 | } | 472 | } |
440 | } | ||
441 | 473 | ||
474 | if (tb[TCA_NETEM_CORRUPT-1]) { | ||
475 | ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT-1]); | ||
476 | if (ret) | ||
477 | return ret; | ||
478 | } | ||
479 | } | ||
442 | 480 | ||
443 | return 0; | 481 | return 0; |
444 | } | 482 | } |
@@ -564,6 +602,7 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
564 | struct tc_netem_qopt qopt; | 602 | struct tc_netem_qopt qopt; |
565 | struct tc_netem_corr cor; | 603 | struct tc_netem_corr cor; |
566 | struct tc_netem_reorder reorder; | 604 | struct tc_netem_reorder reorder; |
605 | struct tc_netem_corrupt corrupt; | ||
567 | 606 | ||
568 | qopt.latency = q->latency; | 607 | qopt.latency = q->latency; |
569 | qopt.jitter = q->jitter; | 608 | qopt.jitter = q->jitter; |
@@ -582,6 +621,10 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
582 | reorder.correlation = q->reorder_cor.rho; | 621 | reorder.correlation = q->reorder_cor.rho; |
583 | RTA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder); | 622 | RTA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder); |
584 | 623 | ||
624 | corrupt.probability = q->corrupt; | ||
625 | corrupt.correlation = q->corrupt_cor.rho; | ||
626 | RTA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); | ||
627 | |||
585 | rta->rta_len = skb->tail - b; | 628 | rta->rta_len = skb->tail - b; |
586 | 629 | ||
587 | return skb->len; | 630 | return skb->len; |