diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 46 | 
1 files changed, 25 insertions, 21 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bef9f04c22ba..ea0d2183df4b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -880,6 +880,11 @@ static void tcp_init_metrics(struct sock *sk)  		tp->snd_ssthresh = dst_metric(dst, RTAX_SSTHRESH);  		if (tp->snd_ssthresh > tp->snd_cwnd_clamp)  			tp->snd_ssthresh = tp->snd_cwnd_clamp; +	} else { +		/* ssthresh may have been reduced unnecessarily during. +		 * 3WHS. Restore it back to its initial default. +		 */ +		tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;  	}  	if (dst_metric(dst, RTAX_REORDERING) &&  	    tp->reordering != dst_metric(dst, RTAX_REORDERING)) { @@ -887,10 +892,7 @@ static void tcp_init_metrics(struct sock *sk)  		tp->reordering = dst_metric(dst, RTAX_REORDERING);  	} -	if (dst_metric(dst, RTAX_RTT) == 0) -		goto reset; - -	if (!tp->srtt && dst_metric_rtt(dst, RTAX_RTT) < (TCP_TIMEOUT_INIT << 3)) +	if (dst_metric(dst, RTAX_RTT) == 0 || tp->srtt == 0)  		goto reset;  	/* Initial rtt is determined from SYN,SYN-ACK. @@ -916,19 +918,26 @@ static void tcp_init_metrics(struct sock *sk)  		tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));  	}  	tcp_set_rto(sk); -	if (inet_csk(sk)->icsk_rto < TCP_TIMEOUT_INIT && !tp->rx_opt.saw_tstamp) {  reset: -		/* Play conservative. If timestamps are not -		 * supported, TCP will fail to recalculate correct -		 * rtt, if initial rto is too small. FORGET ALL AND RESET! +	if (tp->srtt == 0) { +		/* RFC2988bis: We've failed to get a valid RTT sample from +		 * 3WHS. This is most likely due to retransmission, +		 * including spurious one. Reset the RTO back to 3secs +		 * from the more aggressive 1sec to avoid more spurious +		 * retransmission.  		 */ -		if (!tp->rx_opt.saw_tstamp && tp->srtt) { -			tp->srtt = 0; -			tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_INIT; -			inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT; -		} +		tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_FALLBACK; +		inet_csk(sk)->icsk_rto = TCP_TIMEOUT_FALLBACK;  	} -	tp->snd_cwnd = tcp_init_cwnd(tp, dst); +	/* Cut cwnd down to 1 per RFC5681 if SYN or SYN-ACK has been +	 * retransmitted. In light of RFC2988bis' more aggressive 1sec +	 * initRTO, we only reset cwnd when more than 1 SYN/SYN-ACK +	 * retransmission has occurred. +	 */ +	if (tp->total_retrans > 1) +		tp->snd_cwnd = 1; +	else +		tp->snd_cwnd = tcp_init_cwnd(tp, dst);  	tp->snd_cwnd_stamp = tcp_time_stamp;  } @@ -3112,12 +3121,13 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)  	tcp_xmit_retransmit_queue(sk);  } -static void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt) +void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt)  {  	tcp_rtt_estimator(sk, seq_rtt);  	tcp_set_rto(sk);  	inet_csk(sk)->icsk_backoff = 0;  } +EXPORT_SYMBOL(tcp_valid_rtt_meas);  /* Read draft-ietf-tcplw-high-performance before mucking   * with this code. (Supersedes RFC1323) @@ -5806,12 +5816,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,  					      tp->rx_opt.snd_wscale;  				tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); -				/* tcp_ack considers this ACK as duplicate -				 * and does not calculate rtt. -				 * Force it here. -				 */ -				tcp_ack_update_rtt(sk, 0, 0); -  				if (tp->rx_opt.tstamp_ok)  					tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;  |