summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_input.c
diff options
context:
space:
mode:
authorjlemon <jlemon@FreeBSD.org>2000-05-06 03:31:09 +0000
committerjlemon <jlemon@FreeBSD.org>2000-05-06 03:31:09 +0000
commit8a3c72bb35758d483f05567e3ff8926bee1a8813 (patch)
tree22b719c35e23206090023b078760d76bcd4627e7 /sys/netinet/tcp_input.c
parent796be5b52651cb1727e79565d25b60e69d1f738a (diff)
downloadFreeBSD-src-8a3c72bb35758d483f05567e3ff8926bee1a8813.zip
FreeBSD-src-8a3c72bb35758d483f05567e3ff8926bee1a8813.tar.gz
Implement TCP NewReno, as documented in RFC 2582. This allows
better recovery for multiple packet losses in a single window. The algorithm can be toggled via the sysctl net.inet.tcp.newreno, which defaults to "on". Submitted by: Jayanth Vijayaraghavan <jayanth@yahoo-inc.com>
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r--sys/netinet/tcp_input.c79
1 files changed, 73 insertions, 6 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 7922253..82ab08f 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -148,6 +148,7 @@ static void tcp_pulloutofband __P((struct socket *,
static int tcp_reass __P((struct tcpcb *, struct tcphdr *, int *,
struct mbuf *));
static void tcp_xmit_timer __P((struct tcpcb *, int));
+static int tcp_newreno __P((struct tcpcb *, struct tcphdr *));
/* Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint. */
#ifdef INET6
@@ -1104,6 +1105,7 @@ findpcb:
tp->irs = th->th_seq;
tcp_sendseqinit(tp);
tcp_rcvseqinit(tp);
+ tp->snd_recover = tp->snd_una;
/*
* Initialization of the tcpcb for transaction;
* set SND.WND = SEG.WND,
@@ -1780,10 +1782,20 @@ trimthenstep6:
u_int win =
min(tp->snd_wnd, tp->snd_cwnd) / 2 /
tp->t_maxseg;
-
+ if (tcp_do_newreno && SEQ_LT(th->th_ack,
+ tp->snd_recover)) {
+ /* False retransmit, should not
+ * cut window
+ */
+ tp->snd_cwnd += tp->t_maxseg;
+ tp->t_dupacks = 0;
+ (void) tcp_output(tp);
+ goto drop;
+ }
if (win < 2)
win = 2;
tp->snd_ssthresh = win * tp->t_maxseg;
+ tp->snd_recover = tp->snd_max;
callout_stop(tp->tt_rexmt);
tp->t_rtttime = 0;
tp->snd_nxt = th->th_ack;
@@ -1807,10 +1819,26 @@ trimthenstep6:
* If the congestion window was inflated to account
* for the other side's cached packets, retract it.
*/
- if (tp->t_dupacks >= tcprexmtthresh &&
- tp->snd_cwnd > tp->snd_ssthresh)
- tp->snd_cwnd = tp->snd_ssthresh;
- tp->t_dupacks = 0;
+ if (tcp_do_newreno == 0) {
+ if (tp->t_dupacks >= tcprexmtthresh &&
+ tp->snd_cwnd > tp->snd_ssthresh)
+ tp->snd_cwnd = tp->snd_ssthresh;
+ tp->t_dupacks = 0;
+ } else if (tp->t_dupacks >= tcprexmtthresh &&
+ !tcp_newreno(tp, th)) {
+ /*
+ * Window inflation should have left us with approx.
+ * snd_ssthresh outstanding data. But in case we
+ * would be inclined to send a burst, better to do
+ * it via the slow start mechanism.
+ */
+ if (SEQ_GT(th->th_ack + tp->snd_ssthresh, tp->snd_max))
+ tp->snd_cwnd =
+ tp->snd_max - th->th_ack + tp->t_maxseg;
+ else
+ tp->snd_cwnd = tp->snd_ssthresh;
+ tp->t_dupacks = 0;
+ }
if (SEQ_GT(th->th_ack, tp->snd_max)) {
tcpstat.tcps_rcvacktoomuch++;
goto dropafterack;
@@ -1903,7 +1931,8 @@ process_ACK:
if (cw > tp->snd_ssthresh)
incr = incr * incr / cw;
- tp->snd_cwnd = min(cw + incr, TCP_MAXWIN << tp->snd_scale);
+ if (tcp_do_newreno == 0 || SEQ_GEQ(th->th_ack, tp->snd_recover))
+ tp->snd_cwnd = min(cw + incr,TCP_MAXWIN<<tp->snd_scale);
}
if (acked > so->so_snd.sb_cc) {
tp->snd_wnd -= so->so_snd.sb_cc;
@@ -2791,3 +2820,41 @@ tcp_mssopt(tp)
return rt->rt_ifp->if_mtu - min_protoh;
}
+
+
+/*
+ * Checks for partial ack. If partial ack arrives, force the retransmission
+ * of the next unacknowledged segment, do not clear tp->t_dupacks, and return
+ * 1. By setting snd_nxt to ti_ack, this forces retransmission timer to
+ * be started again. If the ack advances at least to tp->snd_recover, return 0.
+ */
+static int
+tcp_newreno(tp, th)
+ struct tcpcb *tp;
+ struct tcphdr *th;
+{
+ if (SEQ_LT(th->th_ack, tp->snd_recover)) {
+ tcp_seq onxt = tp->snd_nxt;
+ tcp_seq ouna = tp->snd_una; /* Haven't updated snd_una yet*/
+ u_long ocwnd = tp->snd_cwnd;
+
+ callout_stop(tp->tt_rexmt);
+ tp->t_rtttime = 0;
+ tp->snd_nxt = th->th_ack;
+ tp->snd_cwnd = tp->t_maxseg;
+ tp->snd_una = th->th_ack;
+ (void) tcp_output(tp);
+
+ tp->snd_cwnd = ocwnd;
+ tp->snd_una = ouna;
+ if (SEQ_GT(onxt, tp->snd_nxt))
+ tp->snd_nxt = onxt;
+ /*
+ * Partial window deflation. Relies on fact that tp->snd_una
+ * not updated yet.
+ */
+ tp->snd_cwnd -= (th->th_ack - tp->snd_una - tp->t_maxseg);
+ return (1);
+ }
+ return (0);
+}
OpenPOWER on IntegriCloud