diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 55 | 
1 files changed, 37 insertions, 18 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a27b9c0e27c0..6c790754ae3e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -85,6 +85,7 @@ int sysctl_tcp_dsack __read_mostly = 1;  int sysctl_tcp_app_win __read_mostly = 31;  int sysctl_tcp_adv_win_scale __read_mostly = 1;  EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); +EXPORT_SYMBOL(sysctl_tcp_timestamps);  /* rfc5961 challenge ack rate limiting */  int sysctl_tcp_challenge_ack_limit = 1000; @@ -128,6 +129,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 +162,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. @@ -2394,10 +2415,7 @@ static void tcp_undo_cwnd_reduction(struct sock *sk, bool unmark_loss)  	if (tp->prior_ssthresh) {  		const struct inet_connection_sock *icsk = inet_csk(sk); -		if (icsk->icsk_ca_ops->undo_cwnd) -			tp->snd_cwnd = icsk->icsk_ca_ops->undo_cwnd(sk); -		else -			tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh << 1); +		tp->snd_cwnd = icsk->icsk_ca_ops->undo_cwnd(sk);  		if (tp->prior_ssthresh > tp->snd_ssthresh) {  			tp->snd_ssthresh = tp->prior_ssthresh; @@ -3181,6 +3199,9 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,  			tp->lost_skb_hint = NULL;  	} +	if (!skb) +		tcp_chrono_stop(sk, TCP_CHRONO_BUSY); +  	if (likely(between(tp->snd_up, prior_snd_una, tp->snd_una)))  		tp->snd_up = tp->snd_una; @@ -3351,9 +3372,7 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack)  	u32 delta = ack - tp->snd_una;  	sock_owned_by_me((struct sock *)tp); -	u64_stats_update_begin_raw(&tp->syncp);  	tp->bytes_acked += delta; -	u64_stats_update_end_raw(&tp->syncp);  	tp->snd_una = ack;  } @@ -3363,9 +3382,7 @@ static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq)  	u32 delta = seq - tp->rcv_nxt;  	sock_owned_by_me((struct sock *)tp); -	u64_stats_update_begin_raw(&tp->syncp);  	tp->bytes_received += delta; -	u64_stats_update_end_raw(&tp->syncp);  	tp->rcv_nxt = seq;  } @@ -5063,8 +5080,11 @@ static void tcp_check_space(struct sock *sk)  		/* pairs with tcp_poll() */  		smp_mb__after_atomic();  		if (sk->sk_socket && -		    test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) +		    test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {  			tcp_new_space(sk); +			if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) +				tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); +		}  	}  } @@ -6298,13 +6318,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,  			goto drop;  	} - -	/* Accept backlog is full. If we have already queued enough -	 * of warm entries in syn queue, drop request. It is better than -	 * clogging syn queue with openreqs with exponentially increasing -	 * timeout. -	 */ -	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { +	if (sk_acceptq_is_full(sk)) {  		NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);  		goto drop;  	} @@ -6314,6 +6328,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,  		goto drop;  	tcp_rsk(req)->af_specific = af_ops; +	tcp_rsk(req)->ts_off = 0;  	tcp_clear_options(&tmp_opt);  	tmp_opt.mss_clamp = af_ops->mss_clamp; @@ -6335,6 +6350,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,  	if (security_inet_conn_request(sk, skb, req))  		goto drop_and_free; +	if (isn && tmp_opt.tstamp_ok) +		af_ops->init_seq(skb, &tcp_rsk(req)->ts_off); +  	if (!want_cookie && !isn) {  		/* VJ's idea. We save last timestamp seen  		 * from the destination in peer table, when entering @@ -6375,7 +6393,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,  			goto drop_and_release;  		} -		isn = af_ops->init_seq(skb); +		isn = af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);  	}  	if (!dst) {  		dst = af_ops->route_req(sk, &fl, req, NULL); @@ -6387,6 +6405,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,  	if (want_cookie) {  		isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); +		tcp_rsk(req)->ts_off = 0;  		req->cookie_ts = tmp_opt.tstamp_ok;  		if (!tmp_opt.tstamp_ok)  			inet_rsk(req)->ecn_ok = 0;  |