aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/reassembly.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-05-18 23:02:35 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-19 18:34:57 -0400
commitec16439e173aaf56f62bd8e175e976fbd452497b (patch)
treec26192b632186e2db52d8b808270f22fc1d1ac81 /net/ipv6/reassembly.c
parent3cc4949269e01f39443d0fcfffb5bc6b47878d45 (diff)
ipv6: use skb coalescing in reassembly
ip6_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/ipv6/reassembly.c')
-rw-r--r--net/ipv6/reassembly.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 5d32dfa4d75a..4ff9af628e72 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -415,6 +415,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
415 struct sk_buff *fp, *head = fq->q.fragments; 415 struct sk_buff *fp, *head = fq->q.fragments;
416 int payload_len; 416 int payload_len;
417 unsigned int nhoff; 417 unsigned int nhoff;
418 int sum_truesize;
418 419
419 fq_kill(fq); 420 fq_kill(fq);
420 421
@@ -484,20 +485,33 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
484 head->mac_header += sizeof(struct frag_hdr); 485 head->mac_header += sizeof(struct frag_hdr);
485 head->network_header += sizeof(struct frag_hdr); 486 head->network_header += sizeof(struct frag_hdr);
486 487
487 skb_shinfo(head)->frag_list = head->next;
488 skb_reset_transport_header(head); 488 skb_reset_transport_header(head);
489 skb_push(head, head->data - skb_network_header(head)); 489 skb_push(head, head->data - skb_network_header(head));
490 490
491 for (fp=head->next; fp; fp = fp->next) { 491 sum_truesize = head->truesize;
492 head->data_len += fp->len; 492 for (fp = head->next; fp;) {
493 head->len += fp->len; 493 bool headstolen;
494 int delta;
495 struct sk_buff *next = fp->next;
496
497 sum_truesize += fp->truesize;
494 if (head->ip_summed != fp->ip_summed) 498 if (head->ip_summed != fp->ip_summed)
495 head->ip_summed = CHECKSUM_NONE; 499 head->ip_summed = CHECKSUM_NONE;
496 else if (head->ip_summed == CHECKSUM_COMPLETE) 500 else if (head->ip_summed == CHECKSUM_COMPLETE)
497 head->csum = csum_add(head->csum, fp->csum); 501 head->csum = csum_add(head->csum, fp->csum);
498 head->truesize += fp->truesize; 502
503 if (skb_try_coalesce(head, fp, &headstolen, &delta)) {
504 kfree_skb_partial(fp, headstolen);
505 } else {
506 if (!skb_shinfo(head)->frag_list)
507 skb_shinfo(head)->frag_list = fp;
508 head->data_len += fp->len;
509 head->len += fp->len;
510 head->truesize += fp->truesize;
511 }
512 fp = next;
499 } 513 }
500 atomic_sub(head->truesize, &fq->q.net->mem); 514 atomic_sub(sum_truesize, &fq->q.net->mem);
501 515
502 head->next = NULL; 516 head->next = NULL;
503 head->dev = dev; 517 head->dev = dev;