|  |  |  | @ -93,7 +93,6 @@ int sysctl_tcp_stdurg __read_mostly; | 
		
	
		
			
				|  |  |  |  | int sysctl_tcp_rfc1337 __read_mostly; | 
		
	
		
			
				|  |  |  |  | int sysctl_tcp_max_orphans __read_mostly = NR_FILE; | 
		
	
		
			
				|  |  |  |  | int sysctl_tcp_frto __read_mostly = 2; | 
		
	
		
			
				|  |  |  |  | int sysctl_tcp_frto_response __read_mostly; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | int sysctl_tcp_thin_dupack __read_mostly; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					
					|  |  |  | @ -108,17 +107,14 @@ int sysctl_tcp_early_retrans __read_mostly = 3; | 
		
	
		
			
				|  |  |  |  | #define FLAG_DATA_SACKED	0x20 /* New SACK.				*/ | 
		
	
		
			
				|  |  |  |  | #define FLAG_ECE		0x40 /* ECE in this ACK				*/ | 
		
	
		
			
				|  |  |  |  | #define FLAG_SLOWPATH		0x100 /* Do not skip RFC checks for window update.*/ | 
		
	
		
			
				|  |  |  |  | #define FLAG_ONLY_ORIG_SACKED	0x200 /* SACKs only non-rexmit sent before RTO */ | 
		
	
		
			
				|  |  |  |  | #define FLAG_SND_UNA_ADVANCED	0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ | 
		
	
		
			
				|  |  |  |  | #define FLAG_DSACKING_ACK	0x800 /* SACK blocks contained D-SACK info */ | 
		
	
		
			
				|  |  |  |  | #define FLAG_NONHEAD_RETRANS_ACKED	0x1000 /* Non-head rexmitted data was ACKed */ | 
		
	
		
			
				|  |  |  |  | #define FLAG_SACK_RENEGING	0x2000 /* snd_una advanced to a sacked seq */ | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #define FLAG_ACKED		(FLAG_DATA_ACKED|FLAG_SYN_ACKED) | 
		
	
		
			
				|  |  |  |  | #define FLAG_NOT_DUP		(FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) | 
		
	
		
			
				|  |  |  |  | #define FLAG_CA_ALERT		(FLAG_DATA_SACKED|FLAG_ECE) | 
		
	
		
			
				|  |  |  |  | #define FLAG_FORWARD_PROGRESS	(FLAG_ACKED|FLAG_DATA_SACKED) | 
		
	
		
			
				|  |  |  |  | #define FLAG_ANY_PROGRESS	(FLAG_FORWARD_PROGRESS|FLAG_SND_UNA_ADVANCED) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) | 
		
	
		
			
				|  |  |  |  | #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) | 
		
	
	
		
			
				
					
					|  |  |  | @ -1159,10 +1155,6 @@ static u8 tcp_sacktag_one(struct sock *sk, | 
		
	
		
			
				|  |  |  |  | 					   tcp_highest_sack_seq(tp))) | 
		
	
		
			
				|  |  |  |  | 					state->reord = min(fack_count, | 
		
	
		
			
				|  |  |  |  | 							   state->reord); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 				/* SACK enhanced F-RTO (RFC4138; Appendix B) */ | 
		
	
		
			
				|  |  |  |  | 				if (!after(end_seq, tp->frto_highmark)) | 
		
	
		
			
				|  |  |  |  | 					state->flag |= FLAG_ONLY_ORIG_SACKED; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 			if (sacked & TCPCB_LOST) { | 
		
	
	
		
			
				
					
					|  |  |  | @ -1555,7 +1547,6 @@ static int | 
		
	
		
			
				|  |  |  |  | tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, | 
		
	
		
			
				|  |  |  |  | 			u32 prior_snd_una) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	const struct inet_connection_sock *icsk = inet_csk(sk); | 
		
	
		
			
				|  |  |  |  | 	struct tcp_sock *tp = tcp_sk(sk); | 
		
	
		
			
				|  |  |  |  | 	const unsigned char *ptr = (skb_transport_header(ack_skb) + | 
		
	
		
			
				|  |  |  |  | 				    TCP_SKB_CB(ack_skb)->sacked); | 
		
	
	
		
			
				
					
					|  |  |  | @ -1728,12 +1719,6 @@ walk: | 
		
	
		
			
				|  |  |  |  | 				       start_seq, end_seq, dup_sack); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | advance_sp: | 
		
	
		
			
				|  |  |  |  | 		/* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct
 | 
		
	
		
			
				|  |  |  |  | 		 * due to in-order walk | 
		
	
		
			
				|  |  |  |  | 		 */ | 
		
	
		
			
				|  |  |  |  | 		if (after(end_seq, tp->frto_highmark)) | 
		
	
		
			
				|  |  |  |  | 			state.flag &= ~FLAG_ONLY_ORIG_SACKED; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 		i++; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					
					|  |  |  | @ -1750,8 +1735,7 @@ advance_sp: | 
		
	
		
			
				|  |  |  |  | 	tcp_verify_left_out(tp); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if ((state.reord < tp->fackets_out) && | 
		
	
		
			
				|  |  |  |  | 	    ((icsk->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker) && | 
		
	
		
			
				|  |  |  |  | 	    (!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark))) | 
		
	
		
			
				|  |  |  |  | 	    ((inet_csk(sk)->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker)) | 
		
	
		
			
				|  |  |  |  | 		tcp_update_reordering(sk, tp->fackets_out - state.reord, 0); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | out: | 
		
	
	
		
			
				
					
					|  |  |  | @ -1825,197 +1809,6 @@ static inline void tcp_reset_reno_sack(struct tcp_sock *tp) | 
		
	
		
			
				|  |  |  |  | 	tp->sacked_out = 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | static int tcp_is_sackfrto(const struct tcp_sock *tp) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	return (sysctl_tcp_frto == 0x2) && !tcp_is_reno(tp); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /* F-RTO can only be used if TCP has never retransmitted anything other than
 | 
		
	
		
			
				|  |  |  |  |  * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here) | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | bool tcp_use_frto(struct sock *sk) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	const struct tcp_sock *tp = tcp_sk(sk); | 
		
	
		
			
				|  |  |  |  | 	const struct inet_connection_sock *icsk = inet_csk(sk); | 
		
	
		
			
				|  |  |  |  | 	struct sk_buff *skb; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (!sysctl_tcp_frto) | 
		
	
		
			
				|  |  |  |  | 		return false; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	/* MTU probe and F-RTO won't really play nicely along currently */ | 
		
	
		
			
				|  |  |  |  | 	if (icsk->icsk_mtup.probe_size) | 
		
	
		
			
				|  |  |  |  | 		return false; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (tcp_is_sackfrto(tp)) | 
		
	
		
			
				|  |  |  |  | 		return true; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	/* Avoid expensive walking of rexmit queue if possible */ | 
		
	
		
			
				|  |  |  |  | 	if (tp->retrans_out > 1) | 
		
	
		
			
				|  |  |  |  | 		return false; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	skb = tcp_write_queue_head(sk); | 
		
	
		
			
				|  |  |  |  | 	if (tcp_skb_is_last(sk, skb)) | 
		
	
		
			
				|  |  |  |  | 		return true; | 
		
	
		
			
				|  |  |  |  | 	skb = tcp_write_queue_next(sk, skb);	/* Skips head */ | 
		
	
		
			
				|  |  |  |  | 	tcp_for_write_queue_from(skb, sk) { | 
		
	
		
			
				|  |  |  |  | 		if (skb == tcp_send_head(sk)) | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 		if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS) | 
		
	
		
			
				|  |  |  |  | 			return false; | 
		
	
		
			
				|  |  |  |  | 		/* Short-circuit when first non-SACKed skb has been checked */ | 
		
	
		
			
				|  |  |  |  | 		if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return true; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /* RTO occurred, but do not yet enter Loss state. Instead, defer RTO
 | 
		
	
		
			
				|  |  |  |  |  * recovery a bit and use heuristics in tcp_process_frto() to detect if | 
		
	
		
			
				|  |  |  |  |  * the RTO was spurious. Only clear SACKED_RETRANS of the head here to | 
		
	
		
			
				|  |  |  |  |  * keep retrans_out counting accurate (with SACK F-RTO, other than head | 
		
	
		
			
				|  |  |  |  |  * may still have that bit set); TCPCB_LOST and remaining SACKED_RETRANS | 
		
	
		
			
				|  |  |  |  |  * bits are handled if the Loss state is really to be entered (in | 
		
	
		
			
				|  |  |  |  |  * tcp_enter_frto_loss). | 
		
	
		
			
				|  |  |  |  |  * | 
		
	
		
			
				|  |  |  |  |  * Do like tcp_enter_loss() would; when RTO expires the second time it | 
		
	
		
			
				|  |  |  |  |  * does: | 
		
	
		
			
				|  |  |  |  |  *  "Reduce ssthresh if it has not yet been made inside this window." | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | void tcp_enter_frto(struct sock *sk) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	const struct inet_connection_sock *icsk = inet_csk(sk); | 
		
	
		
			
				|  |  |  |  | 	struct tcp_sock *tp = tcp_sk(sk); | 
		
	
		
			
				|  |  |  |  | 	struct sk_buff *skb; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if ((!tp->frto_counter && icsk->icsk_ca_state <= TCP_CA_Disorder) || | 
		
	
		
			
				|  |  |  |  | 	    tp->snd_una == tp->high_seq || | 
		
	
		
			
				|  |  |  |  | 	    ((icsk->icsk_ca_state == TCP_CA_Loss || tp->frto_counter) && | 
		
	
		
			
				|  |  |  |  | 	     !icsk->icsk_retransmits)) { | 
		
	
		
			
				|  |  |  |  | 		tp->prior_ssthresh = tcp_current_ssthresh(sk); | 
		
	
		
			
				|  |  |  |  | 		/* Our state is too optimistic in ssthresh() call because cwnd
 | 
		
	
		
			
				|  |  |  |  | 		 * is not reduced until tcp_enter_frto_loss() when previous F-RTO | 
		
	
		
			
				|  |  |  |  | 		 * recovery has not yet completed. Pattern would be this: RTO, | 
		
	
		
			
				|  |  |  |  | 		 * Cumulative ACK, RTO (2xRTO for the same segment does not end | 
		
	
		
			
				|  |  |  |  | 		 * up here twice). | 
		
	
		
			
				|  |  |  |  | 		 * RFC4138 should be more specific on what to do, even though | 
		
	
		
			
				|  |  |  |  | 		 * RTO is quite unlikely to occur after the first Cumulative ACK | 
		
	
		
			
				|  |  |  |  | 		 * due to back-off and complexity of triggering events ... | 
		
	
		
			
				|  |  |  |  | 		 */ | 
		
	
		
			
				|  |  |  |  | 		if (tp->frto_counter) { | 
		
	
		
			
				|  |  |  |  | 			u32 stored_cwnd; | 
		
	
		
			
				|  |  |  |  | 			stored_cwnd = tp->snd_cwnd; | 
		
	
		
			
				|  |  |  |  | 			tp->snd_cwnd = 2; | 
		
	
		
			
				|  |  |  |  | 			tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk); | 
		
	
		
			
				|  |  |  |  | 			tp->snd_cwnd = stored_cwnd; | 
		
	
		
			
				|  |  |  |  | 		} else { | 
		
	
		
			
				|  |  |  |  | 			tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk); | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		/* ... in theory, cong.control module could do "any tricks" in
 | 
		
	
		
			
				|  |  |  |  | 		 * ssthresh(), which means that ca_state, lost bits and lost_out | 
		
	
		
			
				|  |  |  |  | 		 * counter would have to be faked before the call occurs. We | 
		
	
		
			
				|  |  |  |  | 		 * consider that too expensive, unlikely and hacky, so modules | 
		
	
		
			
				|  |  |  |  | 		 * using these in ssthresh() must deal these incompatibility | 
		
	
		
			
				|  |  |  |  | 		 * issues if they receives CA_EVENT_FRTO and frto_counter != 0 | 
		
	
		
			
				|  |  |  |  | 		 */ | 
		
	
		
			
				|  |  |  |  | 		tcp_ca_event(sk, CA_EVENT_FRTO); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	tp->undo_marker = tp->snd_una; | 
		
	
		
			
				|  |  |  |  | 	tp->undo_retrans = 0; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	skb = tcp_write_queue_head(sk); | 
		
	
		
			
				|  |  |  |  | 	if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS) | 
		
	
		
			
				|  |  |  |  | 		tp->undo_marker = 0; | 
		
	
		
			
				|  |  |  |  | 	if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { | 
		
	
		
			
				|  |  |  |  | 		TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; | 
		
	
		
			
				|  |  |  |  | 		tp->retrans_out -= tcp_skb_pcount(skb); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	tcp_verify_left_out(tp); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	/* Too bad if TCP was application limited */ | 
		
	
		
			
				|  |  |  |  | 	tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp) + 1); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	/* Earlier loss recovery underway (see RFC4138; Appendix B).
 | 
		
	
		
			
				|  |  |  |  | 	 * The last condition is necessary at least in tp->frto_counter case. | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	if (tcp_is_sackfrto(tp) && (tp->frto_counter || | 
		
	
		
			
				|  |  |  |  | 	    ((1 << icsk->icsk_ca_state) & (TCPF_CA_Recovery|TCPF_CA_Loss))) && | 
		
	
		
			
				|  |  |  |  | 	    after(tp->high_seq, tp->snd_una)) { | 
		
	
		
			
				|  |  |  |  | 		tp->frto_highmark = tp->high_seq; | 
		
	
		
			
				|  |  |  |  | 	} else { | 
		
	
		
			
				|  |  |  |  | 		tp->frto_highmark = tp->snd_nxt; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	tcp_set_ca_state(sk, TCP_CA_Disorder); | 
		
	
		
			
				|  |  |  |  | 	tp->high_seq = tp->snd_nxt; | 
		
	
		
			
				|  |  |  |  | 	tp->frto_counter = 1; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /* Enter Loss state after F-RTO was applied. Dupack arrived after RTO,
 | 
		
	
		
			
				|  |  |  |  |  * which indicates that we should follow the traditional RTO recovery, | 
		
	
		
			
				|  |  |  |  |  * i.e. mark everything lost and do go-back-N retransmission. | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	struct tcp_sock *tp = tcp_sk(sk); | 
		
	
		
			
				|  |  |  |  | 	struct sk_buff *skb; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	tp->lost_out = 0; | 
		
	
		
			
				|  |  |  |  | 	tp->retrans_out = 0; | 
		
	
		
			
				|  |  |  |  | 	if (tcp_is_reno(tp)) | 
		
	
		
			
				|  |  |  |  | 		tcp_reset_reno_sack(tp); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	tcp_for_write_queue(skb, sk) { | 
		
	
		
			
				|  |  |  |  | 		if (skb == tcp_send_head(sk)) | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 		TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; | 
		
	
		
			
				|  |  |  |  | 		/*
 | 
		
	
		
			
				|  |  |  |  | 		 * Count the retransmission made on RTO correctly (only when | 
		
	
		
			
				|  |  |  |  | 		 * waiting for the first ACK and did not get it)... | 
		
	
		
			
				|  |  |  |  | 		 */ | 
		
	
		
			
				|  |  |  |  | 		if ((tp->frto_counter == 1) && !(flag & FLAG_DATA_ACKED)) { | 
		
	
		
			
				|  |  |  |  | 			/* For some reason this R-bit might get cleared? */ | 
		
	
		
			
				|  |  |  |  | 			if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) | 
		
	
		
			
				|  |  |  |  | 				tp->retrans_out += tcp_skb_pcount(skb); | 
		
	
		
			
				|  |  |  |  | 			/* ...enter this if branch just for the first segment */ | 
		
	
		
			
				|  |  |  |  | 			flag |= FLAG_DATA_ACKED; | 
		
	
		
			
				|  |  |  |  | 		} else { | 
		
	
		
			
				|  |  |  |  | 			if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS) | 
		
	
		
			
				|  |  |  |  | 				tp->undo_marker = 0; | 
		
	
		
			
				|  |  |  |  | 			TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 		/* Marking forward transmissions that were made after RTO lost
 | 
		
	
		
			
				|  |  |  |  | 		 * can cause unnecessary retransmissions in some scenarios, | 
		
	
		
			
				|  |  |  |  | 		 * SACK blocks will mitigate that in some but not in all cases. | 
		
	
		
			
				|  |  |  |  | 		 * We used to not mark them but it was causing break-ups with | 
		
	
		
			
				|  |  |  |  | 		 * receivers that do only in-order receival. | 
		
	
		
			
				|  |  |  |  | 		 * | 
		
	
		
			
				|  |  |  |  | 		 * TODO: we could detect presence of such receiver and select | 
		
	
		
			
				|  |  |  |  | 		 * different behavior per flow. | 
		
	
		
			
				|  |  |  |  | 		 */ | 
		
	
		
			
				|  |  |  |  | 		if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) { | 
		
	
		
			
				|  |  |  |  | 			TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; | 
		
	
		
			
				|  |  |  |  | 			tp->lost_out += tcp_skb_pcount(skb); | 
		
	
		
			
				|  |  |  |  | 			tp->retransmit_high = TCP_SKB_CB(skb)->end_seq; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	tcp_verify_left_out(tp); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments; | 
		
	
		
			
				|  |  |  |  | 	tp->snd_cwnd_cnt = 0; | 
		
	
		
			
				|  |  |  |  | 	tp->snd_cwnd_stamp = tcp_time_stamp; | 
		
	
		
			
				|  |  |  |  | 	tp->frto_counter = 0; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	tp->reordering = min_t(unsigned int, tp->reordering, | 
		
	
		
			
				|  |  |  |  | 			       sysctl_tcp_reordering); | 
		
	
		
			
				|  |  |  |  | 	tcp_set_ca_state(sk, TCP_CA_Loss); | 
		
	
		
			
				|  |  |  |  | 	tp->high_seq = tp->snd_nxt; | 
		
	
		
			
				|  |  |  |  | 	TCP_ECN_queue_cwr(tp); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	tcp_clear_all_retrans_hints(tp); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | static void tcp_clear_retrans_partial(struct tcp_sock *tp) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	tp->retrans_out = 0; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2090,8 +1883,6 @@ void tcp_enter_loss(struct sock *sk, int how) | 
		
	
		
			
				|  |  |  |  | 	tcp_set_ca_state(sk, TCP_CA_Loss); | 
		
	
		
			
				|  |  |  |  | 	tp->high_seq = tp->snd_nxt; | 
		
	
		
			
				|  |  |  |  | 	TCP_ECN_queue_cwr(tp); | 
		
	
		
			
				|  |  |  |  | 	/* Abort F-RTO algorithm if one is in progress */ | 
		
	
		
			
				|  |  |  |  | 	tp->frto_counter = 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /* If ACK arrived pointing to a remembered SACK, it means that our
 | 
		
	
	
		
			
				
					
					|  |  |  | @ -2275,10 +2066,6 @@ static bool tcp_time_to_recover(struct sock *sk, int flag) | 
		
	
		
			
				|  |  |  |  | 	struct tcp_sock *tp = tcp_sk(sk); | 
		
	
		
			
				|  |  |  |  | 	__u32 packets_out; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	/* Do not perform any recovery during F-RTO algorithm */ | 
		
	
		
			
				|  |  |  |  | 	if (tp->frto_counter) | 
		
	
		
			
				|  |  |  |  | 		return false; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	/* Trick#1: The loss is proven. */ | 
		
	
		
			
				|  |  |  |  | 	if (tp->lost_out) | 
		
	
		
			
				|  |  |  |  | 		return true; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2760,7 +2547,7 @@ static void tcp_try_to_open(struct sock *sk, int flag, int newly_acked_sacked) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	tcp_verify_left_out(tp); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (!tp->frto_counter && !tcp_any_retrans_done(sk)) | 
		
	
		
			
				|  |  |  |  | 	if (!tcp_any_retrans_done(sk)) | 
		
	
		
			
				|  |  |  |  | 		tp->retrans_stamp = 0; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (flag & FLAG_ECE) | 
		
	
	
		
			
				
					
					|  |  |  | @ -3198,8 +2985,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, | 
		
	
		
			
				|  |  |  |  | 			flag |= FLAG_RETRANS_DATA_ACKED; | 
		
	
		
			
				|  |  |  |  | 			ca_seq_rtt = -1; | 
		
	
		
			
				|  |  |  |  | 			seq_rtt = -1; | 
		
	
		
			
				|  |  |  |  | 			if ((flag & FLAG_DATA_ACKED) || (acked_pcount > 1)) | 
		
	
		
			
				|  |  |  |  | 				flag |= FLAG_NONHEAD_RETRANS_ACKED; | 
		
	
		
			
				|  |  |  |  | 		} else { | 
		
	
		
			
				|  |  |  |  | 			ca_seq_rtt = now - scb->when; | 
		
	
		
			
				|  |  |  |  | 			last_ackt = skb->tstamp; | 
		
	
	
		
			
				
					
					|  |  |  | @ -3408,150 +3193,6 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 | 
		
	
		
			
				|  |  |  |  | 	return flag; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /* A very conservative spurious RTO response algorithm: reduce cwnd and
 | 
		
	
		
			
				|  |  |  |  |  * continue in congestion avoidance. | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | static void tcp_conservative_spur_to_response(struct tcp_sock *tp) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh); | 
		
	
		
			
				|  |  |  |  | 	tp->snd_cwnd_cnt = 0; | 
		
	
		
			
				|  |  |  |  | 	TCP_ECN_queue_cwr(tp); | 
		
	
		
			
				|  |  |  |  | 	tcp_moderate_cwnd(tp); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /* A conservative spurious RTO response algorithm: reduce cwnd using
 | 
		
	
		
			
				|  |  |  |  |  * PRR and continue in congestion avoidance. | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | static void tcp_cwr_spur_to_response(struct sock *sk) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	tcp_enter_cwr(sk, 0); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | static void tcp_undo_spur_to_response(struct sock *sk, int flag) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	if (flag & FLAG_ECE) | 
		
	
		
			
				|  |  |  |  | 		tcp_cwr_spur_to_response(sk); | 
		
	
		
			
				|  |  |  |  | 	else | 
		
	
		
			
				|  |  |  |  | 		tcp_undo_cwr(sk, true); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /* F-RTO spurious RTO detection algorithm (RFC4138)
 | 
		
	
		
			
				|  |  |  |  |  * | 
		
	
		
			
				|  |  |  |  |  * F-RTO affects during two new ACKs following RTO (well, almost, see inline | 
		
	
		
			
				|  |  |  |  |  * comments). State (ACK number) is kept in frto_counter. When ACK advances | 
		
	
		
			
				|  |  |  |  |  * window (but not to or beyond highest sequence sent before RTO): | 
		
	
		
			
				|  |  |  |  |  *   On First ACK,  send two new segments out. | 
		
	
		
			
				|  |  |  |  |  *   On Second ACK, RTO was likely spurious. Do spurious response (response | 
		
	
		
			
				|  |  |  |  |  *                  algorithm is not part of the F-RTO detection algorithm | 
		
	
		
			
				|  |  |  |  |  *                  given in RFC4138 but can be selected separately). | 
		
	
		
			
				|  |  |  |  |  * Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss | 
		
	
		
			
				|  |  |  |  |  * and TCP falls back to conventional RTO recovery. F-RTO allows overriding | 
		
	
		
			
				|  |  |  |  |  * of Nagle, this is done using frto_counter states 2 and 3, when a new data | 
		
	
		
			
				|  |  |  |  |  * segment of any size sent during F-RTO, state 2 is upgraded to 3. | 
		
	
		
			
				|  |  |  |  |  * | 
		
	
		
			
				|  |  |  |  |  * Rationale: if the RTO was spurious, new ACKs should arrive from the | 
		
	
		
			
				|  |  |  |  |  * original window even after we transmit two new data segments. | 
		
	
		
			
				|  |  |  |  |  * | 
		
	
		
			
				|  |  |  |  |  * SACK version: | 
		
	
		
			
				|  |  |  |  |  *   on first step, wait until first cumulative ACK arrives, then move to | 
		
	
		
			
				|  |  |  |  |  *   the second step. In second step, the next ACK decides. | 
		
	
		
			
				|  |  |  |  |  * | 
		
	
		
			
				|  |  |  |  |  * F-RTO is implemented (mainly) in four functions: | 
		
	
		
			
				|  |  |  |  |  *   - tcp_use_frto() is used to determine if TCP is can use F-RTO | 
		
	
		
			
				|  |  |  |  |  *   - tcp_enter_frto() prepares TCP state on RTO if F-RTO is used, it is | 
		
	
		
			
				|  |  |  |  |  *     called when tcp_use_frto() showed green light | 
		
	
		
			
				|  |  |  |  |  *   - tcp_process_frto() handles incoming ACKs during F-RTO algorithm | 
		
	
		
			
				|  |  |  |  |  *   - tcp_enter_frto_loss() is called if there is not enough evidence | 
		
	
		
			
				|  |  |  |  |  *     to prove that the RTO is indeed spurious. It transfers the control | 
		
	
		
			
				|  |  |  |  |  *     from F-RTO to the conventional RTO recovery | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | static bool tcp_process_frto(struct sock *sk, int flag) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	struct tcp_sock *tp = tcp_sk(sk); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	tcp_verify_left_out(tp); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	/* Duplicate the behavior from Loss state (fastretrans_alert) */ | 
		
	
		
			
				|  |  |  |  | 	if (flag & FLAG_DATA_ACKED) | 
		
	
		
			
				|  |  |  |  | 		inet_csk(sk)->icsk_retransmits = 0; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if ((flag & FLAG_NONHEAD_RETRANS_ACKED) || | 
		
	
		
			
				|  |  |  |  | 	    ((tp->frto_counter >= 2) && (flag & FLAG_RETRANS_DATA_ACKED))) | 
		
	
		
			
				|  |  |  |  | 		tp->undo_marker = 0; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (!before(tp->snd_una, tp->frto_highmark)) { | 
		
	
		
			
				|  |  |  |  | 		tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); | 
		
	
		
			
				|  |  |  |  | 		return true; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (!tcp_is_sackfrto(tp)) { | 
		
	
		
			
				|  |  |  |  | 		/* RFC4138 shortcoming in step 2; should also have case c):
 | 
		
	
		
			
				|  |  |  |  | 		 * ACK isn't duplicate nor advances window, e.g., opposite dir | 
		
	
		
			
				|  |  |  |  | 		 * data, winupdate | 
		
	
		
			
				|  |  |  |  | 		 */ | 
		
	
		
			
				|  |  |  |  | 		if (!(flag & FLAG_ANY_PROGRESS) && (flag & FLAG_NOT_DUP)) | 
		
	
		
			
				|  |  |  |  | 			return true; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 		if (!(flag & FLAG_DATA_ACKED)) { | 
		
	
		
			
				|  |  |  |  | 			tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 0 : 3), | 
		
	
		
			
				|  |  |  |  | 					    flag); | 
		
	
		
			
				|  |  |  |  | 			return true; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} else { | 
		
	
		
			
				|  |  |  |  | 		if (!(flag & FLAG_DATA_ACKED) && (tp->frto_counter == 1)) { | 
		
	
		
			
				|  |  |  |  | 			if (!tcp_packets_in_flight(tp)) { | 
		
	
		
			
				|  |  |  |  | 				tcp_enter_frto_loss(sk, 2, flag); | 
		
	
		
			
				|  |  |  |  | 				return true; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 			/* Prevent sending of new data. */ | 
		
	
		
			
				|  |  |  |  | 			tp->snd_cwnd = min(tp->snd_cwnd, | 
		
	
		
			
				|  |  |  |  | 					   tcp_packets_in_flight(tp)); | 
		
	
		
			
				|  |  |  |  | 			return true; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 		if ((tp->frto_counter >= 2) && | 
		
	
		
			
				|  |  |  |  | 		    (!(flag & FLAG_FORWARD_PROGRESS) || | 
		
	
		
			
				|  |  |  |  | 		     ((flag & FLAG_DATA_SACKED) && | 
		
	
		
			
				|  |  |  |  | 		      !(flag & FLAG_ONLY_ORIG_SACKED)))) { | 
		
	
		
			
				|  |  |  |  | 			/* RFC4138 shortcoming (see comment above) */ | 
		
	
		
			
				|  |  |  |  | 			if (!(flag & FLAG_FORWARD_PROGRESS) && | 
		
	
		
			
				|  |  |  |  | 			    (flag & FLAG_NOT_DUP)) | 
		
	
		
			
				|  |  |  |  | 				return true; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 			tcp_enter_frto_loss(sk, 3, flag); | 
		
	
		
			
				|  |  |  |  | 			return true; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (tp->frto_counter == 1) { | 
		
	
		
			
				|  |  |  |  | 		/* tcp_may_send_now needs to see updated state */ | 
		
	
		
			
				|  |  |  |  | 		tp->snd_cwnd = tcp_packets_in_flight(tp) + 2; | 
		
	
		
			
				|  |  |  |  | 		tp->frto_counter = 2; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 		if (!tcp_may_send_now(sk)) | 
		
	
		
			
				|  |  |  |  | 			tcp_enter_frto_loss(sk, 2, flag); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 		return true; | 
		
	
		
			
				|  |  |  |  | 	} else { | 
		
	
		
			
				|  |  |  |  | 		switch (sysctl_tcp_frto_response) { | 
		
	
		
			
				|  |  |  |  | 		case 2: | 
		
	
		
			
				|  |  |  |  | 			tcp_undo_spur_to_response(sk, flag); | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 		case 1: | 
		
	
		
			
				|  |  |  |  | 			tcp_conservative_spur_to_response(tp); | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 		default: | 
		
	
		
			
				|  |  |  |  | 			tcp_cwr_spur_to_response(sk); | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		tp->frto_counter = 0; | 
		
	
		
			
				|  |  |  |  | 		tp->undo_marker = 0; | 
		
	
		
			
				|  |  |  |  | 		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSPURIOUSRTOS); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return false; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /* RFC 5961 7 [ACK Throttling] */ | 
		
	
		
			
				|  |  |  |  | static void tcp_send_challenge_ack(struct sock *sk) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
	
		
			
				
					
					|  |  |  | @ -3616,7 +3257,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | 
		
	
		
			
				|  |  |  |  | 	int prior_packets; | 
		
	
		
			
				|  |  |  |  | 	int prior_sacked = tp->sacked_out; | 
		
	
		
			
				|  |  |  |  | 	int pkts_acked = 0; | 
		
	
		
			
				|  |  |  |  | 	bool frto_cwnd = false; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	/* If the ack is older than previous acks
 | 
		
	
		
			
				|  |  |  |  | 	 * then we can probably ignore it. | 
		
	
	
		
			
				
					
					|  |  |  | @ -3690,22 +3330,15 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	pkts_acked = prior_packets - tp->packets_out; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (tp->frto_counter) | 
		
	
		
			
				|  |  |  |  | 		frto_cwnd = tcp_process_frto(sk, flag); | 
		
	
		
			
				|  |  |  |  | 	/* Guarantee sacktag reordering detection against wrap-arounds */ | 
		
	
		
			
				|  |  |  |  | 	if (before(tp->frto_highmark, tp->snd_una)) | 
		
	
		
			
				|  |  |  |  | 		tp->frto_highmark = 0; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (tcp_ack_is_dubious(sk, flag)) { | 
		
	
		
			
				|  |  |  |  | 		/* Advance CWND, if state allows this. */ | 
		
	
		
			
				|  |  |  |  | 		if ((flag & FLAG_DATA_ACKED) && !frto_cwnd && | 
		
	
		
			
				|  |  |  |  | 		    tcp_may_raise_cwnd(sk, flag)) | 
		
	
		
			
				|  |  |  |  | 		if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(sk, flag)) | 
		
	
		
			
				|  |  |  |  | 			tcp_cong_avoid(sk, ack, prior_in_flight); | 
		
	
		
			
				|  |  |  |  | 		is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); | 
		
	
		
			
				|  |  |  |  | 		tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, | 
		
	
		
			
				|  |  |  |  | 				      is_dupack, flag); | 
		
	
		
			
				|  |  |  |  | 	} else { | 
		
	
		
			
				|  |  |  |  | 		if ((flag & FLAG_DATA_ACKED) && !frto_cwnd) | 
		
	
		
			
				|  |  |  |  | 		if (flag & FLAG_DATA_ACKED) | 
		
	
		
			
				|  |  |  |  | 			tcp_cong_avoid(sk, ack, prior_in_flight); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					
					|  |  |  | 
 |