aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2007-02-22 02:05:18 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:23:07 -0400
commit95c4922bf9330eb2c71b752359dd89c4e166f3c5 (patch)
tree97587ad7770afeca1196b3ef9d5b08bf4ee4fb95 /net
parent6408d206c7484615ecae54bf6474a02c94e9e862 (diff)
[TCP] FRTO: fixes fallback to conventional recovery
The FRTO detection did not care how ACK pattern affects to cwnd calculation of the conventional recovery. This caused incorrect setting of cwnd when the fallback becames necessary. The knowledge tcp_process_frto() has about the incoming ACK is now passed on to tcp_enter_frto_loss() in allowed_segments parameter that gives the number of segments that must be added to packets-in-flight while calculating the new cwnd. Instead of snd_una we use FLAG_DATA_ACKED in duplicate ACK detection because RFC4138 states (in Section 2.2): If the first acknowledgment after the RTO retransmission does not acknowledge all of the data that was retransmitted in step 1, the TCP sender reverts to the conventional RTO recovery. Otherwise, a malicious receiver acknowledging partial segments could cause the sender to declare the timeout spurious in a case where data was lost. If the next ACK after RTO is duplicate, we do not retransmit anything, which is equal to what conservative conventional recovery does in such case. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_input.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index e990d562f5e3..cc935c8a6aae 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1296,7 +1296,7 @@ void tcp_enter_frto(struct sock *sk)
1296 * which indicates that we should follow the traditional RTO recovery, 1296 * which indicates that we should follow the traditional RTO recovery,
1297 * i.e. mark everything lost and do go-back-N retransmission. 1297 * i.e. mark everything lost and do go-back-N retransmission.
1298 */ 1298 */
1299static void tcp_enter_frto_loss(struct sock *sk) 1299static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments)
1300{ 1300{
1301 struct tcp_sock *tp = tcp_sk(sk); 1301 struct tcp_sock *tp = tcp_sk(sk);
1302 struct sk_buff *skb; 1302 struct sk_buff *skb;
@@ -1326,7 +1326,7 @@ static void tcp_enter_frto_loss(struct sock *sk)
1326 } 1326 }
1327 tcp_sync_left_out(tp); 1327 tcp_sync_left_out(tp);
1328 1328
1329 tp->snd_cwnd = tp->frto_counter + tcp_packets_in_flight(tp)+1; 1329 tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments;
1330 tp->snd_cwnd_cnt = 0; 1330 tp->snd_cwnd_cnt = 0;
1331 tp->snd_cwnd_stamp = tcp_time_stamp; 1331 tp->snd_cwnd_stamp = tcp_time_stamp;
1332 tp->undo_marker = 0; 1332 tp->undo_marker = 0;
@@ -2527,6 +2527,11 @@ static void tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
2527 if (flag&FLAG_DATA_ACKED) 2527 if (flag&FLAG_DATA_ACKED)
2528 inet_csk(sk)->icsk_retransmits = 0; 2528 inet_csk(sk)->icsk_retransmits = 0;
2529 2529
2530 if (!before(tp->snd_una, tp->frto_highmark)) {
2531 tcp_enter_frto_loss(sk, tp->frto_counter + 1);
2532 return;
2533 }
2534
2530 /* RFC4138 shortcoming in step 2; should also have case c): ACK isn't 2535 /* RFC4138 shortcoming in step 2; should also have case c): ACK isn't
2531 * duplicate nor advances window, e.g., opposite dir data, winupdate 2536 * duplicate nor advances window, e.g., opposite dir data, winupdate
2532 */ 2537 */
@@ -2534,9 +2539,8 @@ static void tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
2534 !(flag&FLAG_FORWARD_PROGRESS)) 2539 !(flag&FLAG_FORWARD_PROGRESS))
2535 return; 2540 return;
2536 2541
2537 if (tp->snd_una == prior_snd_una || 2542 if (!(flag&FLAG_DATA_ACKED)) {
2538 !before(tp->snd_una, tp->frto_highmark)) { 2543 tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 0 : 3));
2539 tcp_enter_frto_loss(sk);
2540 return; 2544 return;
2541 } 2545 }
2542 2546