aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2012-03-18 07:06:44 -0400
committerDavid S. Miller <davem@davemloft.net>2012-03-19 16:53:07 -0400
commite86b291962cbf477e35d983d312428cf737bc0f8 (patch)
tree11520ec988be8644df08684004512c35881e21b5 /net/ipv4/tcp_input.c
parentde1288041d01120559d53ebd98e0f92476ee56d3 (diff)
tcp: introduce tcp_data_queue_ofo
Split tcp_data_queue() in two parts for better readability. tcp_data_queue_ofo() is responsible for queueing incoming skb into out of order queue. Change code layout so that the skb_set_owner_r() is performed only if skb is not dropped. This is a preliminary patch before "reduce out_of_order memory use" following patch. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: Neal Cardwell <ncardwell@google.com> Cc: Yuchung Cheng <ycheng@google.com> Cc: H.K. Jerry Chu <hkchu@google.com> Cc: Tom Herbert <therbert@google.com> Cc: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Acked-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c214
1 files changed, 115 insertions, 99 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 68d4057cba00..fa7de12c4a52 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4446,6 +4446,120 @@ static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size)
4446 return 0; 4446 return 0;
4447} 4447}
4448 4448
4449static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
4450{
4451 struct tcp_sock *tp = tcp_sk(sk);
4452 struct sk_buff *skb1;
4453 u32 seq, end_seq;
4454
4455 TCP_ECN_check_ce(tp, skb);
4456
4457 if (tcp_try_rmem_schedule(sk, skb->truesize)) {
4458 /* TODO: should increment a counter */
4459 __kfree_skb(skb);
4460 return;
4461 }
4462
4463 /* Disable header prediction. */
4464 tp->pred_flags = 0;
4465 inet_csk_schedule_ack(sk);
4466
4467 SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
4468 tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
4469
4470 skb1 = skb_peek_tail(&tp->out_of_order_queue);
4471 if (!skb1) {
4472 /* Initial out of order segment, build 1 SACK. */
4473 if (tcp_is_sack(tp)) {
4474 tp->rx_opt.num_sacks = 1;
4475 tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq;
4476 tp->selective_acks[0].end_seq =
4477 TCP_SKB_CB(skb)->end_seq;
4478 }
4479 __skb_queue_head(&tp->out_of_order_queue, skb);
4480 goto end;
4481 }
4482
4483 seq = TCP_SKB_CB(skb)->seq;
4484 end_seq = TCP_SKB_CB(skb)->end_seq;
4485
4486 if (seq == TCP_SKB_CB(skb1)->end_seq) {
4487 __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
4488
4489 if (!tp->rx_opt.num_sacks ||
4490 tp->selective_acks[0].end_seq != seq)
4491 goto add_sack;
4492
4493 /* Common case: data arrive in order after hole. */
4494 tp->selective_acks[0].end_seq = end_seq;
4495 goto end;
4496 }
4497
4498 /* Find place to insert this segment. */
4499 while (1) {
4500 if (!after(TCP_SKB_CB(skb1)->seq, seq))
4501 break;
4502 if (skb_queue_is_first(&tp->out_of_order_queue, skb1)) {
4503 skb1 = NULL;
4504 break;
4505 }
4506 skb1 = skb_queue_prev(&tp->out_of_order_queue, skb1);
4507 }
4508
4509 /* Do skb overlap to previous one? */
4510 if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) {
4511 if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
4512 /* All the bits are present. Drop. */
4513 __kfree_skb(skb);
4514 skb = NULL;
4515 tcp_dsack_set(sk, seq, end_seq);
4516 goto add_sack;
4517 }
4518 if (after(seq, TCP_SKB_CB(skb1)->seq)) {
4519 /* Partial overlap. */
4520 tcp_dsack_set(sk, seq,
4521 TCP_SKB_CB(skb1)->end_seq);
4522 } else {
4523 if (skb_queue_is_first(&tp->out_of_order_queue,
4524 skb1))
4525 skb1 = NULL;
4526 else
4527 skb1 = skb_queue_prev(
4528 &tp->out_of_order_queue,
4529 skb1);
4530 }
4531 }
4532 if (!skb1)
4533 __skb_queue_head(&tp->out_of_order_queue, skb);
4534 else
4535 __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
4536
4537 /* And clean segments covered by new one as whole. */
4538 while (!skb_queue_is_last(&tp->out_of_order_queue, skb)) {
4539 skb1 = skb_queue_next(&tp->out_of_order_queue, skb);
4540
4541 if (!after(end_seq, TCP_SKB_CB(skb1)->seq))
4542 break;
4543 if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
4544 tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
4545 end_seq);
4546 break;
4547 }
4548 __skb_unlink(skb1, &tp->out_of_order_queue);
4549 tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
4550 TCP_SKB_CB(skb1)->end_seq);
4551 __kfree_skb(skb1);
4552 }
4553
4554add_sack:
4555 if (tcp_is_sack(tp))
4556 tcp_sack_new_ofo_skb(sk, seq, end_seq);
4557end:
4558 if (skb)
4559 skb_set_owner_r(skb, sk);
4560}
4561
4562
4449static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) 4563static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
4450{ 4564{
4451 const struct tcphdr *th = tcp_hdr(skb); 4565 const struct tcphdr *th = tcp_hdr(skb);
@@ -4561,105 +4675,7 @@ drop:
4561 goto queue_and_out; 4675 goto queue_and_out;
4562 } 4676 }
4563 4677
4564 TCP_ECN_check_ce(tp, skb); 4678 tcp_data_queue_ofo(sk, skb);
4565
4566 if (tcp_try_rmem_schedule(sk, skb->truesize))
4567 goto drop;
4568
4569 /* Disable header prediction. */
4570 tp->pred_flags = 0;
4571 inet_csk_schedule_ack(sk);
4572
4573 SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
4574 tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
4575
4576 skb_set_owner_r(skb, sk);
4577
4578 if (!skb_peek(&tp->out_of_order_queue)) {
4579 /* Initial out of order segment, build 1 SACK. */
4580 if (tcp_is_sack(tp)) {
4581 tp->rx_opt.num_sacks = 1;
4582 tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq;
4583 tp->selective_acks[0].end_seq =
4584 TCP_SKB_CB(skb)->end_seq;
4585 }
4586 __skb_queue_head(&tp->out_of_order_queue, skb);
4587 } else {
4588 struct sk_buff *skb1 = skb_peek_tail(&tp->out_of_order_queue);
4589 u32 seq = TCP_SKB_CB(skb)->seq;
4590 u32 end_seq = TCP_SKB_CB(skb)->end_seq;
4591
4592 if (seq == TCP_SKB_CB(skb1)->end_seq) {
4593 __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
4594
4595 if (!tp->rx_opt.num_sacks ||
4596 tp->selective_acks[0].end_seq != seq)
4597 goto add_sack;
4598
4599 /* Common case: data arrive in order after hole. */
4600 tp->selective_acks[0].end_seq = end_seq;
4601 return;
4602 }
4603
4604 /* Find place to insert this segment. */
4605 while (1) {
4606 if (!after(TCP_SKB_CB(skb1)->seq, seq))
4607 break;
4608 if (skb_queue_is_first(&tp->out_of_order_queue, skb1)) {
4609 skb1 = NULL;
4610 break;
4611 }
4612 skb1 = skb_queue_prev(&tp->out_of_order_queue, skb1);
4613 }
4614
4615 /* Do skb overlap to previous one? */
4616 if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) {
4617 if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
4618 /* All the bits are present. Drop. */
4619 __kfree_skb(skb);
4620 tcp_dsack_set(sk, seq, end_seq);
4621 goto add_sack;
4622 }
4623 if (after(seq, TCP_SKB_CB(skb1)->seq)) {
4624 /* Partial overlap. */
4625 tcp_dsack_set(sk, seq,
4626 TCP_SKB_CB(skb1)->end_seq);
4627 } else {
4628 if (skb_queue_is_first(&tp->out_of_order_queue,
4629 skb1))
4630 skb1 = NULL;
4631 else
4632 skb1 = skb_queue_prev(
4633 &tp->out_of_order_queue,
4634 skb1);
4635 }
4636 }
4637 if (!skb1)
4638 __skb_queue_head(&tp->out_of_order_queue, skb);
4639 else
4640 __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
4641
4642 /* And clean segments covered by new one as whole. */
4643 while (!skb_queue_is_last(&tp->out_of_order_queue, skb)) {
4644 skb1 = skb_queue_next(&tp->out_of_order_queue, skb);
4645
4646 if (!after(end_seq, TCP_SKB_CB(skb1)->seq))
4647 break;
4648 if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
4649 tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
4650 end_seq);
4651 break;
4652 }
4653 __skb_unlink(skb1, &tp->out_of_order_queue);
4654 tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
4655 TCP_SKB_CB(skb1)->end_seq);
4656 __kfree_skb(skb1);
4657 }
4658
4659add_sack:
4660 if (tcp_is_sack(tp))
4661 tcp_sack_new_ofo_skb(sk, seq, end_seq);
4662 }
4663} 4679}
4664 4680
4665static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, 4681static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb,