Unify the "send high" and "recover" variables as specified in the
lastest rev of the spec. Use an explicit flag for Fast Recovery. [1] Fix bug with exiting Fast Recovery on a retransmit timeout diagnosed by Lu Guohan. [2] Reviewed by: Thomas Henderson <thomas.r.henderson@boeing.com> Reported and tested by: Lu Guohan <lguohan00@mails.tsinghua.edu.cn> [2] Approved by: Thomas Henderson <thomas.r.henderson@boeing.com>, Sally Floyd <floyd@acm.org> [1]
This commit is contained in:
parent
ff40920e9e
commit
9d11646de7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=117650
@ -992,8 +992,7 @@ tcp_input(m, off0)
|
||||
tp->snd_cwnd >= tp->snd_wnd &&
|
||||
((!tcp_do_newreno &&
|
||||
tp->t_dupacks < tcprexmtthresh) ||
|
||||
(tcp_do_newreno &&
|
||||
!SEQ_LT(tp->snd_una, tp->snd_recover)))) {
|
||||
(tcp_do_newreno && !IN_FASTRECOVERY(tp)))) {
|
||||
KASSERT(headlocked, ("headlocked"));
|
||||
INP_INFO_WUNLOCK(&tcbinfo);
|
||||
/*
|
||||
@ -1009,7 +1008,9 @@ tcp_input(m, off0)
|
||||
tp->snd_cwnd = tp->snd_cwnd_prev;
|
||||
tp->snd_ssthresh =
|
||||
tp->snd_ssthresh_prev;
|
||||
tp->snd_high = tp->snd_high_prev;
|
||||
tp->snd_recover = tp->snd_recover_prev;
|
||||
if (tp->t_flags & TF_WASFRECOVERY)
|
||||
ENTER_FASTRECOVERY(tp);
|
||||
tp->snd_nxt = tp->snd_max;
|
||||
tp->t_badrxtwin = 0;
|
||||
}
|
||||
@ -1036,10 +1037,10 @@ tcp_input(m, off0)
|
||||
tcpstat.tcps_rcvackpack++;
|
||||
tcpstat.tcps_rcvackbyte += acked;
|
||||
sbdrop(&so->so_snd, acked);
|
||||
if (SEQ_GT(tp->snd_una, tp->snd_high) &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_high))
|
||||
tp->snd_high = th->th_ack - 1;
|
||||
tp->snd_una = tp->snd_recover = th->th_ack;
|
||||
if (SEQ_GT(tp->snd_una, tp->snd_recover) &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_recover))
|
||||
tp->snd_recover = th->th_ack - 1;
|
||||
tp->snd_una = th->th_ack;
|
||||
/*
|
||||
* pull snd_wl2 up to prevent seq wrap relative
|
||||
* to th_ack.
|
||||
@ -1739,8 +1740,7 @@ tcp_input(m, off0)
|
||||
tp->t_dupacks = 0;
|
||||
else if (++tp->t_dupacks > tcprexmtthresh ||
|
||||
(tcp_do_newreno &&
|
||||
SEQ_LT(tp->snd_una,
|
||||
tp->snd_recover))) {
|
||||
IN_FASTRECOVERY(tp))) {
|
||||
tp->snd_cwnd += tp->t_maxseg;
|
||||
(void) tcp_output(tp);
|
||||
goto drop;
|
||||
@ -1748,7 +1748,8 @@ tcp_input(m, off0)
|
||||
tcp_seq onxt = tp->snd_nxt;
|
||||
u_int win;
|
||||
if (tcp_do_newreno &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_high)) {
|
||||
SEQ_LEQ(th->th_ack,
|
||||
tp->snd_recover)) {
|
||||
tp->t_dupacks = 0;
|
||||
break;
|
||||
}
|
||||
@ -1757,6 +1758,7 @@ tcp_input(m, off0)
|
||||
if (win < 2)
|
||||
win = 2;
|
||||
tp->snd_ssthresh = win * tp->t_maxseg;
|
||||
ENTER_FASTRECOVERY(tp);
|
||||
tp->snd_recover = tp->snd_max;
|
||||
callout_stop(tp->tt_rexmt);
|
||||
tp->t_rtttime = 0;
|
||||
@ -1809,7 +1811,7 @@ tcp_input(m, off0)
|
||||
* for the other side's cached packets, retract it.
|
||||
*/
|
||||
if (tcp_do_newreno) {
|
||||
if (SEQ_LT(tp->snd_una, tp->snd_recover)) {
|
||||
if (IN_FASTRECOVERY(tp)) {
|
||||
if (SEQ_LT(th->th_ack, tp->snd_recover)) {
|
||||
tcp_newreno_partial_ack(tp, th);
|
||||
} else {
|
||||
@ -1879,7 +1881,9 @@ tcp_input(m, off0)
|
||||
++tcpstat.tcps_sndrexmitbad;
|
||||
tp->snd_cwnd = tp->snd_cwnd_prev;
|
||||
tp->snd_ssthresh = tp->snd_ssthresh_prev;
|
||||
tp->snd_high = tp->snd_high_prev;
|
||||
tp->snd_recover = tp->snd_recover_prev;
|
||||
if (tp->t_flags & TF_WASFRECOVERY)
|
||||
ENTER_FASTRECOVERY(tp);
|
||||
tp->snd_nxt = tp->snd_max;
|
||||
tp->t_badrxtwin = 0; /* XXX probably not required */
|
||||
}
|
||||
@ -1933,7 +1937,7 @@ tcp_input(m, off0)
|
||||
* Otherwise open linearly: maxseg per window
|
||||
* (maxseg^2 / cwnd per packet).
|
||||
*/
|
||||
if (!tcp_do_newreno || SEQ_GEQ(tp->snd_una, tp->snd_recover)) {
|
||||
if (!tcp_do_newreno || !IN_FASTRECOVERY(tp)) {
|
||||
register u_int cw = tp->snd_cwnd;
|
||||
register u_int incr = tp->t_maxseg;
|
||||
if (cw > tp->snd_ssthresh)
|
||||
@ -1951,12 +1955,13 @@ tcp_input(m, off0)
|
||||
}
|
||||
sowwakeup(so);
|
||||
/* detect una wraparound */
|
||||
if (SEQ_GEQ(tp->snd_una, tp->snd_recover) &&
|
||||
SEQ_LT(th->th_ack, tp->snd_recover))
|
||||
tp->snd_recover = th->th_ack;
|
||||
if (SEQ_GT(tp->snd_una, tp->snd_high) &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_high))
|
||||
tp->snd_high = th->th_ack - 1;
|
||||
if (tcp_do_newreno && !IN_FASTRECOVERY(tp) &&
|
||||
SEQ_GT(tp->snd_una, tp->snd_recover) &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_recover))
|
||||
tp->snd_recover = th->th_ack - 1;
|
||||
if (tcp_do_newreno && IN_FASTRECOVERY(tp) &&
|
||||
SEQ_GEQ(th->th_ack, tp->snd_recover))
|
||||
EXIT_FASTRECOVERY(tp);
|
||||
tp->snd_una = th->th_ack;
|
||||
if (SEQ_LT(tp->snd_nxt, tp->snd_una))
|
||||
tp->snd_nxt = tp->snd_una;
|
||||
|
@ -992,8 +992,7 @@ tcp_input(m, off0)
|
||||
tp->snd_cwnd >= tp->snd_wnd &&
|
||||
((!tcp_do_newreno &&
|
||||
tp->t_dupacks < tcprexmtthresh) ||
|
||||
(tcp_do_newreno &&
|
||||
!SEQ_LT(tp->snd_una, tp->snd_recover)))) {
|
||||
(tcp_do_newreno && !IN_FASTRECOVERY(tp)))) {
|
||||
KASSERT(headlocked, ("headlocked"));
|
||||
INP_INFO_WUNLOCK(&tcbinfo);
|
||||
/*
|
||||
@ -1009,7 +1008,9 @@ tcp_input(m, off0)
|
||||
tp->snd_cwnd = tp->snd_cwnd_prev;
|
||||
tp->snd_ssthresh =
|
||||
tp->snd_ssthresh_prev;
|
||||
tp->snd_high = tp->snd_high_prev;
|
||||
tp->snd_recover = tp->snd_recover_prev;
|
||||
if (tp->t_flags & TF_WASFRECOVERY)
|
||||
ENTER_FASTRECOVERY(tp);
|
||||
tp->snd_nxt = tp->snd_max;
|
||||
tp->t_badrxtwin = 0;
|
||||
}
|
||||
@ -1036,10 +1037,10 @@ tcp_input(m, off0)
|
||||
tcpstat.tcps_rcvackpack++;
|
||||
tcpstat.tcps_rcvackbyte += acked;
|
||||
sbdrop(&so->so_snd, acked);
|
||||
if (SEQ_GT(tp->snd_una, tp->snd_high) &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_high))
|
||||
tp->snd_high = th->th_ack - 1;
|
||||
tp->snd_una = tp->snd_recover = th->th_ack;
|
||||
if (SEQ_GT(tp->snd_una, tp->snd_recover) &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_recover))
|
||||
tp->snd_recover = th->th_ack - 1;
|
||||
tp->snd_una = th->th_ack;
|
||||
/*
|
||||
* pull snd_wl2 up to prevent seq wrap relative
|
||||
* to th_ack.
|
||||
@ -1739,8 +1740,7 @@ tcp_input(m, off0)
|
||||
tp->t_dupacks = 0;
|
||||
else if (++tp->t_dupacks > tcprexmtthresh ||
|
||||
(tcp_do_newreno &&
|
||||
SEQ_LT(tp->snd_una,
|
||||
tp->snd_recover))) {
|
||||
IN_FASTRECOVERY(tp))) {
|
||||
tp->snd_cwnd += tp->t_maxseg;
|
||||
(void) tcp_output(tp);
|
||||
goto drop;
|
||||
@ -1748,7 +1748,8 @@ tcp_input(m, off0)
|
||||
tcp_seq onxt = tp->snd_nxt;
|
||||
u_int win;
|
||||
if (tcp_do_newreno &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_high)) {
|
||||
SEQ_LEQ(th->th_ack,
|
||||
tp->snd_recover)) {
|
||||
tp->t_dupacks = 0;
|
||||
break;
|
||||
}
|
||||
@ -1757,6 +1758,7 @@ tcp_input(m, off0)
|
||||
if (win < 2)
|
||||
win = 2;
|
||||
tp->snd_ssthresh = win * tp->t_maxseg;
|
||||
ENTER_FASTRECOVERY(tp);
|
||||
tp->snd_recover = tp->snd_max;
|
||||
callout_stop(tp->tt_rexmt);
|
||||
tp->t_rtttime = 0;
|
||||
@ -1809,7 +1811,7 @@ tcp_input(m, off0)
|
||||
* for the other side's cached packets, retract it.
|
||||
*/
|
||||
if (tcp_do_newreno) {
|
||||
if (SEQ_LT(tp->snd_una, tp->snd_recover)) {
|
||||
if (IN_FASTRECOVERY(tp)) {
|
||||
if (SEQ_LT(th->th_ack, tp->snd_recover)) {
|
||||
tcp_newreno_partial_ack(tp, th);
|
||||
} else {
|
||||
@ -1879,7 +1881,9 @@ tcp_input(m, off0)
|
||||
++tcpstat.tcps_sndrexmitbad;
|
||||
tp->snd_cwnd = tp->snd_cwnd_prev;
|
||||
tp->snd_ssthresh = tp->snd_ssthresh_prev;
|
||||
tp->snd_high = tp->snd_high_prev;
|
||||
tp->snd_recover = tp->snd_recover_prev;
|
||||
if (tp->t_flags & TF_WASFRECOVERY)
|
||||
ENTER_FASTRECOVERY(tp);
|
||||
tp->snd_nxt = tp->snd_max;
|
||||
tp->t_badrxtwin = 0; /* XXX probably not required */
|
||||
}
|
||||
@ -1933,7 +1937,7 @@ tcp_input(m, off0)
|
||||
* Otherwise open linearly: maxseg per window
|
||||
* (maxseg^2 / cwnd per packet).
|
||||
*/
|
||||
if (!tcp_do_newreno || SEQ_GEQ(tp->snd_una, tp->snd_recover)) {
|
||||
if (!tcp_do_newreno || !IN_FASTRECOVERY(tp)) {
|
||||
register u_int cw = tp->snd_cwnd;
|
||||
register u_int incr = tp->t_maxseg;
|
||||
if (cw > tp->snd_ssthresh)
|
||||
@ -1951,12 +1955,13 @@ tcp_input(m, off0)
|
||||
}
|
||||
sowwakeup(so);
|
||||
/* detect una wraparound */
|
||||
if (SEQ_GEQ(tp->snd_una, tp->snd_recover) &&
|
||||
SEQ_LT(th->th_ack, tp->snd_recover))
|
||||
tp->snd_recover = th->th_ack;
|
||||
if (SEQ_GT(tp->snd_una, tp->snd_high) &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_high))
|
||||
tp->snd_high = th->th_ack - 1;
|
||||
if (tcp_do_newreno && !IN_FASTRECOVERY(tp) &&
|
||||
SEQ_GT(tp->snd_una, tp->snd_recover) &&
|
||||
SEQ_LEQ(th->th_ack, tp->snd_recover))
|
||||
tp->snd_recover = th->th_ack - 1;
|
||||
if (tcp_do_newreno && IN_FASTRECOVERY(tp) &&
|
||||
SEQ_GEQ(th->th_ack, tp->snd_recover))
|
||||
EXIT_FASTRECOVERY(tp);
|
||||
tp->snd_una = th->th_ack;
|
||||
if (SEQ_LT(tp->snd_nxt, tp->snd_una))
|
||||
tp->snd_nxt = tp->snd_una;
|
||||
|
@ -73,7 +73,7 @@
|
||||
|
||||
#define tcp_sendseqinit(tp) \
|
||||
(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
|
||||
(tp)->snd_recover = (tp)->snd_high = (tp)->iss
|
||||
(tp)->snd_recover = (tp)->iss
|
||||
|
||||
#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * hz)
|
||||
/* timestamp wrap-around time */
|
||||
|
@ -528,7 +528,11 @@ tcp_timer_rexmt(xtp)
|
||||
*/
|
||||
tp->snd_cwnd_prev = tp->snd_cwnd;
|
||||
tp->snd_ssthresh_prev = tp->snd_ssthresh;
|
||||
tp->snd_high_prev = tp->snd_high;
|
||||
tp->snd_recover_prev = tp->snd_recover;
|
||||
if (IN_FASTRECOVERY(tp))
|
||||
tp->t_flags |= TF_WASFRECOVERY;
|
||||
else
|
||||
tp->t_flags &= ~TF_WASFRECOVERY;
|
||||
tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1));
|
||||
}
|
||||
tcpstat.tcps_rexmttimeo++;
|
||||
@ -566,7 +570,7 @@ tcp_timer_rexmt(xtp)
|
||||
tp->t_srtt = 0;
|
||||
}
|
||||
tp->snd_nxt = tp->snd_una;
|
||||
tp->snd_high = tp->snd_max;
|
||||
tp->snd_recover = tp->snd_max;
|
||||
/*
|
||||
* Force a segment to be sent.
|
||||
*/
|
||||
@ -607,6 +611,7 @@ tcp_timer_rexmt(xtp)
|
||||
tp->snd_ssthresh = win * tp->t_maxseg;
|
||||
tp->t_dupacks = 0;
|
||||
}
|
||||
EXIT_FASTRECOVERY(tp);
|
||||
(void) tcp_output(tp);
|
||||
|
||||
out:
|
||||
|
@ -83,26 +83,28 @@ struct tcpcb {
|
||||
struct inpcb *t_inpcb; /* back pointer to internet pcb */
|
||||
int t_state; /* state of this connection */
|
||||
u_int t_flags;
|
||||
#define TF_ACKNOW 0x00001 /* ack peer immediately */
|
||||
#define TF_DELACK 0x00002 /* ack, but try to delay it */
|
||||
#define TF_NODELAY 0x00004 /* don't delay packets to coalesce */
|
||||
#define TF_NOOPT 0x00008 /* don't use tcp options */
|
||||
#define TF_SENTFIN 0x00010 /* have sent FIN */
|
||||
#define TF_REQ_SCALE 0x00020 /* have/will request window scaling */
|
||||
#define TF_RCVD_SCALE 0x00040 /* other side has requested scaling */
|
||||
#define TF_REQ_TSTMP 0x00080 /* have/will request timestamps */
|
||||
#define TF_RCVD_TSTMP 0x00100 /* a timestamp was received in SYN */
|
||||
#define TF_SACK_PERMIT 0x00200 /* other side said I could SACK */
|
||||
#define TF_NEEDSYN 0x00400 /* send SYN (implicit state) */
|
||||
#define TF_NEEDFIN 0x00800 /* send FIN (implicit state) */
|
||||
#define TF_NOPUSH 0x01000 /* don't push */
|
||||
#define TF_REQ_CC 0x02000 /* have/will request CC */
|
||||
#define TF_RCVD_CC 0x04000 /* a CC was received in SYN */
|
||||
#define TF_SENDCCNEW 0x08000 /* send CCnew instead of CC in SYN */
|
||||
#define TF_MORETOCOME 0x10000 /* More data to be appended to sock */
|
||||
#define TF_LQ_OVERFLOW 0x20000 /* listen queue overflow */
|
||||
#define TF_LASTIDLE 0x40000 /* connection was previously idle */
|
||||
#define TF_RXWIN0SENT 0x80000 /* sent a receiver win 0 in response */
|
||||
#define TF_ACKNOW 0x000001 /* ack peer immediately */
|
||||
#define TF_DELACK 0x000002 /* ack, but try to delay it */
|
||||
#define TF_NODELAY 0x000004 /* don't delay packets to coalesce */
|
||||
#define TF_NOOPT 0x000008 /* don't use tcp options */
|
||||
#define TF_SENTFIN 0x000010 /* have sent FIN */
|
||||
#define TF_REQ_SCALE 0x000020 /* have/will request window scaling */
|
||||
#define TF_RCVD_SCALE 0x000040 /* other side has requested scaling */
|
||||
#define TF_REQ_TSTMP 0x000080 /* have/will request timestamps */
|
||||
#define TF_RCVD_TSTMP 0x000100 /* a timestamp was received in SYN */
|
||||
#define TF_SACK_PERMIT 0x000200 /* other side said I could SACK */
|
||||
#define TF_NEEDSYN 0x000400 /* send SYN (implicit state) */
|
||||
#define TF_NEEDFIN 0x000800 /* send FIN (implicit state) */
|
||||
#define TF_NOPUSH 0x001000 /* don't push */
|
||||
#define TF_REQ_CC 0x002000 /* have/will request CC */
|
||||
#define TF_RCVD_CC 0x004000 /* a CC was received in SYN */
|
||||
#define TF_SENDCCNEW 0x008000 /* send CCnew instead of CC in SYN */
|
||||
#define TF_MORETOCOME 0x010000 /* More data to be appended to sock */
|
||||
#define TF_LQ_OVERFLOW 0x020000 /* listen queue overflow */
|
||||
#define TF_LASTIDLE 0x040000 /* connection was previously idle */
|
||||
#define TF_RXWIN0SENT 0x080000 /* sent a receiver win 0 in response */
|
||||
#define TF_FASTRECOVERY 0x100000 /* in NewReno Fast Recovery */
|
||||
#define TF_WASFRECOVERY 0x200000 /* was in NewReno Fast Recovery */
|
||||
int t_force; /* 1 if forcing out a byte */
|
||||
|
||||
tcp_seq snd_una; /* send unacknowledged */
|
||||
@ -131,7 +133,6 @@ struct tcpcb {
|
||||
*/
|
||||
u_long snd_bandwidth; /* calculated bandwidth or 0 */
|
||||
tcp_seq snd_recover; /* for use in NewReno Fast Recovery */
|
||||
tcp_seq snd_high; /* for use in NewReno Fast Recovery */
|
||||
|
||||
u_int t_maxopd; /* mss plus options */
|
||||
|
||||
@ -175,11 +176,15 @@ struct tcpcb {
|
||||
/* experimental */
|
||||
u_long snd_cwnd_prev; /* cwnd prior to retransmit */
|
||||
u_long snd_ssthresh_prev; /* ssthresh prior to retransmit */
|
||||
tcp_seq snd_high_prev; /* snd_high prior to retransmit */
|
||||
tcp_seq snd_recover_prev; /* snd_recover prior to retransmit */
|
||||
u_long t_badrxtwin; /* window for retransmit recovery */
|
||||
u_char snd_limited; /* segments limited transmitted */
|
||||
};
|
||||
|
||||
#define IN_FASTRECOVERY(tp) (tp->t_flags & TF_FASTRECOVERY)
|
||||
#define ENTER_FASTRECOVERY(tp) tp->t_flags |= TF_FASTRECOVERY
|
||||
#define EXIT_FASTRECOVERY(tp) tp->t_flags &= ~TF_FASTRECOVERY
|
||||
|
||||
/*
|
||||
* Structure to hold TCP options that are only used during segment
|
||||
* processing (in tcp_input), but not held in the tcpcb.
|
||||
|
Loading…
Reference in New Issue
Block a user