summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_output.c
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2010-08-18 18:05:54 +0000
committerandre <andre@FreeBSD.org>2010-08-18 18:05:54 +0000
commit26acc98c1d408fd7878e5399b58433d094b24758 (patch)
tree49d1aa8b779fb8e531f370e3650bd2c8d1952551 /sys/netinet/tcp_output.c
parentfb7d7246f68844fc4062c081c8cab78a7a9320db (diff)
downloadFreeBSD-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.c41
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) {
OpenPOWER on IntegriCloud