With RFC3168 ECN, CWR SHOULD only be sent with new data

Overly conservative data receivers may ignore the CWR flag
on other packets, and keep ECE latched. This can result in
continous reduction of the congestion window, and very poor
performance when ECN is enabled.

Reviewed by:	rgrimes (mentor), rrs
Approved by:	rgrimes (mentor), tuexen (mentor)
MFC after:	3 days
Sponsored by:	NetApp, Inc.
Differential Revision:	https://reviews.freebsd.org/D23364
This commit is contained in:
Richard Scheffenegger 2020-05-21 21:33:15 +00:00
parent 8e0511652b
commit af2fb894c9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=361347
3 changed files with 34 additions and 20 deletions

View File

@ -447,9 +447,15 @@ cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type)
}
break;
case CC_ECN:
if (!IN_CONGRECOVERY(tp->t_flags)) {
if (!IN_CONGRECOVERY(tp->t_flags) ||
/*
* Allow ECN reaction on ACK to CWR, if
* that data segment was also CE marked.
*/
SEQ_GEQ(th->th_ack, tp->snd_recover)) {
EXIT_CONGRECOVERY(tp->t_flags);
TCPSTAT_INC(tcps_ecn_rcwnd);
tp->snd_recover = tp->snd_max;
tp->snd_recover = tp->snd_max + 1;
if (tp->t_flags2 & TF2_ECN_PERMIT)
tp->t_flags2 |= TF2_ECN_SND_CWR;
}

View File

@ -1170,7 +1170,8 @@ tcp_output(struct tcpcb *tp)
*/
if (len > 0 && SEQ_GEQ(tp->snd_nxt, tp->snd_max) &&
(sack_rxmit == 0) &&
!((tp->t_flags & TF_FORCEDATA) && len == 1)) {
!((tp->t_flags & TF_FORCEDATA) && len == 1 &&
SEQ_LT(tp->snd_una, tp->snd_max))) {
#ifdef INET6
if (isipv6)
ip6->ip6_flow |= htonl(IPTOS_ECN_ECT0 << 20);
@ -1178,14 +1179,14 @@ tcp_output(struct tcpcb *tp)
#endif
ip->ip_tos |= IPTOS_ECN_ECT0;
TCPSTAT_INC(tcps_ecn_ect0);
}
/*
* Reply with proper ECN notifications.
*/
if (tp->t_flags2 & TF2_ECN_SND_CWR) {
flags |= TH_CWR;
tp->t_flags2 &= ~TF2_ECN_SND_CWR;
/*
* Reply with proper ECN notifications.
* Only set CWR on new data segments.
*/
if (tp->t_flags2 & TF2_ECN_SND_CWR) {
flags |= TH_CWR;
tp->t_flags2 &= ~TF2_ECN_SND_CWR;
}
}
if (tp->t_flags2 & TF2_ECN_SND_ECE)
flags |= TH_ECE;

View File

@ -4095,9 +4095,15 @@ rack_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type)
}
break;
case CC_ECN:
if (!IN_CONGRECOVERY(tp->t_flags)) {
if (!IN_CONGRECOVERY(tp->t_flags) ||
/*
* Allow ECN reaction on ACK to CWR, if
* that data segment was also CE marked.
*/
SEQ_GEQ(th->th_ack, tp->snd_recover)) {
EXIT_CONGRECOVERY(tp->t_flags);
KMOD_TCPSTAT_INC(tcps_ecn_rcwnd);
tp->snd_recover = tp->snd_max;
tp->snd_recover = tp->snd_max + 1;
if (tp->t_flags2 & TF2_ECN_PERMIT)
tp->t_flags2 |= TF2_ECN_SND_CWR;
}
@ -13556,13 +13562,14 @@ rack_output(struct tcpcb *tp)
#endif
ip->ip_tos |= IPTOS_ECN_ECT0;
KMOD_TCPSTAT_INC(tcps_ecn_ect0);
}
/*
* Reply with proper ECN notifications.
*/
if (tp->t_flags2 & TF2_ECN_SND_CWR) {
flags |= TH_CWR;
tp->t_flags2 &= ~TF2_ECN_SND_CWR;
/*
* Reply with proper ECN notifications.
* Only set CWR on new data segments.
*/
if (tp->t_flags2 & TF2_ECN_SND_CWR) {
flags |= TH_CWR;
tp->t_flags2 &= ~TF2_ECN_SND_CWR;
}
}
if (tp->t_flags2 & TF2_ECN_SND_ECE)
flags |= TH_ECE;