diff options
author | andre <andre@FreeBSD.org> | 2010-08-18 18:05:54 +0000 |
---|---|---|
committer | andre <andre@FreeBSD.org> | 2010-08-18 18:05:54 +0000 |
commit | 26acc98c1d408fd7878e5399b58433d094b24758 (patch) | |
tree | 49d1aa8b779fb8e531f370e3650bd2c8d1952551 /sys/netinet/tcp_output.c | |
parent | fb7d7246f68844fc4062c081c8cab78a7a9320db (diff) | |
download | FreeBSD-src-26acc98c1d408fd7878e5399b58433d094b24758.zip FreeBSD-src-26acc98c1d408fd7878e5399b58433d094b24758.tar.gz |
If a TCP connection has been idle for one retransmit timeout or more
it must reset its congestion window back to the initial window.
RFC3390 has increased the initial window from 1 segment to up to
4 segments.
The initial window increase of RFC3390 wasn't reflected into the
restart window which remained at its original defaults of 4 segments
for local and 1 segment for all other connections. Both values are
controllable through sysctl net.inet.tcp.local_slowstart_flightsize
and net.inet.tcp.slowstart_flightsize.
The increase helps TCP's slow start algorithm to open up the congestion
window much faster.
Reviewed by: lstewart
MFC after: 1 week
Diffstat (limited to 'sys/netinet/tcp_output.c')
-rw-r--r-- | sys/netinet/tcp_output.c | 41 |
1 files changed, 26 insertions, 15 deletions
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index be8ea53..50d0ee6 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -140,7 +140,7 @@ tcp_output(struct tcpcb *tp) { struct socket *so = tp->t_inpcb->inp_socket; long len, recwin, sendwin; - int off, flags, error; + int off, flags, error, rw; struct mbuf *m; struct ip *ip = NULL; struct ipovly *ipov = NULL; @@ -176,23 +176,34 @@ tcp_output(struct tcpcb *tp) idle = (tp->t_flags & TF_LASTIDLE) || (tp->snd_max == tp->snd_una); if (idle && ticks - tp->t_rcvtime >= tp->t_rxtcur) { /* - * We have been idle for "a while" and no acks are - * expected to clock out any data we send -- - * slow start to get ack "clock" running again. + * If we've been idle for more than one retransmit + * timeout the old congestion window is no longer + * current and we have to reduce it to the restart + * window before we can transmit again. * - * Set the slow-start flight size depending on whether - * this is a local network or not. + * The restart window is the initial window or the last + * CWND, whichever is smaller. + * + * This is done to prevent us from flooding the path with + * a full CWND at wirespeed, overloading router and switch + * buffers along the way. + * + * See RFC5681 Section 4.1. "Restarting Idle Connections". */ - int ss = V_ss_fltsz; + if (V_tcp_do_rfc3390) + rw = min(4 * tp->t_maxseg, + max(2 * tp->t_maxseg, 4380)); #ifdef INET6 - if (isipv6) { - if (in6_localaddr(&tp->t_inpcb->in6p_faddr)) - ss = V_ss_fltsz_local; - } else -#endif /* INET6 */ - if (in_localaddr(tp->t_inpcb->inp_faddr)) - ss = V_ss_fltsz_local; - tp->snd_cwnd = tp->t_maxseg * ss; + else if ((isipv6 ? in6_localaddr(&tp->t_inpcb->in6p_faddr) : + in_localaddr(tp->t_inpcb->inp_faddr))) +#else + else if (in_localaddr(tp->t_inpcb->inp_faddr)) +#endif + rw = V_ss_fltsz_local * tp->t_maxseg; + else + rw = V_ss_fltsz * tp->t_maxseg; + + tp->snd_cwnd = min(rw, tp->snd_cwnd); } tp->t_flags &= ~TF_LASTIDLE; if (idle) { |