git: 4e28874a6048 - main - When TCP ECN decides it wants to assure an ACK is sent it needs to do it correctly and with some limits.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 25 Feb 2026 13:03:46 UTC
The branch main has been updated by rrs:
URL: https://cgit.FreeBSD.org/src/commit/?id=4e28874a6048f3c5a72a42b5bcfcfc7e71cad8a6
commit 4e28874a6048f3c5a72a42b5bcfcfc7e71cad8a6
Author: Randall Stewart <rrs@FreeBSD.org>
AuthorDate: 2026-02-25 12:59:04 +0000
Commit: Randall Stewart <rrs@FreeBSD.org>
CommitDate: 2026-02-25 13:03:33 +0000
When TCP ECN decides it wants to assure an ACK is sent it needs to do it correctly and with some limits.
So in testing I have found two interesting cases where ECN is going
to make it so that an ack will be sent right away. These cases need
to be limited to being in the ESTABLISHED state. You don't want ECN
sending ACK's when we are transitioning in front or end states.
Also we don't start a delayed ack timer <and> at the same time set
the ACKNOW flag, thats just plain wrong.
Reviewed by: tuexen, rscheff
Differential Revision:<https://reviews.freebsd.org/D55460>
---
sys/netinet/tcp_ecn.c | 5 ++++-
sys/netinet/tcp_input.c | 7 +++++--
sys/netinet/tcp_stacks/rack.c | 5 ++++-
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/sys/netinet/tcp_ecn.c b/sys/netinet/tcp_ecn.c
index 31b9418c5fc2..fb650831289e 100644
--- a/sys/netinet/tcp_ecn.c
+++ b/sys/netinet/tcp_ecn.c
@@ -353,7 +353,10 @@ tcp_ecn_input_segment(struct tcpcb *tp, uint16_t thflags, int tlen, int pkts, in
}
if (thflags & TH_CWR) {
tp->t_flags2 &= ~TF2_ECN_SND_ECE;
- tp->t_flags |= TF_ACKNOW;
+ if ((tp->t_state == TCPS_ESTABLISHED) ||
+ (tp->t_state == TCPS_FIN_WAIT_1) ||
+ (tp->t_state == TCPS_FIN_WAIT_2))
+ tp->t_flags |= TF_ACKNOW;
}
if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
tp->t_flags2 |= TF2_ECN_SND_ECE;
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index c015995ffc7a..35a9d7633fa7 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -539,9 +539,12 @@ cc_ecnpkt_handler_flags(struct tcpcb *tp, uint16_t flags, uint8_t iptos)
CC_ALGO(tp)->ecnpkt_handler(&tp->t_ccv);
- if (tp->t_ccv.flags & CCF_ACKNOW) {
- tcp_timer_activate(tp, TT_DELACK, tcp_delacktime);
+ if (((tp->t_state == TCPS_ESTABLISHED) ||
+ (tp->t_state == TCPS_FIN_WAIT_1) ||
+ (tp->t_state == TCPS_FIN_WAIT_2)) &&
+ (tp->t_ccv.flags & CCF_ACKNOW)) {
tp->t_flags |= TF_ACKNOW;
+ tp->t_ccv.flags &= ~CCF_ACKNOW;
}
}
}
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 42c6757b4b2a..78b0026a8c5d 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -15709,6 +15709,8 @@ rack_do_compressed_ack_processing(struct tcpcb *tp, struct socket *so, struct mb
tcp_packets_this_ack(tp, ae->ack),
ae->codepoint))
rack_cong_signal(tp, CC_ECN, ae->ack, __LINE__);
+ if (tp->t_flags & TF_ACKNOW)
+ rack->r_wanted_output = 1;
#ifdef TCP_ACCOUNTING
/* Count for the specific type of ack in */
if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
@@ -16566,7 +16568,8 @@ rack_do_segment_nounlock(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
tcp_packets_this_ack(tp, th->th_ack),
iptos))
rack_cong_signal(tp, CC_ECN, th->th_ack, __LINE__);
-
+ if (tp->t_flags & TF_ACKNOW)
+ rack->r_wanted_output = 1;
/*
* If echoed timestamp is later than the current time, fall back to
* non RFC1323 RTT calculation. Normalize timestamp if syncookies