aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/reassembly.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-21 13:03:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-21 13:03:46 -0400
commitcb62ab71fe2b16e8203a0f0a2ef4eda23d761338 (patch)
tree536ba39658e47d511a489c52f7aac60cd78967e5 /net/ipv6/reassembly.c
parent31ed8e6f93a27304c9e157dab0267772cd94eaad (diff)
parent74863948f925d9f3bb4e3d3a783e49e9c662d839 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking changes from David Miller: 1) Get rid of the error prone NLA_PUT*() macros that used an embedded goto. 2) Kill off the token-ring and MCA networking drivers, from Paul Gortmaker. 3) Reduce high-order allocations made by datagram AF_UNIX sockets, from Eric Dumazet. 4) Add PTP hardware clock support to IGB and IXGBE, from Richard Cochran and Jacob Keller. 5) Allow users to query timestamping capabilities of a card via ethtool, from Richard Cochran. 6) Add loadbalance mode to the teaming driver, from Jiri Pirko. Part of this is that we can now have BPF filters not attached to sockets, and the loadbalancing function is calculated using one. 7) Francois Romieu went through the network drivers removing gratuitous uses of netdev->base_addr, perhaps some day we can remove it completely but it's used for ISA probing still. 8) Add a BPF JIT for sparc. I know, who cares, right? :-) 9) Move networking sysctl registry away from using the compatability mode interfaces in the sysctl code. From Eric W Biederman. 10) Pavel Emelyanov added a way to save and restore TCP socket state via TCP_REPAIR, TCP_REPAIR_QUEUE, and TCP_QUEUE_SEQ socket options as well as a way to forcefully bind a socket to a port via the sk->sk_reuse value SK_FORCE_REUSE. There is also a TCP_REPAIR_OPTIONS which allows to reinstante the TCP options enabled on the connection. 11) Several enhancements from Eric Dumazet that, in particular, can enhance splice performance on TCP sockets significantly. a) Reset the offset of the per-socket sendmsg page when we know we're the only use of the page in linear_to_page(). b) Add facilities such that skb->data can be backed a page rather than SLAB kmalloc'd memory. In particular devices which were receiving into linear RX buffers can now end up providing paged data. The big result is that code like splice and GRO do not have to copy any more. 12) Allow a pure sender to more gracefully handle ACK backlogs in TCP. What can happen at high rates is that the sender hasn't grown his receive buffer limits at all (he's not receiving data so really doesn't need to), but the non-data ACKs consume receive buffer space. sk_add_backlog() is too aggressive in dropping frames in this case, so relax it's requirements by using the receive buffer plus the send buffer limit as the backlog limit instead of just the former. Also from Eric Dumazet. 13) Add ipv6 support to L2TP, from Benjamin LaHaise, James Chapman, and Chris Elston. 14) Implement TCP early retransmit (RFC 5827), from Yuchung Cheng. Basically, we can start fast retransmit before hiting the dupack threshold under certain conditions. 15) New CODEL active queue management packet scheduler, from Eric Dumazet based upon initial work by Dave Taht. Basically, the big feature is that packets are dropped (or ECN bits are set) based upon how long packets live in the queue, rather than the queue length (which is what RED uses). * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1341 commits) drivers/net/stmmac: seq_file fix memory leak ipv6/exthdrs: strict Pad1 and PadN check USB: qmi_wwan: Add ZTE (Vodafone) K3520-Z USB: qmi_wwan: Add ZTE (Vodafone) K3765-Z USB: qmi_wwan: Make forced int 4 whitelist generic net/ipv4: replace simple_strtoul with kstrtoul net/ipv4/ipconfig: neaten __setup placement net: qmi_wwan: Add Vodafone/Huawei K5005 support net: cdc_ether: Add ZTE WWAN matches before generic Ethernet ipv6: use skb coalescing in reassembly ipv4: use skb coalescing in defragmentation net: introduce skb_try_coalesce() net:ipv6:fixed space issues relating to operators. net:ipv6:fixed a trailing white space issue. ipv6: disable GSO on sockets hitting dst_allfrag tg3: use netdev_alloc_frag() API net: napi_frags_skb() is static ppp: avoid false drop_monitor false positives ipv6: bool/const conversions phase2 ipx: Remove spurious NULL checking in ipx_ioctl(). ...
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r--net/ipv6/reassembly.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 9447bd69873a..4ff9af628e72 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -134,15 +134,16 @@ static unsigned int ip6_hashfn(struct inet_frag_queue *q)
134 return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr, ip6_frags.rnd); 134 return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr, ip6_frags.rnd);
135} 135}
136 136
137int ip6_frag_match(struct inet_frag_queue *q, void *a) 137bool ip6_frag_match(struct inet_frag_queue *q, void *a)
138{ 138{
139 struct frag_queue *fq; 139 struct frag_queue *fq;
140 struct ip6_create_arg *arg = a; 140 struct ip6_create_arg *arg = a;
141 141
142 fq = container_of(q, struct frag_queue, q); 142 fq = container_of(q, struct frag_queue, q);
143 return (fq->id == arg->id && fq->user == arg->user && 143 return fq->id == arg->id &&
144 ipv6_addr_equal(&fq->saddr, arg->src) && 144 fq->user == arg->user &&
145 ipv6_addr_equal(&fq->daddr, arg->dst)); 145 ipv6_addr_equal(&fq->saddr, arg->src) &&
146 ipv6_addr_equal(&fq->daddr, arg->dst);
146} 147}
147EXPORT_SYMBOL(ip6_frag_match); 148EXPORT_SYMBOL(ip6_frag_match);
148 149
@@ -414,6 +415,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
414 struct sk_buff *fp, *head = fq->q.fragments; 415 struct sk_buff *fp, *head = fq->q.fragments;
415 int payload_len; 416 int payload_len;
416 unsigned int nhoff; 417 unsigned int nhoff;
418 int sum_truesize;
417 419
418 fq_kill(fq); 420 fq_kill(fq);
419 421
@@ -433,7 +435,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
433 skb_morph(head, fq->q.fragments); 435 skb_morph(head, fq->q.fragments);
434 head->next = fq->q.fragments->next; 436 head->next = fq->q.fragments->next;
435 437
436 kfree_skb(fq->q.fragments); 438 consume_skb(fq->q.fragments);
437 fq->q.fragments = head; 439 fq->q.fragments = head;
438 } 440 }
439 441
@@ -483,20 +485,33 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
483 head->mac_header += sizeof(struct frag_hdr); 485 head->mac_header += sizeof(struct frag_hdr);
484 head->network_header += sizeof(struct frag_hdr); 486 head->network_header += sizeof(struct frag_hdr);
485 487
486 skb_shinfo(head)->frag_list = head->next;
487 skb_reset_transport_header(head); 488 skb_reset_transport_header(head);
488 skb_push(head, head->data - skb_network_header(head)); 489 skb_push(head, head->data - skb_network_header(head));
489 490
490 for (fp=head->next; fp; fp = fp->next) { 491 sum_truesize = head->truesize;
491 head->data_len += fp->len; 492 for (fp = head->next; fp;) {
492 head->len += fp->len; 493 bool headstolen;
494 int delta;
495 struct sk_buff *next = fp->next;
496
497 sum_truesize += fp->truesize;
493 if (head->ip_summed != fp->ip_summed) 498 if (head->ip_summed != fp->ip_summed)
494 head->ip_summed = CHECKSUM_NONE; 499 head->ip_summed = CHECKSUM_NONE;
495 else if (head->ip_summed == CHECKSUM_COMPLETE) 500 else if (head->ip_summed == CHECKSUM_COMPLETE)
496 head->csum = csum_add(head->csum, fp->csum); 501 head->csum = csum_add(head->csum, fp->csum);
497 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;
498 } 513 }
499 atomic_sub(head->truesize, &fq->q.net->mem); 514 atomic_sub(sum_truesize, &fq->q.net->mem);
500 515
501 head->next = NULL; 516 head->next = NULL;
502 head->dev = dev; 517 head->dev = dev;
@@ -518,12 +533,10 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
518 return 1; 533 return 1;
519 534
520out_oversize: 535out_oversize:
521 if (net_ratelimit()) 536 net_dbg_ratelimited("ip6_frag_reasm: payload len = %d\n", payload_len);
522 printk(KERN_DEBUG "ip6_frag_reasm: payload len = %d\n", payload_len);
523 goto out_fail; 537 goto out_fail;
524out_oom: 538out_oom:
525 if (net_ratelimit()) 539 net_dbg_ratelimited("ip6_frag_reasm: no memory for reassembly\n");
526 printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
527out_fail: 540out_fail:
528 rcu_read_lock(); 541 rcu_read_lock();
529 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); 542 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
@@ -646,7 +659,7 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net)
646 table[2].data = &net->ipv6.frags.timeout; 659 table[2].data = &net->ipv6.frags.timeout;
647 } 660 }
648 661
649 hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table); 662 hdr = register_net_sysctl(net, "net/ipv6", table);
650 if (hdr == NULL) 663 if (hdr == NULL)
651 goto err_reg; 664 goto err_reg;
652 665
@@ -674,7 +687,7 @@ static struct ctl_table_header *ip6_ctl_header;
674 687
675static int ip6_frags_sysctl_register(void) 688static int ip6_frags_sysctl_register(void)
676{ 689{
677 ip6_ctl_header = register_net_sysctl_rotable(net_ipv6_ctl_path, 690 ip6_ctl_header = register_net_sysctl(&init_net, "net/ipv6",
678 ip6_frags_ctl_table); 691 ip6_frags_ctl_table);
679 return ip6_ctl_header == NULL ? -ENOMEM : 0; 692 return ip6_ctl_header == NULL ? -ENOMEM : 0;
680} 693}