aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2007-07-30 22:48:37 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-31 05:28:30 -0400
commit1e757f9996114f713a79d3fbcd08739efcfc5c34 (patch)
tree169b4399c718ec6bf178ad1d77d8b8bf27d1d714
parent143cf35324548df54563b19d0444e0fe170027f8 (diff)
[TCP]: Fix ratehalving with bidirectional flows
Actually, the ratehalving seems to work too well, as cwnd is reduced on every second ACK even though the packets in flight remains unchanged. Recoveries in a bidirectional flows suffer quite badly because of this, both NewReno and SACK are affected. After this patch, rate halving is performed for ACK only if packets in flight was supposedly changed too. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/tcp_input.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 4b255fe999d9..41163ddc312c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1851,19 +1851,22 @@ static inline u32 tcp_cwnd_min(const struct sock *sk)
1851} 1851}
1852 1852
1853/* Decrease cwnd each second ack. */ 1853/* Decrease cwnd each second ack. */
1854static void tcp_cwnd_down(struct sock *sk) 1854static void tcp_cwnd_down(struct sock *sk, int flag)
1855{ 1855{
1856 struct tcp_sock *tp = tcp_sk(sk); 1856 struct tcp_sock *tp = tcp_sk(sk);
1857 int decr = tp->snd_cwnd_cnt + 1; 1857 int decr = tp->snd_cwnd_cnt + 1;
1858 1858
1859 tp->snd_cwnd_cnt = decr&1; 1859 if ((flag&FLAG_FORWARD_PROGRESS) ||
1860 decr >>= 1; 1860 (IsReno(tp) && !(flag&FLAG_NOT_DUP))) {
1861 tp->snd_cwnd_cnt = decr&1;
1862 decr >>= 1;
1861 1863
1862 if (decr && tp->snd_cwnd > tcp_cwnd_min(sk)) 1864 if (decr && tp->snd_cwnd > tcp_cwnd_min(sk))
1863 tp->snd_cwnd -= decr; 1865 tp->snd_cwnd -= decr;
1864 1866
1865 tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1); 1867 tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1);
1866 tp->snd_cwnd_stamp = tcp_time_stamp; 1868 tp->snd_cwnd_stamp = tcp_time_stamp;
1869 }
1867} 1870}
1868 1871
1869/* Nothing was retransmitted or returned timestamp is less 1872/* Nothing was retransmitted or returned timestamp is less
@@ -2060,7 +2063,7 @@ static void tcp_try_to_open(struct sock *sk, int flag)
2060 } 2063 }
2061 tcp_moderate_cwnd(tp); 2064 tcp_moderate_cwnd(tp);
2062 } else { 2065 } else {
2063 tcp_cwnd_down(sk); 2066 tcp_cwnd_down(sk, flag);
2064 } 2067 }
2065} 2068}
2066 2069
@@ -2260,7 +2263,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
2260 2263
2261 if (is_dupack || tcp_head_timedout(sk)) 2264 if (is_dupack || tcp_head_timedout(sk))
2262 tcp_update_scoreboard(sk); 2265 tcp_update_scoreboard(sk);
2263 tcp_cwnd_down(sk); 2266 tcp_cwnd_down(sk, flag);
2264 tcp_xmit_retransmit_queue(sk); 2267 tcp_xmit_retransmit_queue(sk);
2265} 2268}
2266 2269