summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_output.c
diff options
context:
space:
mode:
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