aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
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/ipv4
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/ipv4')
-rw-r--r--net/ipv4/ip_fragment.c12
1 files changed, 12 insertions, 0 deletions
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: