aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-05-18 23:02:20 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-19 18:34:57 -0400
commit3cc4949269e01f39443d0fcfffb5bc6b47878d45 (patch)
treec83d9410536d3fa4308781a8f36baab09a2144a1 /net
parentbad43ca8325f493dcaa0896c2f036276af059c7e (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')
-rw-r--r--net/ipv4/ip_fragment.c26
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;