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 @@ -163,16 +163,30 @@ &VNET_NAME(tcp_do_rfc3042), 0, "Enable RFC 3042 (Limited Transmit)"); -VNET_DEFINE(int, tcp_do_rfc3390) = 1; -SYSCTL_INT(_net_inet_tcp, OID_AUTO, rfc3390, CTLFLAG_VNET | CTLFLAG_RW, - &VNET_NAME(tcp_do_rfc3390), 0, +VNET_DEFINE(int, tcp_do_rfc3390); +static int tcp_sysctl_rfc3390_handler(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rfc3390, + CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW, + &VNET_NAME(tcp_do_rfc3390), 0, &tcp_sysctl_rfc3390_handler, "I", "Enable RFC 3390 (Increasing TCP's Initial Congestion Window)"); +VNET_DEFINE(int, tcp_do_rfc6928); +static int tcp_sysctl_rfc6928_handler(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rfc6928, + CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW, + &VNET_NAME(tcp_do_rfc6928), 0, &tcp_sysctl_rfc6928_handler, "I", + "Enable RFC 6928 (Increasing TCP's Initial Congestion Window)"); + VNET_DEFINE(int, tcp_initcwnd_segments) = 10; 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) = 14600; +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 +363,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 +3814,75 @@ 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. + * + * RFC3390: min (4*MSS, max (2*MSS, 4380)) + * RFC6928: min (10*MSS, max (2*MSS, 14600)) + * code: max(2*MSS, min(initcwnd_segments * MSS, initcwnd_bytes)) + */ +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_bytes >= 4380) + initcwnd = max(2 * maxseg, + min(V_tcp_initcwnd_segments * maxseg, + V_tcp_initcwnd_bytes)); + 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); +} + +static int +tcp_sysctl_rfc3390_handler(SYSCTL_HANDLER_ARGS) +{ + int error, new; + + new = V_tcp_do_rfc3390; + error = sysctl_handle_int(oidp, &new, 0, req); + if (error == 0 && req->newptr && new == 1) { + V_tcp_initcwnd_segments = 4; + V_tcp_initcwnd_bytes = 4380; + V_tcp_do_rfc3390 = new; + } + + return (error); +} + +static int +tcp_sysctl_rfc6928_handler(SYSCTL_HANDLER_ARGS) +{ + int error, new; + + new = V_tcp_do_rfc6928; + error = sysctl_handle_int(oidp, &new, 0, req); + if (error == 0 && req->newptr && new == 1) { + V_tcp_initcwnd_segments = 10; + V_tcp_initcwnd_bytes = 14600; + V_tcp_do_rfc6928 = new; + } + + return (error); +} 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)