diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 22 | 
1 files changed, 21 insertions, 1 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a27b9c0e27c0..c71d49ce0c93 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -128,6 +128,23 @@ 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 bool __once __read_mostly; + +	if (!__once) { +		struct net_device *dev; + +		__once = true; + +		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"); +		rcu_read_unlock(); +	} +} +  /* Adapt the MSS value used to make delayed ack decision to the   * real world.   */ @@ -144,7 +161,10 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)  	 */  	len = skb_shinfo(skb)->gso_size ? : skb->len;  	if (len >= icsk->icsk_ack.rcv_mss) { -		icsk->icsk_ack.rcv_mss = len; +		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);  	} else {  		/* Otherwise, we make more careful check taking into account,  		 * that SACKs block is variable.  | 
