aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChangli Gao <xiaosuo@gmail.com>2010-06-29 00:39:37 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-30 16:44:29 -0400
commitd6bebca92c663fb216c072193945946f3807ca7f (patch)
treefd797f062fa19d2ee470cf33c9b475bff08e2545
parent4ce3c183fcade7f4b30a33dae90cd774c3d9e094 (diff)
fragment: add fast path for in-order fragments
add fast path for in-order fragments As the fragments are sent in order in most of OSes, such as Windows, Darwin and FreeBSD, it is likely the new fragments are at the end of the inet_frag_queue. In the fast path, we check if the skb at the end of the inet_frag_queue is the prev we expect. Signed-off-by: Changli Gao <xiaosuo@gmail.com> ---- include/net/inet_frag.h | 1 + net/ipv4/ip_fragment.c | 12 ++++++++++++ net/ipv6/reassembly.c | 11 +++++++++++ 3 files changed, 24 insertions(+) Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/inet_frag.h1
-rw-r--r--net/ipv4/ip_fragment.c12
-rw-r--r--net/ipv6/reassembly.c11
3 files changed, 24 insertions, 0 deletions
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 39f2dc943908..16ff29a7bb30 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -20,6 +20,7 @@ struct inet_frag_queue {
20 atomic_t refcnt; 20 atomic_t refcnt;
21 struct timer_list timer; /* when will this queue expire? */ 21 struct timer_list timer; /* when will this queue expire? */
22 struct sk_buff *fragments; /* list of received fragments */ 22 struct sk_buff *fragments; /* list of received fragments */
23 struct sk_buff *fragments_tail;
23 ktime_t stamp; 24 ktime_t stamp;
24 int len; /* total length of orig datagram */ 25 int len; /* total length of orig datagram */
25 int meat; 26 int meat;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 858d34648eee..dd0dbf0c6b7f 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -314,6 +314,7 @@ static int ip_frag_reinit(struct ipq *qp)
314 qp->q.len = 0; 314 qp->q.len = 0;
315 qp->q.meat = 0; 315 qp->q.meat = 0;
316 qp->q.fragments = NULL; 316 qp->q.fragments = NULL;
317 qp->q.fragments_tail = NULL;
317 qp->iif = 0; 318 qp->iif = 0;
318 319
319 return 0; 320 return 0;
@@ -386,6 +387,11 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
386 * in the chain of fragments so far. We must know where to put 387 * in the chain of fragments so far. We must know where to put
387 * this fragment, right? 388 * this fragment, right?
388 */ 389 */
390 prev = qp->q.fragments_tail;
391 if (!prev || FRAG_CB(prev)->offset < offset) {
392 next = NULL;
393 goto found;
394 }
389 prev = NULL; 395 prev = NULL;
390 for (next = qp->q.fragments; next != NULL; next = next->next) { 396 for (next = qp->q.fragments; next != NULL; next = next->next) {
391 if (FRAG_CB(next)->offset >= offset) 397 if (FRAG_CB(next)->offset >= offset)
@@ -393,6 +399,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
393 prev = next; 399 prev = next;
394 } 400 }
395 401
402found:
396 /* We found where to put this one. Check for overlap with 403 /* We found where to put this one. Check for overlap with
397 * preceding fragment, and, if needed, align things so that 404 * preceding fragment, and, if needed, align things so that
398 * any overlaps are eliminated. 405 * any overlaps are eliminated.
@@ -451,6 +458,8 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
451 458
452 /* Insert this fragment in the chain of fragments. */ 459 /* Insert this fragment in the chain of fragments. */
453 skb->next = next; 460 skb->next = next;
461 if (!next)
462 qp->q.fragments_tail = skb;
454 if (prev) 463 if (prev)
455 prev->next = skb; 464 prev->next = skb;
456 else 465 else
@@ -504,6 +513,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
504 goto out_nomem; 513 goto out_nomem;
505 514
506 fp->next = head->next; 515 fp->next = head->next;
516 if (!fp->next)
517 qp->q.fragments_tail = fp;
507 prev->next = fp; 518 prev->next = fp;
508 519
509 skb_morph(head, qp->q.fragments); 520 skb_morph(head, qp->q.fragments);
@@ -574,6 +585,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
574 iph->tot_len = htons(len); 585 iph->tot_len = htons(len);
575 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); 586 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
576 qp->q.fragments = NULL; 587 qp->q.fragments = NULL;
588 qp->q.fragments_tail = NULL;
577 return 0; 589 return 0;
578 590
579out_nomem: 591out_nomem:
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 0b97230a3251..545c4141b755 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -333,6 +333,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
333 * in the chain of fragments so far. We must know where to put 333 * in the chain of fragments so far. We must know where to put
334 * this fragment, right? 334 * this fragment, right?
335 */ 335 */
336 prev = fq->q.fragments_tail;
337 if (!prev || FRAG6_CB(prev)->offset < offset) {
338 next = NULL;
339 goto found;
340 }
336 prev = NULL; 341 prev = NULL;
337 for(next = fq->q.fragments; next != NULL; next = next->next) { 342 for(next = fq->q.fragments; next != NULL; next = next->next) {
338 if (FRAG6_CB(next)->offset >= offset) 343 if (FRAG6_CB(next)->offset >= offset)
@@ -340,6 +345,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
340 prev = next; 345 prev = next;
341 } 346 }
342 347
348found:
343 /* We found where to put this one. Check for overlap with 349 /* We found where to put this one. Check for overlap with
344 * preceding fragment, and, if needed, align things so that 350 * preceding fragment, and, if needed, align things so that
345 * any overlaps are eliminated. 351 * any overlaps are eliminated.
@@ -397,6 +403,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
397 403
398 /* Insert this fragment in the chain of fragments. */ 404 /* Insert this fragment in the chain of fragments. */
399 skb->next = next; 405 skb->next = next;
406 if (!next)
407 fq->q.fragments_tail = skb;
400 if (prev) 408 if (prev)
401 prev->next = skb; 409 prev->next = skb;
402 else 410 else
@@ -463,6 +471,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
463 goto out_oom; 471 goto out_oom;
464 472
465 fp->next = head->next; 473 fp->next = head->next;
474 if (!fp->next)
475 fq->q.fragments_tail = fp;
466 prev->next = fp; 476 prev->next = fp;
467 477
468 skb_morph(head, fq->q.fragments); 478 skb_morph(head, fq->q.fragments);
@@ -549,6 +559,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
549 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); 559 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
550 rcu_read_unlock(); 560 rcu_read_unlock();
551 fq->q.fragments = NULL; 561 fq->q.fragments = NULL;
562 fq->q.fragments_tail = NULL;
552 return 1; 563 return 1;
553 564
554out_oversize: 565out_oversize: