diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp_input.c | 63 |
1 files changed, 39 insertions, 24 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 125b4517f368..03f5ede87224 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2461,6 +2461,44 @@ static int tcp_time_to_recover(struct sock *sk) | |||
2461 | return 0; | 2461 | return 0; |
2462 | } | 2462 | } |
2463 | 2463 | ||
2464 | /* New heuristics: it is possible only after we switched to restart timer | ||
2465 | * each time when something is ACKed. Hence, we can detect timed out packets | ||
2466 | * during fast retransmit without falling to slow start. | ||
2467 | * | ||
2468 | * Usefulness of this as is very questionable, since we should know which of | ||
2469 | * the segments is the next to timeout which is relatively expensive to find | ||
2470 | * in general case unless we add some data structure just for that. The | ||
2471 | * current approach certainly won't find the right one too often and when it | ||
2472 | * finally does find _something_ it usually marks large part of the window | ||
2473 | * right away (because a retransmission with a larger timestamp blocks the | ||
2474 | * loop from advancing). -ij | ||
2475 | */ | ||
2476 | static void tcp_timeout_skbs(struct sock *sk) | ||
2477 | { | ||
2478 | struct tcp_sock *tp = tcp_sk(sk); | ||
2479 | struct sk_buff *skb; | ||
2480 | |||
2481 | if (!tcp_is_fack(tp) || !tcp_head_timedout(sk)) | ||
2482 | return; | ||
2483 | |||
2484 | skb = tp->scoreboard_skb_hint; | ||
2485 | if (tp->scoreboard_skb_hint == NULL) | ||
2486 | skb = tcp_write_queue_head(sk); | ||
2487 | |||
2488 | tcp_for_write_queue_from(skb, sk) { | ||
2489 | if (skb == tcp_send_head(sk)) | ||
2490 | break; | ||
2491 | if (!tcp_skb_timedout(sk, skb)) | ||
2492 | break; | ||
2493 | |||
2494 | tcp_skb_mark_lost(tp, skb); | ||
2495 | } | ||
2496 | |||
2497 | tp->scoreboard_skb_hint = skb; | ||
2498 | |||
2499 | tcp_verify_left_out(tp); | ||
2500 | } | ||
2501 | |||
2464 | /* Mark head of queue up as lost. With RFC3517 SACK, the packets is | 2502 | /* Mark head of queue up as lost. With RFC3517 SACK, the packets is |
2465 | * is against sacked "cnt", otherwise it's against facked "cnt" | 2503 | * is against sacked "cnt", otherwise it's against facked "cnt" |
2466 | */ | 2504 | */ |
@@ -2533,30 +2571,7 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit) | |||
2533 | tcp_mark_head_lost(sk, sacked_upto); | 2571 | tcp_mark_head_lost(sk, sacked_upto); |
2534 | } | 2572 | } |
2535 | 2573 | ||
2536 | /* New heuristics: it is possible only after we switched | 2574 | tcp_timeout_skbs(sk); |
2537 | * to restart timer each time when something is ACKed. | ||
2538 | * Hence, we can detect timed out packets during fast | ||
2539 | * retransmit without falling to slow start. | ||
2540 | */ | ||
2541 | if (tcp_is_fack(tp) && tcp_head_timedout(sk)) { | ||
2542 | struct sk_buff *skb; | ||
2543 | |||
2544 | skb = tp->scoreboard_skb_hint ? tp->scoreboard_skb_hint | ||
2545 | : tcp_write_queue_head(sk); | ||
2546 | |||
2547 | tcp_for_write_queue_from(skb, sk) { | ||
2548 | if (skb == tcp_send_head(sk)) | ||
2549 | break; | ||
2550 | if (!tcp_skb_timedout(sk, skb)) | ||
2551 | break; | ||
2552 | |||
2553 | tcp_skb_mark_lost(tp, skb); | ||
2554 | } | ||
2555 | |||
2556 | tp->scoreboard_skb_hint = skb; | ||
2557 | |||
2558 | tcp_verify_left_out(tp); | ||
2559 | } | ||
2560 | } | 2575 | } |
2561 | 2576 | ||
2562 | /* CWND moderation, preventing bursts due to too big ACKs | 2577 | /* CWND moderation, preventing bursts due to too big ACKs |