diff options
Diffstat (limited to 'net/ipv4/tcp_output.c')
| -rw-r--r-- | net/ipv4/tcp_output.c | 46 | 
1 files changed, 26 insertions, 20 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ec335fabd5cc..92fde8d1aa82 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -160,6 +160,7 @@ static void tcp_event_data_sent(struct tcp_sock *tp,  {  	struct inet_connection_sock *icsk = inet_csk(sk);  	const u32 now = tcp_time_stamp; +	const struct dst_entry *dst = __sk_dst_get(sk);  	if (sysctl_tcp_slow_start_after_idle &&  	    (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto)) @@ -170,8 +171,9 @@ static void tcp_event_data_sent(struct tcp_sock *tp,  	/* If it is a reply for ato after last received  	 * packet, enter pingpong mode.  	 */ -	if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato) -		icsk->icsk_ack.pingpong = 1; +	if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato && +	    (!dst || !dst_metric(dst, RTAX_QUICKACK))) +			icsk->icsk_ack.pingpong = 1;  }  /* Account for an ACK we sent. */ @@ -181,6 +183,21 @@ static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts)  	inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);  } + +u32 tcp_default_init_rwnd(u32 mss) +{ +	/* Initial receive window should be twice of TCP_INIT_CWND to +	 * enable proper sending of new unsent data during fast recovery +	 * (RFC 3517, Section 4, NextSeg() rule (2)). Further place a +	 * limit when mss is larger than 1460. +	 */ +	u32 init_rwnd = TCP_INIT_CWND * 2; + +	if (mss > 1460) +		init_rwnd = max((1460 * init_rwnd) / mss, 2U); +	return init_rwnd; +} +  /* Determine a window scaling and initial window to offer.   * Based on the assumption that the given amount of space   * will be offered. Store the results in the tp structure. @@ -230,22 +247,10 @@ void tcp_select_initial_window(int __space, __u32 mss,  		}  	} -	/* Set initial window to a value enough for senders starting with -	 * initial congestion window of TCP_DEFAULT_INIT_RCVWND. Place -	 * a limit on the initial window when mss is larger than 1460. -	 */  	if (mss > (1 << *rcv_wscale)) { -		int init_cwnd = TCP_DEFAULT_INIT_RCVWND; -		if (mss > 1460) -			init_cwnd = -			max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2); -		/* when initializing use the value from init_rcv_wnd -		 * rather than the default from above -		 */ -		if (init_rcv_wnd) -			*rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss); -		else -			*rcv_wnd = min(*rcv_wnd, init_cwnd * mss); +		if (!init_rcv_wnd) /* Use default unless specified otherwise */ +			init_rcv_wnd = tcp_default_init_rwnd(mss); +		*rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss);  	}  	/* Set the clamp no higher than max representable value */ @@ -2402,6 +2407,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)  		 * see tcp_input.c tcp_sacktag_write_queue().  		 */  		TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt; +	} else { +		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL);  	}  	return err;  } @@ -2523,10 +2530,9 @@ begin_fwd:  		if (sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))  			continue; -		if (tcp_retransmit_skb(sk, skb)) { -			NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL); +		if (tcp_retransmit_skb(sk, skb))  			return; -		} +  		NET_INC_STATS_BH(sock_net(sk), mib_idx);  		if (tcp_in_cwnd_reduction(sk))  | 
