|
@@ -1236,22 +1236,22 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
|
|
|
return flag;
|
|
|
}
|
|
|
|
|
|
+/* F-RTO can only be used if these conditions are satisfied:
|
|
|
+ * - there must be some unsent new data
|
|
|
+ * - the advertised window should allow sending it
|
|
|
+ */
|
|
|
int tcp_use_frto(const struct sock *sk)
|
|
|
{
|
|
|
const struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
|
|
- /* F-RTO must be activated in sysctl and there must be some
|
|
|
- * unsent new data, and the advertised window should allow
|
|
|
- * sending it.
|
|
|
- */
|
|
|
return (sysctl_tcp_frto && sk->sk_send_head &&
|
|
|
!after(TCP_SKB_CB(sk->sk_send_head)->end_seq,
|
|
|
tp->snd_una + tp->snd_wnd));
|
|
|
}
|
|
|
|
|
|
-/* RTO occurred, but do not yet enter loss state. Instead, transmit two new
|
|
|
- * segments to see from the next ACKs whether any data was really missing.
|
|
|
- * If the RTO was spurious, new ACKs should arrive.
|
|
|
+/* RTO occurred, but do not yet enter Loss state. Instead, defer RTO
|
|
|
+ * recovery a bit and use heuristics in tcp_process_frto() to detect if
|
|
|
+ * the RTO was spurious.
|
|
|
*/
|
|
|
void tcp_enter_frto(struct sock *sk)
|
|
|
{
|
|
@@ -2489,6 +2489,30 @@ static void tcp_conservative_spur_to_response(struct tcp_sock *tp)
|
|
|
tcp_moderate_cwnd(tp);
|
|
|
}
|
|
|
|
|
|
+/* F-RTO spurious RTO detection algorithm (RFC4138)
|
|
|
+ *
|
|
|
+ * F-RTO affects during two new ACKs following RTO. State (ACK number) is kept
|
|
|
+ * in frto_counter. When ACK advances window (but not to or beyond highest
|
|
|
+ * sequence sent before RTO):
|
|
|
+ * On First ACK, send two new segments out.
|
|
|
+ * On Second ACK, RTO was likely spurious. Do spurious response (response
|
|
|
+ * algorithm is not part of the F-RTO detection algorithm
|
|
|
+ * given in RFC4138 but can be selected separately).
|
|
|
+ * Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss
|
|
|
+ * and TCP falls back to conventional RTO recovery.
|
|
|
+ *
|
|
|
+ * Rationale: if the RTO was spurious, new ACKs should arrive from the
|
|
|
+ * original window even after we transmit two new data segments.
|
|
|
+ *
|
|
|
+ * F-RTO is implemented (mainly) in four functions:
|
|
|
+ * - tcp_use_frto() is used to determine if TCP is can use F-RTO
|
|
|
+ * - tcp_enter_frto() prepares TCP state on RTO if F-RTO is used, it is
|
|
|
+ * called when tcp_use_frto() showed green light
|
|
|
+ * - tcp_process_frto() handles incoming ACKs during F-RTO algorithm
|
|
|
+ * - tcp_enter_frto_loss() is called if there is not enough evidence
|
|
|
+ * to prove that the RTO is indeed spurious. It transfers the control
|
|
|
+ * from F-RTO to the conventional RTO recovery
|
|
|
+ */
|
|
|
static void tcp_process_frto(struct sock *sk, u32 prior_snd_una)
|
|
|
{
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
@@ -2497,25 +2521,16 @@ static void tcp_process_frto(struct sock *sk, u32 prior_snd_una)
|
|
|
|
|
|
if (tp->snd_una == prior_snd_una ||
|
|
|
!before(tp->snd_una, tp->frto_highmark)) {
|
|
|
- /* RTO was caused by loss, start retransmitting in
|
|
|
- * go-back-N slow start
|
|
|
- */
|
|
|
tcp_enter_frto_loss(sk);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (tp->frto_counter == 1) {
|
|
|
- /* First ACK after RTO advances the window: allow two new
|
|
|
- * segments out.
|
|
|
- */
|
|
|
tp->snd_cwnd = tcp_packets_in_flight(tp) + 2;
|
|
|
- } else {
|
|
|
+ } else /* frto_counter == 2 */ {
|
|
|
tcp_conservative_spur_to_response(tp);
|
|
|
}
|
|
|
|
|
|
- /* F-RTO affects on two new ACKs following RTO.
|
|
|
- * At latest on third ACK the TCP behavior is back to normal.
|
|
|
- */
|
|
|
tp->frto_counter = (tp->frto_counter + 1) % 3;
|
|
|
}
|
|
|
|