diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 051f0f815f17..7641b2761a14 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
| @@ -1265,20 +1265,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
| 1265 | return flag; | 1265 | return flag; |
| 1266 | } | 1266 | } |
| 1267 | 1267 | ||
| 1268 | /* F-RTO can only be used if these conditions are satisfied: | 1268 | /* F-RTO can only be used if TCP has never retransmitted anything other than |
| 1269 | * - there must be some unsent new data | 1269 | * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here) |
| 1270 | * - the advertised window should allow sending it | ||
| 1271 | * - TCP has never retransmitted anything other than head (SACK enhanced | ||
| 1272 | * variant from Appendix B of RFC4138 is more robust here) | ||
| 1273 | */ | 1270 | */ |
| 1274 | int tcp_use_frto(struct sock *sk) | 1271 | int tcp_use_frto(struct sock *sk) |
| 1275 | { | 1272 | { |
| 1276 | const struct tcp_sock *tp = tcp_sk(sk); | 1273 | const struct tcp_sock *tp = tcp_sk(sk); |
| 1277 | struct sk_buff *skb; | 1274 | struct sk_buff *skb; |
| 1278 | 1275 | ||
| 1279 | if (!sysctl_tcp_frto || !tcp_send_head(sk) || | 1276 | if (!sysctl_tcp_frto) |
| 1280 | after(TCP_SKB_CB(tcp_send_head(sk))->end_seq, | ||
| 1281 | tp->snd_una + tp->snd_wnd)) | ||
| 1282 | return 0; | 1277 | return 0; |
| 1283 | 1278 | ||
| 1284 | if (IsSackFrto()) | 1279 | if (IsSackFrto()) |
| @@ -2642,7 +2637,9 @@ static void tcp_undo_spur_to_response(struct sock *sk, int flag) | |||
| 2642 | * algorithm is not part of the F-RTO detection algorithm | 2637 | * algorithm is not part of the F-RTO detection algorithm |
| 2643 | * given in RFC4138 but can be selected separately). | 2638 | * given in RFC4138 but can be selected separately). |
| 2644 | * Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss | 2639 | * Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss |
| 2645 | * and TCP falls back to conventional RTO recovery. | 2640 | * and TCP falls back to conventional RTO recovery. F-RTO allows overriding |
| 2641 | * of Nagle, this is done using frto_counter states 2 and 3, when a new data | ||
| 2642 | * segment of any size sent during F-RTO, state 2 is upgraded to 3. | ||
| 2646 | * | 2643 | * |
| 2647 | * Rationale: if the RTO was spurious, new ACKs should arrive from the | 2644 | * Rationale: if the RTO was spurious, new ACKs should arrive from the |
| 2648 | * original window even after we transmit two new data segments. | 2645 | * original window even after we transmit two new data segments. |
| @@ -2671,7 +2668,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | |||
| 2671 | inet_csk(sk)->icsk_retransmits = 0; | 2668 | inet_csk(sk)->icsk_retransmits = 0; |
| 2672 | 2669 | ||
| 2673 | if (!before(tp->snd_una, tp->frto_highmark)) { | 2670 | if (!before(tp->snd_una, tp->frto_highmark)) { |
| 2674 | tcp_enter_frto_loss(sk, tp->frto_counter + 1, flag); | 2671 | tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); |
| 2675 | return 1; | 2672 | return 1; |
| 2676 | } | 2673 | } |
| 2677 | 2674 | ||
| @@ -2697,7 +2694,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | |||
| 2697 | return 1; | 2694 | return 1; |
| 2698 | } | 2695 | } |
| 2699 | 2696 | ||
| 2700 | if ((tp->frto_counter == 2) && | 2697 | if ((tp->frto_counter >= 2) && |
| 2701 | (!(flag&FLAG_FORWARD_PROGRESS) || | 2698 | (!(flag&FLAG_FORWARD_PROGRESS) || |
| 2702 | ((flag&FLAG_DATA_SACKED) && !(flag&FLAG_ONLY_ORIG_SACKED)))) { | 2699 | ((flag&FLAG_DATA_SACKED) && !(flag&FLAG_ONLY_ORIG_SACKED)))) { |
| 2703 | /* RFC4138 shortcoming (see comment above) */ | 2700 | /* RFC4138 shortcoming (see comment above) */ |
| @@ -2710,10 +2707,19 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | |||
| 2710 | } | 2707 | } |
| 2711 | 2708 | ||
| 2712 | if (tp->frto_counter == 1) { | 2709 | if (tp->frto_counter == 1) { |
| 2710 | /* Sending of the next skb must be allowed or no FRTO */ | ||
| 2711 | if (!tcp_send_head(sk) || | ||
| 2712 | after(TCP_SKB_CB(tcp_send_head(sk))->end_seq, | ||
| 2713 | tp->snd_una + tp->snd_wnd)) { | ||
| 2714 | tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), | ||
| 2715 | flag); | ||
| 2716 | return 1; | ||
| 2717 | } | ||
| 2718 | |||
| 2713 | tp->snd_cwnd = tcp_packets_in_flight(tp) + 2; | 2719 | tp->snd_cwnd = tcp_packets_in_flight(tp) + 2; |
| 2714 | tp->frto_counter = 2; | 2720 | tp->frto_counter = 2; |
| 2715 | return 1; | 2721 | return 1; |
| 2716 | } else /* frto_counter == 2 */ { | 2722 | } else { |
| 2717 | switch (sysctl_tcp_frto_response) { | 2723 | switch (sysctl_tcp_frto_response) { |
| 2718 | case 2: | 2724 | case 2: |
| 2719 | tcp_undo_spur_to_response(sk, flag); | 2725 | tcp_undo_spur_to_response(sk, flag); |
