aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/reassembly.c
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 /net/ipv6/reassembly.c
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>
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r--net/ipv6/reassembly.c11
1 files changed, 11 insertions, 0 deletions
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: