summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2000-09-05 21:57:42 +0000
committerNiels Provos <provos@cvs.openbsd.org>2000-09-05 21:57:42 +0000
commitbd283c54e9b0fb364bc2573d357bf401b661b747 (patch)
tree74d5cff36092378594e3baf96ad1da74f036a829
parent20def5508e57c7205c4776a54a03e0df6aa4f3cd (diff)
various fixes to SACK and FACK from adesai@cisco.com, tomh@tomh.org and
osuga@mml.yrp.nttdocomo.co.jp
-rw-r--r--sys/netinet/tcp_input.c28
-rw-r--r--sys/netinet/tcp_output.c24
2 files changed, 41 insertions, 11 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index e84f649e326..33a38b7dee4 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.68 2000/07/27 04:05:26 itojun Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.69 2000/09/05 21:57:41 provos Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -1563,9 +1563,7 @@ trimthenstep6:
* False fast retx after
* timeout. Do not cut window.
*/
- tp->snd_cwnd += tp->t_maxseg;
tp->t_dupacks = 0;
- (void) tcp_output(tp);
goto drop;
}
#endif
@@ -1581,13 +1579,13 @@ trimthenstep6:
tp->t_rtt = 0;
tcpstat.tcps_sndrexmitfast++;
#if defined(TCP_SACK) && defined(TCP_FACK)
+ tp->t_dupacks = tcprexmtthresh;
(void) tcp_output(tp);
/*
* During FR, snd_cwnd is held
* constant for FACK.
*/
tp->snd_cwnd = tp->snd_ssthresh;
- tp->t_dupacks = tcprexmtthresh;
#else
/*
* tcp_output() will send
@@ -1663,7 +1661,7 @@ trimthenstep6:
th->th_ack) < tp->snd_ssthresh)
tp->snd_cwnd =
tcp_seq_subtract(tp->snd_max,
- th->th_ack) + tp->t_maxseg;
+ th->th_ack);
tp->t_dupacks = 0;
#if defined(TCP_SACK) && defined(TCP_FACK)
if (SEQ_GT(th->th_ack, tp->snd_fack))
@@ -1680,7 +1678,7 @@ trimthenstep6:
tp->snd_ssthresh)
tp->snd_cwnd =
tcp_seq_subtract(tp->snd_max,
- th->th_ack) + tp->t_maxseg;
+ th->th_ack);
tp->t_dupacks = 0;
}
}
@@ -1739,7 +1737,7 @@ trimthenstep6:
if (cw > tp->snd_ssthresh)
incr = incr * incr / cw;
#if defined (TCP_SACK)
- if (SEQ_GEQ(th->th_ack, tp->snd_last))
+ if (tp->t_dupacks < tcprexmtthresh)
#endif
tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
}
@@ -1759,8 +1757,14 @@ trimthenstep6:
if (SEQ_LT(tp->snd_nxt, tp->snd_una))
tp->snd_nxt = tp->snd_una;
#if defined (TCP_SACK) && defined (TCP_FACK)
- if (SEQ_GT(tp->snd_una, tp->snd_fack))
+ if (SEQ_GT(tp->snd_una, tp->snd_fack)) {
tp->snd_fack = tp->snd_una;
+ /* Update snd_awnd for partial ACK
+ * without any SACK blocks.
+ */
+ tp->snd_awnd = tcp_seq_subtract(tp->snd_nxt,
+ tp->snd_fack) + tp->retran_data;
+ }
#endif
switch (tp->t_state) {
@@ -2546,6 +2550,8 @@ tcp_del_sackholes(tp, th)
tp->snd_numholes--;
} else if (SEQ_LT(cur->start, lastack)) {
cur->start = lastack;
+ if (SEQ_LT(cur->rxmit, cur->start))
+ cur->rxmit = cur->start;
break;
} else
break;
@@ -2588,7 +2594,11 @@ tcp_sack_partialack(tp, th)
* fact that tp->snd_una has not been updated yet. In FACK
* hold snd_cwnd constant during fast recovery.
*/
- tp->snd_cwnd -= (th->th_ack - tp->snd_una - tp->t_maxseg);
+ if (tp->snd_cwnd > (th->th_ack - tp->snd_una)) {
+ tp->snd_cwnd -= th->th_ack - tp->snd_una;
+ tp->snd_cwnd += tp->t_maxseg;
+ } else
+ tp->snd_cwnd = tp->t_maxseg;
#endif
return 1;
}
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 07164c6ff8a..a746eea1b41 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_output.c,v 1.30 2000/02/21 21:42:13 provos Exp $ */
+/* $OpenBSD: tcp_output.c,v 1.31 2000/09/05 21:57:41 provos Exp $ */
/* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */
/*
@@ -127,7 +127,17 @@ register struct tcpcb *tp;
return 0;
p = tp->snd_holes;
while (p) {
+#ifndef TCP_FACK
if (p->dups >= tcprexmtthresh && SEQ_LT(p->rxmit, p->end)) {
+#else
+ /* In FACK, if p->dups is less than tcprexmtthresh, but
+ * snd_fack advances more than tcprextmtthresh * tp->t_maxseg,
+ * tcp_input() will try fast retransmit. This forces output.
+ */
+ if ((p->dups >= tcprexmtthresh ||
+ tp->t_dupacks == tcprexmtthresh) &&
+ SEQ_LT(p->rxmit, p->end)) {
+#endif /* TCP_FACK */
if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */
p = p->next;
continue;
@@ -235,6 +245,15 @@ again:
tcp_sack_adjust(tp);
#endif
off = tp->snd_nxt - tp->snd_una;
+#if defined(TCP_SACK) && defined(TCP_FACK)
+ /* Normally, sendable data is limited by off < tp->snd_cwnd.
+ * But in FACK, sendable data is limited by snd_awnd < snd_cwnd,
+ * regardless of offset.
+ */
+ if (!tp->sack_disable && (tp->t_dupacks > tcprexmtthresh))
+ win = tp->snd_wnd;
+ else
+#endif
win = ulmin(tp->snd_wnd, tp->snd_cwnd);
flags = tcp_outflags[tp->t_state];
@@ -248,7 +267,8 @@ again:
* now, and we previously incremented snd_cwnd in tcp_input().
*/
if (!tp->sack_disable && !sendalot) {
- if ((p = tcp_sack_output(tp))) {
+ if (tp->t_dupacks >= tcprexmtthresh &&
+ (p = tcp_sack_output(tp))) {
off = p->rxmit - tp->snd_una;
sack_rxmit = 1;
#if 0