tcp: ECN blackhole should not force quickack mode
While playing with a new ADSL box at home, I discovered that ECN blackhole can trigger suboptimal quickack mode on linux : We send one ACK for each incoming data frame, without any delay and eventual piggyback. This is because TCP_ECN_check_ce() considers that if no ECT is seen on a segment, this is because this segment was a retransmit. Refine this heuristic and apply it only if we seen ECT in a previous segment, to detect ECN blackhole at IP level. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Jamal Hadi Salim <jhs@mojatatu.com> CC: Jerry Chu <hkchu@google.com> CC: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> CC: Jim Gettys <jg@freedesktop.org> CC: Dave Taht <dave.taht@gmail.com> Acked-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									0bdb0bd013
								
							
						
					
					
						commit
						7a269ffad7
					
				| @ -356,6 +356,7 @@ static inline void tcp_dec_quickack_mode(struct sock *sk, | ||||
| #define	TCP_ECN_OK		1 | ||||
| #define	TCP_ECN_QUEUE_CWR	2 | ||||
| #define	TCP_ECN_DEMAND_CWR	4 | ||||
| #define	TCP_ECN_SEEN		8 | ||||
| 
 | ||||
| static __inline__ void | ||||
| TCP_ECN_create_request(struct request_sock *req, struct tcphdr *th) | ||||
|  | ||||
| @ -217,16 +217,25 @@ static inline void TCP_ECN_withdraw_cwr(struct tcp_sock *tp) | ||||
| 	tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; | ||||
| } | ||||
| 
 | ||||
| static inline void TCP_ECN_check_ce(struct tcp_sock *tp, struct sk_buff *skb) | ||||
| static inline void TCP_ECN_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) | ||||
| { | ||||
| 	if (tp->ecn_flags & TCP_ECN_OK) { | ||||
| 		if (INET_ECN_is_ce(TCP_SKB_CB(skb)->flags)) | ||||
| 			tp->ecn_flags |= TCP_ECN_DEMAND_CWR; | ||||
| 	if (!(tp->ecn_flags & TCP_ECN_OK)) | ||||
| 		return; | ||||
| 
 | ||||
| 	switch (TCP_SKB_CB(skb)->flags & INET_ECN_MASK) { | ||||
| 	case INET_ECN_NOT_ECT: | ||||
| 		/* Funny extension: if ECT is not set on a segment,
 | ||||
| 		 * it is surely retransmit. It is not in ECN RFC, | ||||
| 		 * but Linux follows this rule. */ | ||||
| 		else if (INET_ECN_is_not_ect((TCP_SKB_CB(skb)->flags))) | ||||
| 		 * and we already seen ECT on a previous segment, | ||||
| 		 * it is probably a retransmit. | ||||
| 		 */ | ||||
| 		if (tp->ecn_flags & TCP_ECN_SEEN) | ||||
| 			tcp_enter_quickack_mode((struct sock *)tp); | ||||
| 		break; | ||||
| 	case INET_ECN_CE: | ||||
| 		tp->ecn_flags |= TCP_ECN_DEMAND_CWR; | ||||
| 		/* fallinto */ | ||||
| 	default: | ||||
| 		tp->ecn_flags |= TCP_ECN_SEEN; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user