diff options
author | Yuchung Cheng <ycheng@google.com> | 2015-05-18 15:31:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-19 16:36:57 -0400 |
commit | da34ac7626b571d262f92b93f11eb32dd58d9c4e (patch) | |
tree | e3c4f0b85dd67290c942fafaaed936ef4f73d234 /net/ipv4/tcp_input.c | |
parent | 33b4b015e1a1ca7a8fdce40af5e71642a8ea355c (diff) |
tcp: only undo on partial ACKs in CA_Loss
Undo based on TCP timestamps should only happen on ACKs that advance
SND_UNA, according to the Eifel algorithm in RFC 3522:
Section 3.2:
(4) If the value of the Timestamp Echo Reply field of the
acceptable ACK's Timestamps option is smaller than the
value of RetransmitTS, then proceed to step (5),
Section Terminology:
We use the term 'acceptable ACK' as defined in [RFC793]. That is an
ACK that acknowledges previously unacknowledged data.
This is because upon receiving an out-of-order packet, the receiver
returns the last timestamp that advances RCV_NXT, not the current
timestamp of the packet in the DUPACK. Without checking the flag,
the DUPACK will cause tcp_packet_delayed() to return true and
tcp_try_undo_loss() will revert cwnd reduction.
Note that we check the condition in CA_Recovery already by only
calling tcp_try_undo_partial() if FLAG_SND_UNA_ADVANCED is set or
tcp_try_undo_recovery() if snd_una crosses high_seq.
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Signed-off-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.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bc790ea9960f..9faf775a8c4a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2698,11 +2698,16 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack) | |||
2698 | struct tcp_sock *tp = tcp_sk(sk); | 2698 | struct tcp_sock *tp = tcp_sk(sk); |
2699 | bool recovered = !before(tp->snd_una, tp->high_seq); | 2699 | bool recovered = !before(tp->snd_una, tp->high_seq); |
2700 | 2700 | ||
2701 | if ((flag & FLAG_SND_UNA_ADVANCED) && | ||
2702 | tcp_try_undo_loss(sk, false)) | ||
2703 | return; | ||
2704 | |||
2701 | if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */ | 2705 | if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */ |
2702 | /* Step 3.b. A timeout is spurious if not all data are | 2706 | /* Step 3.b. A timeout is spurious if not all data are |
2703 | * lost, i.e., never-retransmitted data are (s)acked. | 2707 | * lost, i.e., never-retransmitted data are (s)acked. |
2704 | */ | 2708 | */ |
2705 | if (tcp_try_undo_loss(sk, flag & FLAG_ORIG_SACK_ACKED)) | 2709 | if ((flag & FLAG_ORIG_SACK_ACKED) && |
2710 | tcp_try_undo_loss(sk, true)) | ||
2706 | return; | 2711 | return; |
2707 | 2712 | ||
2708 | if (after(tp->snd_nxt, tp->high_seq) && | 2713 | if (after(tp->snd_nxt, tp->high_seq) && |
@@ -2732,8 +2737,6 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack) | |||
2732 | else if (flag & FLAG_SND_UNA_ADVANCED) | 2737 | else if (flag & FLAG_SND_UNA_ADVANCED) |
2733 | tcp_reset_reno_sack(tp); | 2738 | tcp_reset_reno_sack(tp); |
2734 | } | 2739 | } |
2735 | if (tcp_try_undo_loss(sk, false)) | ||
2736 | return; | ||
2737 | tcp_xmit_retransmit_queue(sk); | 2740 | tcp_xmit_retransmit_queue(sk); |
2738 | } | 2741 | } |
2739 | 2742 | ||