diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 44 | 
1 files changed, 33 insertions, 11 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 9c04a9c8be9d..2e39cb881e20 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2782,13 +2782,37 @@ static void tcp_mtup_probe_success(struct sock *sk)  	NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMTUPSUCCESS);  } +/* Sometimes we deduce that packets have been dropped due to reasons other than + * congestion, like path MTU reductions or failed client TFO attempts. In these + * cases we call this function to retransmit as many packets as cwnd allows, + * without reducing cwnd. Given that retransmits will set retrans_stamp to a + * non-zero value (and may do so in a later calling context due to TSQ), we + * also enter CA_Loss so that we track when all retransmitted packets are ACKed + * and clear retrans_stamp when that happens (to ensure later recurring RTOs + * are using the correct retrans_stamp and don't declare ETIMEDOUT + * prematurely). + */ +static void tcp_non_congestion_loss_retransmit(struct sock *sk) +{ +	const struct inet_connection_sock *icsk = inet_csk(sk); +	struct tcp_sock *tp = tcp_sk(sk); + +	if (icsk->icsk_ca_state != TCP_CA_Loss) { +		tp->high_seq = tp->snd_nxt; +		tp->snd_ssthresh = tcp_current_ssthresh(sk); +		tp->prior_ssthresh = 0; +		tp->undo_marker = 0; +		tcp_set_ca_state(sk, TCP_CA_Loss); +	} +	tcp_xmit_retransmit_queue(sk); +} +  /* Do a simple retransmit without using the backoff mechanisms in   * tcp_timer. This is used for path mtu discovery.   * The socket is already locked here.   */  void tcp_simple_retransmit(struct sock *sk)  { -	const struct inet_connection_sock *icsk = inet_csk(sk);  	struct tcp_sock *tp = tcp_sk(sk);  	struct sk_buff *skb;  	int mss; @@ -2828,14 +2852,7 @@ void tcp_simple_retransmit(struct sock *sk)  	 * in network, but units changed and effective  	 * cwnd/ssthresh really reduced now.  	 */ -	if (icsk->icsk_ca_state != TCP_CA_Loss) { -		tp->high_seq = tp->snd_nxt; -		tp->snd_ssthresh = tcp_current_ssthresh(sk); -		tp->prior_ssthresh = 0; -		tp->undo_marker = 0; -		tcp_set_ca_state(sk, TCP_CA_Loss); -	} -	tcp_xmit_retransmit_queue(sk); +	tcp_non_congestion_loss_retransmit(sk);  }  EXPORT_SYMBOL(tcp_simple_retransmit); @@ -6295,7 +6312,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,  			tp->fastopen_client_fail = TFO_DATA_NOT_ACKED;  		skb_rbtree_walk_from(data)  			 tcp_mark_skb_lost(sk, data); -		tcp_xmit_retransmit_queue(sk); +		tcp_non_congestion_loss_retransmit(sk);  		NET_INC_STATS(sock_net(sk),  				LINUX_MIB_TCPFASTOPENACTIVEFAIL);  		return true; @@ -7256,7 +7273,12 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,  		tcp_rsk(req)->tfo_listener = false;  		if (!want_cookie) {  			req->timeout = tcp_timeout_init((struct sock *)req); -			inet_csk_reqsk_queue_hash_add(sk, req, req->timeout); +			if (unlikely(!inet_csk_reqsk_queue_hash_add(sk, req, +								    req->timeout))) { +				reqsk_free(req); +				return 0; +			} +  		}  		af_ops->send_synack(sk, dst, &fl, req, &foc,  				    !want_cookie ? TCP_SYNACK_NORMAL :  |