aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c47
1 files changed, 32 insertions, 15 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index fec8a7a4dbaf..378ca8a086a3 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
@@ -2109,7 +2112,10 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
2109{ 2112{
2110 struct inet_connection_sock *icsk = inet_csk(sk); 2113 struct inet_connection_sock *icsk = inet_csk(sk);
2111 struct tcp_sock *tp = tcp_sk(sk); 2114 struct tcp_sock *tp = tcp_sk(sk);
2112 int is_dupack = (tp->snd_una == prior_snd_una && !(flag&FLAG_NOT_DUP)); 2115 int is_dupack = (tp->snd_una == prior_snd_una &&
2116 (!(flag&FLAG_NOT_DUP) ||
2117 ((flag&FLAG_DATA_SACKED) &&
2118 (tp->fackets_out > tp->reordering))));
2113 2119
2114 /* Some technical things: 2120 /* Some technical things:
2115 * 1. Reno does not count dupacks (sacked_out) automatically. */ 2121 * 1. Reno does not count dupacks (sacked_out) automatically. */
@@ -2260,7 +2266,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
2260 2266
2261 if (is_dupack || tcp_head_timedout(sk)) 2267 if (is_dupack || tcp_head_timedout(sk))
2262 tcp_update_scoreboard(sk); 2268 tcp_update_scoreboard(sk);
2263 tcp_cwnd_down(sk); 2269 tcp_cwnd_down(sk, flag);
2264 tcp_xmit_retransmit_queue(sk); 2270 tcp_xmit_retransmit_queue(sk);
2265} 2271}
2266 2272
@@ -2490,12 +2496,23 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
2490 tcp_ack_update_rtt(sk, acked, seq_rtt); 2496 tcp_ack_update_rtt(sk, acked, seq_rtt);
2491 tcp_ack_packets_out(sk); 2497 tcp_ack_packets_out(sk);
2492 2498
2493 /* Is the ACK triggering packet unambiguous? */ 2499 if (ca_ops->pkts_acked) {
2494 if (acked & FLAG_RETRANS_DATA_ACKED) 2500 s32 rtt_us = -1;
2495 last_ackt = net_invalid_timestamp(); 2501
2502 /* Is the ACK triggering packet unambiguous? */
2503 if (!(acked & FLAG_RETRANS_DATA_ACKED)) {
2504 /* High resolution needed and available? */
2505 if (ca_ops->flags & TCP_CONG_RTT_STAMP &&
2506 !ktime_equal(last_ackt,
2507 net_invalid_timestamp()))
2508 rtt_us = ktime_us_delta(ktime_get_real(),
2509 last_ackt);
2510 else if (seq_rtt > 0)
2511 rtt_us = jiffies_to_usecs(seq_rtt);
2512 }
2496 2513
2497 if (ca_ops->pkts_acked) 2514 ca_ops->pkts_acked(sk, pkts_acked, rtt_us);
2498 ca_ops->pkts_acked(sk, pkts_acked, last_ackt); 2515 }
2499 } 2516 }
2500 2517
2501#if FASTRETRANS_DEBUG > 0 2518#if FASTRETRANS_DEBUG > 0