Index: sys/netinet/cc/cc_newreno.c =================================================================== --- sys/netinet/cc/cc_newreno.c +++ sys/netinet/cc/cc_newreno.c @@ -151,7 +151,7 @@ static void newreno_after_idle(struct cc_var *ccv) { - int rw; + u_long rw; /* * If we've been idle for more than one retransmit timeout the old @@ -166,11 +166,7 @@ * * See RFC5681 Section 4.1. "Restarting Idle Connections". */ - if (V_tcp_do_rfc3390) - rw = min(4 * CCV(ccv, t_maxseg), - max(2 * CCV(ccv, t_maxseg), 4380)); - else - rw = CCV(ccv, t_maxseg) * 2; + rw = tcp_initcwnd(ccv->ccvc.tcp, CCV(ccv, t_maxseg)); CCV(ccv, snd_cwnd) = min(rw, CCV(ccv, snd_cwnd)); } Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -168,11 +168,21 @@ &VNET_NAME(tcp_do_rfc3390), 0, "Enable RFC 3390 (Increasing TCP's Initial Congestion Window)"); -VNET_DEFINE(int, tcp_initcwnd_segments) = 10; +VNET_DEFINE(int, tcp_do_rfc6928) = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, rfc6928, CTLFLAG_VNET | CTLFLAG_RW, + &VNET_NAME(tcp_do_rfc6928), 0, + "Enable RFC 6928 (Increasing TCP's Initial Congestion Window)"); + +VNET_DEFINE(int, tcp_initcwnd_segments) = 0; SYSCTL_INT(_net_inet_tcp, OID_AUTO, initcwnd_segments, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_initcwnd_segments), 0, "Slow-start flight size (initial congestion window) in number of segments"); +VNET_DEFINE(int, tcp_initcwnd_bytes) = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, initcwnd_bytes, + CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_initcwnd_bytes), 0, + "Slow-start flight size (initial congestion window) in number of bytes"); + VNET_DEFINE(int, tcp_do_rfc3465) = 1; SYSCTL_INT(_net_inet_tcp, OID_AUTO, rfc3465, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_do_rfc3465), 0, @@ -349,34 +359,8 @@ TCPSTAT_INC(tcps_usedssthresh); } - /* - * Set the initial slow-start flight size. - * - * RFC5681 Section 3.1 specifies the default conservative values. - * RFC3390 specifies slightly more aggressive values. - * RFC6928 increases it to ten segments. - * Support for user specified value for initial flight size. - * - * If a SYN or SYN/ACK was lost and retransmitted, we have to - * reduce the initial CWND to one segment as congestion is likely - * requiring us to be cautious. - */ - if (tp->snd_cwnd == 1) - tp->snd_cwnd = maxseg; /* SYN(-ACK) lost */ - else if (V_tcp_initcwnd_segments) - tp->snd_cwnd = min(V_tcp_initcwnd_segments * maxseg, - max(2 * maxseg, V_tcp_initcwnd_segments * 1460)); - else if (V_tcp_do_rfc3390) - tp->snd_cwnd = min(4 * maxseg, max(2 * maxseg, 4380)); - else { - /* Per RFC5681 Section 3.1 */ - if (maxseg > 2190) - tp->snd_cwnd = 2 * maxseg; - else if (maxseg > 1095) - tp->snd_cwnd = 3 * maxseg; - else - tp->snd_cwnd = 4 * maxseg; - } + /* Determine the initial congestion window */ + tp->snd_cwnd = tcp_initcwnd(tp, maxseg); if (CC_ALGO(tp)->conn_init != NULL) CC_ALGO(tp)->conn_init(tp->ccv); @@ -3826,3 +3810,51 @@ tp->sackhint.sack_bytes_rexmit - tp->sackhint.sacked_bytes); } + +/* + * Set the initial slow-start flight size. + * + * Support for user specified value for initial flight size. + * RFC6928 increases it to ten segments. + * RFC3390 specifies slightly more aggressive values. + * RFC5681 Section 3.1 specifies the default conservative values. + * + * If a SYN or SYN/ACK was lost and retransmitted, we have to + * reduce the initial CWND to one segment as congestion is likely + * requiring us to be cautious. + * + * Note: The "magic" numbers below are directly derived from the + * referenced RFCs and are kept as such for better readability. + */ +u_long +tcp_initcwnd(struct tcpcb *tp, u_int maxseg) +{ + u_long initcwnd; + if (tp->snd_cwnd == 1) + initcwnd = maxseg; /* SYN(-ACK) lost */ + else if (V_tcp_initcwnd_segments && V_tcp_initcwnd_bytes) + initcwnd = max(V_tcp_initcwnd_bytes, + min(V_tcp_initcwnd_segments * maxseg, + max(2 * maxseg, V_tcp_initcwnd_segments * 1460))); + else if (V_tcp_initcwnd_segments && !V_tcp_initcwnd_bytes) + initcwnd = min(V_tcp_initcwnd_segments * maxseg, + max(2 * maxseg, V_tcp_initcwnd_segments * 1460)); + else if (V_tcp_initcwnd_bytes, !V_tcp_initcwnd_segments) + initcwnd = min(V_tcp_initcwnd_bytes, + max(2 * maxseg, V_tcp_initcwnd_bytes)); + else if (V_tcp_do_rfc6928) + initcwnd = min(10 * maxseg, max(2 * maxseg, 14600)); + else if (V_tcp_do_rfc3390) + initcwnd = min(4 * maxseg, max(2 * maxseg, 4380)); + else { + /* Per RFC5681 Section 3.1 */ + if (maxseg > 2190) + initcwnd = 2 * maxseg; + else if (maxseg > 1095) + initcwnd = 3 * maxseg; + else + initcwnd = 4 * maxseg; + } + + return (initcwnd); +} Index: sys/netinet/tcp_var.h =================================================================== --- sys/netinet/tcp_var.h +++ sys/netinet/tcp_var.h @@ -693,7 +693,9 @@ VNET_DECLARE(int, tcp_minmss); VNET_DECLARE(int, tcp_delack_enabled); VNET_DECLARE(int, tcp_do_rfc3390); +VNET_DECLARE(int, tcp_do_rfc6928); VNET_DECLARE(int, tcp_initcwnd_segments); +VNET_DECLARE(int, tcp_initcwnd_bytes); VNET_DECLARE(int, tcp_sendspace); VNET_DECLARE(int, tcp_recvspace); VNET_DECLARE(int, path_mtu_discovery); @@ -705,7 +707,9 @@ #define V_tcp_minmss VNET(tcp_minmss) #define V_tcp_delack_enabled VNET(tcp_delack_enabled) #define V_tcp_do_rfc3390 VNET(tcp_do_rfc3390) +#define V_tcp_do_rfc6928 VNET(tcp_do_rfc6928) #define V_tcp_initcwnd_segments VNET(tcp_initcwnd_segments) +#define V_tcp_initcwnd_bytes VNET(tcp_initcwnd_bytes) #define V_tcp_sendspace VNET(tcp_sendspace) #define V_tcp_recvspace VNET(tcp_recvspace) #define V_path_mtu_discovery VNET(path_mtu_discovery) @@ -845,6 +849,7 @@ int tcp_newreno(struct tcpcb *, struct tcphdr *); u_long tcp_seq_subtract(u_long, u_long ); int tcp_compute_pipe(struct tcpcb *); +u_long tcp_initcwnd(struct tcpcb *, u_int); static inline void tcp_fields_to_host(struct tcphdr *th)