diff options
author | Niels Provos <provos@cvs.openbsd.org> | 2000-02-21 21:42:14 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 2000-02-21 21:42:14 +0000 |
commit | 8e5ea50ac7894e04a29346fc325a5926926bda49 (patch) | |
tree | 6bf90e4f39e004c1211b750b02527775fb9ef3d2 | |
parent | 7686a9d107cbe24bfc6976fcf40b4eb9607eed1c (diff) |
TCP SACK fixes via Tom Henderson (tomh@cs.berkeley.edu):
- tcp_sack_adjust() was completely rewritten, since it was erroneously
referencing receiver side sequence numbers and comparing with sender
side sequence numbers (thanks to Arun Desai (adesai@cisco.com) who
discovered the problem)
- in tcp_output(), moved assignment of sendalot=0 to the piece of code
immediately following the search for sack-eligible retransmissions
(bug identified by Arun Desai).
- tcp_input() was not clearing t_dupacks if fewer than three dupacks arrived
between acks of new data. (bug identified by Gaurav Banga (gaurav@netapp.com))
-rw-r--r-- | sys/netinet/tcp_input.c | 4 | ||||
-rw-r--r-- | sys/netinet/tcp_output.c | 53 |
2 files changed, 35 insertions, 22 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 5b28a0fd020..d84f9583b87 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.56 1999/12/21 17:49:28 provos Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.57 2000/02/21 21:42:13 provos Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -1672,6 +1672,8 @@ trimthenstep6: tp->t_dupacks = 0; } } + if (tp->t_dupacks < tcprexmtthresh) + tp->t_dupacks = 0; #else /* else no TCP_SACK */ if (tp->t_dupacks >= tcprexmtthresh && tp->snd_cwnd > tp->snd_ssthresh) diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 6d6cf41dfa6..07164c6ff8a 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_output.c,v 1.29 2000/01/07 00:57:54 itojun Exp $ */ +/* $OpenBSD: tcp_output.c,v 1.30 2000/02/21 21:42:13 provos Exp $ */ /* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */ /* @@ -152,19 +152,30 @@ void tcp_sack_adjust(tp) struct tcpcb *tp; { - int i; - - for (i = 0; i < tp->rcv_numsacks; i++) { - if (SEQ_LT(tp->snd_nxt, tp->sackblks[i].start)) - break; - if (SEQ_LEQ(tp->sackblks[i].end, tp->snd_nxt)) - continue; - if (tp->sackblks[i].start == 0 && tp->sackblks[i].end == 0) - continue; - /* snd_nxt must be in middle of block of SACKed data */ - tp->snd_nxt = tp->sackblks[i].end; - break; + struct sackhole *cur = tp->snd_holes; + if (cur == 0) + return; /* No holes */ + if (SEQ_GEQ(tp->snd_nxt, tp->rcv_lastsack)) + return; /* We're already beyond any SACKed blocks */ + /* + * Two cases for which we want to advance snd_nxt: + * i) snd_nxt lies between end of one hole and beginning of another + * ii) snd_nxt lies between end of last hole and rcv_lastsack + */ + while (cur->next) { + if (SEQ_LT(tp->snd_nxt, cur->end)) + return; + if (SEQ_GEQ(tp->snd_nxt, cur->next->start)) + cur = cur->next; + else { + tp->snd_nxt = cur->next->start; + return; + } } + if (SEQ_LT(tp->snd_nxt, cur->end)) + return; + tp->snd_nxt = tp->rcv_lastsack; + return; } #endif /* TCP_SACK */ @@ -182,7 +193,7 @@ tcp_output(tp) register struct tcphdr *th; u_char opt[MAX_TCPOPTLEN]; unsigned int optlen, hdrlen; - int idle, sendalot; + int idle, sendalot = 0; #ifdef TCP_SACK int i, sack_rxmit = 0; struct sackhole *p; @@ -214,7 +225,6 @@ tcp_output(tp) */ tp->snd_cwnd = tp->t_maxseg; again: - sendalot = 0; #ifdef TCP_SACK /* * If we've recently taken a timeout, snd_max will be greater than @@ -228,12 +238,6 @@ again: win = ulmin(tp->snd_wnd, tp->snd_cwnd); flags = tcp_outflags[tp->t_state]; - /* - * If in persist timeout with window of 0, send 1 byte. - * Otherwise, if window is small but nonzero - * and timer expired, we will send what we can - * and go to transmit state. - */ #ifdef TCP_SACK /* @@ -260,6 +264,13 @@ again: } #endif /* TCP_SACK */ + sendalot = 0; + /* + * If in persist timeout with window of 0, send 1 byte. + * Otherwise, if window is small but nonzero + * and timer expired, we will send what we can + * and go to transmit state. + */ if (tp->t_force) { if (win == 0) { /* |