diff options
author | Eric Dumazet <edumazet@google.com> | 2012-05-18 23:02:20 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-19 18:34:57 -0400 |
commit | 3cc4949269e01f39443d0fcfffb5bc6b47878d45 (patch) | |
tree | c83d9410536d3fa4308781a8f36baab09a2144a1 /net/ipv4 | |
parent | bad43ca8325f493dcaa0896c2f036276af059c7e (diff) |
ipv4: use skb coalescing in defragmentation
ip_frag_reasm() can use skb_try_coalesce() to build optimized skb,
reducing memory used by them (truesize), and reducing number of cache
line misses and overhead for the consumer.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/ip_fragment.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 695b27f44161..9dbd3dd6022d 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -545,6 +545,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
545 | int len; | 545 | int len; |
546 | int ihlen; | 546 | int ihlen; |
547 | int err; | 547 | int err; |
548 | int sum_truesize; | ||
548 | u8 ecn; | 549 | u8 ecn; |
549 | 550 | ||
550 | ipq_kill(qp); | 551 | ipq_kill(qp); |
@@ -611,19 +612,32 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
611 | atomic_add(clone->truesize, &qp->q.net->mem); | 612 | atomic_add(clone->truesize, &qp->q.net->mem); |
612 | } | 613 | } |
613 | 614 | ||
614 | skb_shinfo(head)->frag_list = head->next; | ||
615 | skb_push(head, head->data - skb_network_header(head)); | 615 | skb_push(head, head->data - skb_network_header(head)); |
616 | 616 | ||
617 | for (fp=head->next; fp; fp = fp->next) { | 617 | sum_truesize = head->truesize; |
618 | head->data_len += fp->len; | 618 | for (fp = head->next; fp;) { |
619 | head->len += fp->len; | 619 | bool headstolen; |
620 | int delta; | ||
621 | struct sk_buff *next = fp->next; | ||
622 | |||
623 | sum_truesize += fp->truesize; | ||
620 | if (head->ip_summed != fp->ip_summed) | 624 | if (head->ip_summed != fp->ip_summed) |
621 | head->ip_summed = CHECKSUM_NONE; | 625 | head->ip_summed = CHECKSUM_NONE; |
622 | else if (head->ip_summed == CHECKSUM_COMPLETE) | 626 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
623 | head->csum = csum_add(head->csum, fp->csum); | 627 | head->csum = csum_add(head->csum, fp->csum); |
624 | head->truesize += fp->truesize; | 628 | |
629 | if (skb_try_coalesce(head, fp, &headstolen, &delta)) { | ||
630 | kfree_skb_partial(fp, headstolen); | ||
631 | } else { | ||
632 | if (!skb_shinfo(head)->frag_list) | ||
633 | skb_shinfo(head)->frag_list = fp; | ||
634 | head->data_len += fp->len; | ||
635 | head->len += fp->len; | ||
636 | head->truesize += fp->truesize; | ||
637 | } | ||
638 | fp = next; | ||
625 | } | 639 | } |
626 | atomic_sub(head->truesize, &qp->q.net->mem); | 640 | atomic_sub(sum_truesize, &qp->q.net->mem); |
627 | 641 | ||
628 | head->next = NULL; | 642 | head->next = NULL; |
629 | head->dev = dev; | 643 | head->dev = dev; |