diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 63 | 
1 files changed, 36 insertions, 27 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 39c393cc0fd3..659d1baefb2b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -126,7 +126,8 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2;  #define REXMIT_LOST	1 /* retransmit packets marked lost */  #define REXMIT_NEW	2 /* FRTO-style transmit of unsent/new packets */ -static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb) +static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb, +			     unsigned int len)  {  	static bool __once __read_mostly; @@ -137,8 +138,9 @@ static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb)  		rcu_read_lock();  		dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif); -		pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", -			dev ? dev->name : "Unknown driver"); +		if (!dev || len >= dev->mtu) +			pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", +				dev ? dev->name : "Unknown driver");  		rcu_read_unlock();  	}  } @@ -161,8 +163,10 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)  	if (len >= icsk->icsk_ack.rcv_mss) {  		icsk->icsk_ack.rcv_mss = min_t(unsigned int, len,  					       tcp_sk(sk)->advmss); -		if (unlikely(icsk->icsk_ack.rcv_mss != len)) -			tcp_gro_dev_warn(sk, skb); +		/* Account for possibly-removed options */ +		if (unlikely(len > icsk->icsk_ack.rcv_mss + +				   MAX_TCP_OPTION_SPACE)) +			tcp_gro_dev_warn(sk, skb, len);  	} else {  		/* Otherwise, we make more careful check taking into account,  		 * that SACKs block is variable. @@ -874,22 +878,11 @@ static void tcp_update_reordering(struct sock *sk, const int metric,  				  const int ts)  {  	struct tcp_sock *tp = tcp_sk(sk); -	if (metric > tp->reordering) { -		int mib_idx; +	int mib_idx; +	if (metric > tp->reordering) {  		tp->reordering = min(sysctl_tcp_max_reordering, metric); -		/* This exciting event is worth to be remembered. 8) */ -		if (ts) -			mib_idx = LINUX_MIB_TCPTSREORDER; -		else if (tcp_is_reno(tp)) -			mib_idx = LINUX_MIB_TCPRENOREORDER; -		else if (tcp_is_fack(tp)) -			mib_idx = LINUX_MIB_TCPFACKREORDER; -		else -			mib_idx = LINUX_MIB_TCPSACKREORDER; - -		NET_INC_STATS(sock_net(sk), mib_idx);  #if FASTRETRANS_DEBUG > 1  		pr_debug("Disorder%d %d %u f%u s%u rr%d\n",  			 tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state, @@ -902,6 +895,18 @@ static void tcp_update_reordering(struct sock *sk, const int metric,  	}  	tp->rack.reord = 1; + +	/* This exciting event is worth to be remembered. 8) */ +	if (ts) +		mib_idx = LINUX_MIB_TCPTSREORDER; +	else if (tcp_is_reno(tp)) +		mib_idx = LINUX_MIB_TCPRENOREORDER; +	else if (tcp_is_fack(tp)) +		mib_idx = LINUX_MIB_TCPFACKREORDER; +	else +		mib_idx = LINUX_MIB_TCPSACKREORDER; + +	NET_INC_STATS(sock_net(sk), mib_idx);  }  /* This must be called before lost_out is incremented */ @@ -1930,6 +1935,7 @@ void tcp_enter_loss(struct sock *sk)  	struct tcp_sock *tp = tcp_sk(sk);  	struct net *net = sock_net(sk);  	struct sk_buff *skb; +	bool new_recovery = icsk->icsk_ca_state < TCP_CA_Recovery;  	bool is_reneg;			/* is receiver reneging on SACKs? */  	bool mark_lost; @@ -1989,15 +1995,18 @@ void tcp_enter_loss(struct sock *sk)  	tp->high_seq = tp->snd_nxt;  	tcp_ecn_queue_cwr(tp); -	/* F-RTO RFC5682 sec 3.1 step 1 mandates to disable F-RTO -	 * if a previous recovery is underway, otherwise it may incorrectly -	 * call a timeout spurious if some previously retransmitted packets -	 * are s/acked (sec 3.2). We do not apply that retriction since -	 * retransmitted skbs are permanently tagged with TCPCB_EVER_RETRANS -	 * so FLAG_ORIG_SACK_ACKED is always correct. But we do disable F-RTO -	 * on PTMU discovery to avoid sending new data. +	/* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous +	 * loss recovery is underway except recurring timeout(s) on +	 * the same SND.UNA (sec 3.2). Disable F-RTO on path MTU probing +	 * +	 * In theory F-RTO can be used repeatedly during loss recovery. +	 * In practice this interacts badly with broken middle-boxes that +	 * falsely raise the receive window, which results in repeated +	 * timeouts and stop-and-go behavior.  	 */ -	tp->frto = sysctl_tcp_frto && !inet_csk(sk)->icsk_mtup.probe_size; +	tp->frto = sysctl_tcp_frto && +		   (new_recovery || icsk->icsk_retransmits) && +		   !inet_csk(sk)->icsk_mtup.probe_size;  }  /* If ACK arrived pointing to a remembered SACK, it means that our @@ -5541,6 +5550,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)  	struct inet_connection_sock *icsk = inet_csk(sk);  	tcp_set_state(sk, TCP_ESTABLISHED); +	icsk->icsk_ack.lrcvtime = tcp_time_stamp;  	if (skb) {  		icsk->icsk_af_ops->sk_rx_dst_set(sk, skb); @@ -5759,7 +5769,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,  			 * to stand against the temptation 8)     --ANK  			 */  			inet_csk_schedule_ack(sk); -			icsk->icsk_ack.lrcvtime = tcp_time_stamp;  			tcp_enter_quickack_mode(sk);  			inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,  						  TCP_DELACK_MAX, TCP_RTO_MAX);  | 
