aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-07-03 16:55:21 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-09 03:01:49 -0400
commit960fb66e520a405dde39ff883f17ff2669c13d85 (patch)
treec59b298e45158401419fc42088dad8edf754e535
parentb94e52f62683dc0b00c6d1b58b80929a078c0fd5 (diff)
netem: add limitation to reordered packets
Fix two netem bugs : 1) When a frame was dropped by tfifo_enqueue(), drop counter was incremented twice. 2) When reordering is triggered, we enqueue a packet without checking queue limit. This can OOM pretty fast when this is repeated enough, since skbs are orphaned, no socket limit can help in this situation. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Mark Gordon <msg@google.com> Cc: Andreas Terzis <aterzis@google.com> Cc: Yuchung Cheng <ycheng@google.com> Cc: Hagen Paul Pfeifer <hagen@jauu.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sched/sch_netem.c42
1 files changed, 15 insertions, 27 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index a2a95aabf9c2..c412ad0d0308 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -331,29 +331,22 @@ static psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sche
331 return PSCHED_NS2TICKS(ticks); 331 return PSCHED_NS2TICKS(ticks);
332} 332}
333 333
334static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) 334static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
335{ 335{
336 struct sk_buff_head *list = &sch->q; 336 struct sk_buff_head *list = &sch->q;
337 psched_time_t tnext = netem_skb_cb(nskb)->time_to_send; 337 psched_time_t tnext = netem_skb_cb(nskb)->time_to_send;
338 struct sk_buff *skb; 338 struct sk_buff *skb = skb_peek_tail(list);
339
340 if (likely(skb_queue_len(list) < sch->limit)) {
341 skb = skb_peek_tail(list);
342 /* Optimize for add at tail */
343 if (likely(!skb || tnext >= netem_skb_cb(skb)->time_to_send))
344 return qdisc_enqueue_tail(nskb, sch);
345 339
346 skb_queue_reverse_walk(list, skb) { 340 /* Optimize for add at tail */
347 if (tnext >= netem_skb_cb(skb)->time_to_send) 341 if (likely(!skb || tnext >= netem_skb_cb(skb)->time_to_send))
348 break; 342 return __skb_queue_tail(list, nskb);
349 }
350 343
351 __skb_queue_after(list, skb, nskb); 344 skb_queue_reverse_walk(list, skb) {
352 sch->qstats.backlog += qdisc_pkt_len(nskb); 345 if (tnext >= netem_skb_cb(skb)->time_to_send)
353 return NET_XMIT_SUCCESS; 346 break;
354 } 347 }
355 348
356 return qdisc_reshape_fail(nskb, sch); 349 __skb_queue_after(list, skb, nskb);
357} 350}
358 351
359/* 352/*
@@ -368,7 +361,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
368 /* We don't fill cb now as skb_unshare() may invalidate it */ 361 /* We don't fill cb now as skb_unshare() may invalidate it */
369 struct netem_skb_cb *cb; 362 struct netem_skb_cb *cb;
370 struct sk_buff *skb2; 363 struct sk_buff *skb2;
371 int ret;
372 int count = 1; 364 int count = 1;
373 365
374 /* Random duplication */ 366 /* Random duplication */
@@ -419,6 +411,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
419 skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8); 411 skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8);
420 } 412 }
421 413
414 if (unlikely(skb_queue_len(&sch->q) >= sch->limit))
415 return qdisc_reshape_fail(skb, sch);
416
417 sch->qstats.backlog += qdisc_pkt_len(skb);
418
422 cb = netem_skb_cb(skb); 419 cb = netem_skb_cb(skb);
423 if (q->gap == 0 || /* not doing reordering */ 420 if (q->gap == 0 || /* not doing reordering */
424 q->counter < q->gap - 1 || /* inside last reordering gap */ 421 q->counter < q->gap - 1 || /* inside last reordering gap */
@@ -450,7 +447,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
450 447
451 cb->time_to_send = now + delay; 448 cb->time_to_send = now + delay;
452 ++q->counter; 449 ++q->counter;
453 ret = tfifo_enqueue(skb, sch); 450 tfifo_enqueue(skb, sch);
454 } else { 451 } else {
455 /* 452 /*
456 * Do re-ordering by putting one out of N packets at the front 453 * Do re-ordering by putting one out of N packets at the front
@@ -460,16 +457,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
460 q->counter = 0; 457 q->counter = 0;
461 458
462 __skb_queue_head(&sch->q, skb); 459 __skb_queue_head(&sch->q, skb);
463 sch->qstats.backlog += qdisc_pkt_len(skb);
464 sch->qstats.requeues++; 460 sch->qstats.requeues++;
465 ret = NET_XMIT_SUCCESS;
466 }
467
468 if (ret != NET_XMIT_SUCCESS) {
469 if (net_xmit_drop_count(ret)) {
470 sch->qstats.drops++;
471 return ret;
472 }
473 } 461 }
474 462
475 return NET_XMIT_SUCCESS; 463 return NET_XMIT_SUCCESS;