Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -1762,7 +1762,7 @@ tp->t_rttlow = t; tcp_xmit_timer(tp, TCP_TS_TO_TICKS(t) + 1); - } else if (tp->t_rtttime && + } else if (tp->t_rtseq && SEQ_GT(th->th_ack, tp->t_rtseq)) { if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime) @@ -2581,6 +2581,7 @@ CC_DUPACK); tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rtttime = 0; + tp->t_rtseq = 0; if (tp->t_flags & TF_SACK_PERMIT) { TCPSTAT_INC( tcps_sack_recovery_episode); @@ -2761,7 +2762,7 @@ if (!tp->t_rttlow || tp->t_rttlow > t) tp->t_rttlow = t; tcp_xmit_timer(tp, TCP_TS_TO_TICKS(t) + 1); - } else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) { + } else if (tp->t_rtseq && SEQ_GT(th->th_ack, tp->t_rtseq)) { if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime) tp->t_rttlow = ticks - tp->t_rtttime; tcp_xmit_timer(tp, ticks - tp->t_rtttime); @@ -3481,7 +3482,16 @@ tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); tp->t_rttbest = tp->t_srtt + tp->t_rttvar; } - tp->t_rtttime = 0; + /* + * For the after-idle check, exclude the last RTT and + * set rtttime to the current time. The RTT sample + * is being collected when t_rtseq != 0, so we clear + * t_rtseq instead of t_rtttime. + */ + tp->t_rtttime = ticks; + if (tp->t_rtttime == 0) + tp->t_rtttime--; + tp->t_rtseq = 0; tp->t_rxtshift = 0; /* @@ -3810,6 +3820,7 @@ tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rtttime = 0; + tp->t_rtseq = 0; tp->snd_nxt = th->th_ack; /* * Set snd_cwnd to one segment beyond acknowledged offset. Index: sys/netinet/tcp_output.c =================================================================== --- sys/netinet/tcp_output.c +++ sys/netinet/tcp_output.c @@ -260,7 +260,8 @@ * to send, then transmit; otherwise, investigate further. */ idle = (tp->t_flags & TF_LASTIDLE) || (tp->snd_max == tp->snd_una); - if (idle && ticks - tp->t_rcvtime >= tp->t_rxtcur) + if (idle && (((ticks - tp->t_rcvtime) >= tp->t_rxtcur) || + (tp->t_rtttime && ((ticks - tp->t_rtttime) >= tp->t_rxtcur)))) cc_after_idle(tp); tp->t_flags &= ~TF_LASTIDLE; if (idle) { @@ -1499,9 +1500,13 @@ * Time this transmission if not a retransmission and * not currently timing anything. */ - if (tp->t_rtttime == 0) { + if (tp->t_rtseq ==0) { tp->t_rtttime = ticks; + if (tp->t_rtttime == 0) + tp->t_rtttime--; tp->t_rtseq = startseq; + if (tp->t_rtseq == 0) + tp->t_rtseq++; TCPSTAT_INC(tcps_segstimed); } #ifdef STATS Index: sys/netinet/tcp_sack.c =================================================================== --- sys/netinet/tcp_sack.c +++ sys/netinet/tcp_sack.c @@ -777,6 +777,7 @@ INP_WLOCK_ASSERT(tp->t_inpcb); tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rtttime = 0; + tp->t_rtseq = 0; /* Send one or 2 segments based on how much new data was acked. */ if ((BYTES_THIS_ACK(tp, th) / tp->t_maxseg) >= 2) num_segs = 2; Index: sys/netinet/tcp_stacks/bbr.c =================================================================== --- sys/netinet/tcp_stacks/bbr.c +++ sys/netinet/tcp_stacks/bbr.c @@ -5213,6 +5213,7 @@ tp->snd_recover = tp->snd_max; tp->t_flags |= TF_ACKNOW; tp->t_rtttime = 0; + tp->t_rtseq = 0; out: return (retval); } Index: sys/netinet/tcp_stacks/rack.c =================================================================== --- sys/netinet/tcp_stacks/rack.c +++ sys/netinet/tcp_stacks/rack.c @@ -5886,6 +5886,7 @@ tp->snd_recover = tp->snd_max; tp->t_flags |= TF_ACKNOW; tp->t_rtttime = 0; + tp->t_rtseq = 0; rack_cong_signal(tp, NULL, CC_RTO); out: return (retval); @@ -10993,7 +10994,8 @@ */ if (tp->t_idle_reduce && (tp->snd_max == tp->snd_una) && - ((ticks - tp->t_rcvtime) >= tp->t_rxtcur)) { + (((ticks - tp->t_rcvtime) >= tp->t_rxtcur) || + (tp->t_rtttime && ((ticks - tp->t_rtttime) >= tp->t_rxtcur)))) { counter_u64_add(rack_input_idle_reduces, 1); rack_cc_after_idle(rack, tp); } @@ -12146,7 +12148,8 @@ */ idle = (tp->t_flags & TF_LASTIDLE) || (tp->snd_max == tp->snd_una); if (tp->t_idle_reduce) { - if (idle && ((ticks - tp->t_rcvtime) >= tp->t_rxtcur)) + if (idle && (((ticks - tp->t_rcvtime) >= tp->t_rxtcur) || + (tp->t_rtttime && ((ticks - tp->t_rtttime) >= tp->t_rxtcur)))) rack_cc_after_idle(rack, tp); } tp->t_flags &= ~TF_LASTIDLE; @@ -14044,9 +14047,13 @@ * This is only relevant in case of switching back to * the base stack. */ - if (tp->t_rtttime == 0) { + if (tp->t_rtseq == 0) { tp->t_rtttime = ticks; + if (tp->t_rtttime == 0) + tp->t_rtttime--; tp->t_rtseq = startseq; + if (tp->t_rtseq == 0) + tp->t_rtseq++; KMOD_TCPSTAT_INC(tcps_segstimed); } if (len && Index: sys/netinet/tcp_subr.c =================================================================== --- sys/netinet/tcp_subr.c +++ sys/netinet/tcp_subr.c @@ -2902,6 +2902,7 @@ TCPSTAT_INC(tcps_mturesent); tp->t_rtttime = 0; + tp->t_rtseq = 0; tp->snd_nxt = tp->snd_una; tcp_free_sackholes(tp); tp->snd_recover = tp->snd_max; Index: sys/netinet/tcp_timer.c =================================================================== --- sys/netinet/tcp_timer.c +++ sys/netinet/tcp_timer.c @@ -873,6 +873,7 @@ * If timing a segment in this window, stop the timer. */ tp->t_rtttime = 0; + tp->t_rtseq = 0; cc_cong_signal(tp, NULL, CC_RTO); NET_EPOCH_ENTER(et);