diff options
-rw-r--r-- | include/net/tcp.h | 5 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 13 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 6 |
3 files changed, 17 insertions, 7 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index c6ecd455edab..ef8f9d4dae85 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -1199,9 +1199,14 @@ static inline struct sk_buff *tcp_send_head(struct sock *sk) | |||
1199 | 1199 | ||
1200 | static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb) | 1200 | static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb) |
1201 | { | 1201 | { |
1202 | struct tcp_sock *tp = tcp_sk(sk); | ||
1203 | |||
1202 | sk->sk_send_head = skb->next; | 1204 | sk->sk_send_head = skb->next; |
1203 | if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue) | 1205 | if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue) |
1204 | sk->sk_send_head = NULL; | 1206 | sk->sk_send_head = NULL; |
1207 | /* Don't override Nagle indefinately with F-RTO */ | ||
1208 | if (tp->frto_counter == 2) | ||
1209 | tp->frto_counter = 3; | ||
1205 | } | 1210 | } |
1206 | 1211 | ||
1207 | static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked) | 1212 | static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked) |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6b669898b197..7641b2761a14 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2637,7 +2637,9 @@ static void tcp_undo_spur_to_response(struct sock *sk, int flag) | |||
2637 | * algorithm is not part of the F-RTO detection algorithm | 2637 | * algorithm is not part of the F-RTO detection algorithm |
2638 | * given in RFC4138 but can be selected separately). | 2638 | * given in RFC4138 but can be selected separately). |
2639 | * 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 |
2640 | * 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. | ||
2641 | * | 2643 | * |
2642 | * 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 |
2643 | * original window even after we transmit two new data segments. | 2645 | * original window even after we transmit two new data segments. |
@@ -2666,7 +2668,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | |||
2666 | inet_csk(sk)->icsk_retransmits = 0; | 2668 | inet_csk(sk)->icsk_retransmits = 0; |
2667 | 2669 | ||
2668 | if (!before(tp->snd_una, tp->frto_highmark)) { | 2670 | if (!before(tp->snd_una, tp->frto_highmark)) { |
2669 | tcp_enter_frto_loss(sk, tp->frto_counter + 1, flag); | 2671 | tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); |
2670 | return 1; | 2672 | return 1; |
2671 | } | 2673 | } |
2672 | 2674 | ||
@@ -2692,7 +2694,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | |||
2692 | return 1; | 2694 | return 1; |
2693 | } | 2695 | } |
2694 | 2696 | ||
2695 | if ((tp->frto_counter == 2) && | 2697 | if ((tp->frto_counter >= 2) && |
2696 | (!(flag&FLAG_FORWARD_PROGRESS) || | 2698 | (!(flag&FLAG_FORWARD_PROGRESS) || |
2697 | ((flag&FLAG_DATA_SACKED) && !(flag&FLAG_ONLY_ORIG_SACKED)))) { | 2699 | ((flag&FLAG_DATA_SACKED) && !(flag&FLAG_ONLY_ORIG_SACKED)))) { |
2698 | /* RFC4138 shortcoming (see comment above) */ | 2700 | /* RFC4138 shortcoming (see comment above) */ |
@@ -2709,14 +2711,15 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | |||
2709 | if (!tcp_send_head(sk) || | 2711 | if (!tcp_send_head(sk) || |
2710 | after(TCP_SKB_CB(tcp_send_head(sk))->end_seq, | 2712 | after(TCP_SKB_CB(tcp_send_head(sk))->end_seq, |
2711 | tp->snd_una + tp->snd_wnd)) { | 2713 | tp->snd_una + tp->snd_wnd)) { |
2712 | tcp_enter_frto_loss(sk, tp->frto_counter + 1, flag); | 2714 | tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), |
2715 | flag); | ||
2713 | return 1; | 2716 | return 1; |
2714 | } | 2717 | } |
2715 | 2718 | ||
2716 | tp->snd_cwnd = tcp_packets_in_flight(tp) + 2; | 2719 | tp->snd_cwnd = tcp_packets_in_flight(tp) + 2; |
2717 | tp->frto_counter = 2; | 2720 | tp->frto_counter = 2; |
2718 | return 1; | 2721 | return 1; |
2719 | } else /* frto_counter == 2 */ { | 2722 | } else { |
2720 | switch (sysctl_tcp_frto_response) { | 2723 | switch (sysctl_tcp_frto_response) { |
2721 | case 2: | 2724 | case 2: |
2722 | tcp_undo_spur_to_response(sk, flag); | 2725 | tcp_undo_spur_to_response(sk, flag); |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b5fa3c19afee..0faacf9c419d 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -1035,8 +1035,10 @@ static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb, | |||
1035 | if (nonagle & TCP_NAGLE_PUSH) | 1035 | if (nonagle & TCP_NAGLE_PUSH) |
1036 | return 1; | 1036 | return 1; |
1037 | 1037 | ||
1038 | /* Don't use the nagle rule for urgent data (or for the final FIN). */ | 1038 | /* Don't use the nagle rule for urgent data (or for the final FIN). |
1039 | if (tp->urg_mode || | 1039 | * Nagle can be ignored during F-RTO too (see RFC4138). |
1040 | */ | ||
1041 | if (tp->urg_mode || (tp->frto_counter == 2) || | ||
1040 | (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)) | 1042 | (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)) |
1041 | return 1; | 1043 | return 1; |
1042 | 1044 | ||