From 370efe5ac85e97e32cfe78d25183c6f605b4d3e5 Mon Sep 17 00:00:00 2001 From: Lawrence Stewart Date: Mon, 19 Mar 2018 16:37:47 +0000 Subject: Add support for the experimental Internet-Draft "TCP Alternative Backoff with ECN (ABE)" proposal to the New Reno congestion control algorithm module. ABE reduces the amount of congestion window reduction in response to ECN-signalled congestion relative to the loss-inferred congestion response. More details about ABE can be found in the Internet-Draft: https://tools.ietf.org/html/draft-ietf-tcpm-alternativebackoff-ecn The implementation introduces four new sysctls: - net.inet.tcp.cc.abe defaults to 0 (disabled) and can be set to non-zero to enable ABE for ECN-enabled TCP connections. - net.inet.tcp.cc.newreno.beta and net.inet.tcp.cc.newreno.beta_ecn set the multiplicative window decrease factor, specified as a percentage, applied to the congestion window in response to a loss-based or ECN-based congestion signal respectively. They default to the values specified in the draft i.e. beta=50 and beta_ecn=80. - net.inet.tcp.cc.abe_frlossreduce defaults to 0 (disabled) and can be set to non-zero to enable the use of standard beta (50% by default) when repairing loss during an ECN-signalled congestion recovery episode. It enables a more conservative congestion response and is provided for the purposes of experimentation as a result of some discussion at IETF 100 in Singapore. The values of beta and beta_ecn can also be set per-connection by way of the TCP_CCALGOOPT TCP-level socket option and the new CC_NEWRENO_BETA or CC_NEWRENO_BETA_ECN CC algo sub-options. Submitted by: Tom Jones Tested by: Tom Jones , Grenville Armitage Relnotes: Yes Differential Revision: https://reviews.freebsd.org/D11616 --- sys/netinet/cc/cc.c | 11 ++++ sys/netinet/cc/cc.h | 6 ++ sys/netinet/cc/cc_newreno.c | 144 +++++++++++++++++++++++++++++++++++++++++--- sys/netinet/cc/cc_newreno.h | 42 +++++++++++++ 4 files changed, 196 insertions(+), 7 deletions(-) create mode 100644 sys/netinet/cc/cc_newreno.h (limited to 'sys/netinet/cc') diff --git a/sys/netinet/cc/cc.c b/sys/netinet/cc/cc.c index c08cea503445..70022e1b9604 100644 --- a/sys/netinet/cc/cc.c +++ b/sys/netinet/cc/cc.c @@ -327,3 +327,14 @@ SYSCTL_PROC(_net_inet_tcp_cc, OID_AUTO, algorithm, SYSCTL_PROC(_net_inet_tcp_cc, OID_AUTO, available, CTLTYPE_STRING|CTLFLAG_RD, NULL, 0, cc_list_available, "A", "List available congestion control algorithms"); + +VNET_DEFINE(int, cc_do_abe) = 0; +SYSCTL_INT(_net_inet_tcp_cc, OID_AUTO, abe, CTLFLAG_VNET | CTLFLAG_RW, + &VNET_NAME(cc_do_abe), 0, + "Enable draft-ietf-tcpm-alternativebackoff-ecn (TCP Alternative Backoff with ECN)"); + +VNET_DEFINE(int, cc_abe_frlossreduce) = 0; +SYSCTL_INT(_net_inet_tcp_cc, OID_AUTO, abe_frlossreduce, CTLFLAG_VNET | CTLFLAG_RW, + &VNET_NAME(cc_abe_frlossreduce), 0, + "Apply standard beta instead of ABE-beta during ECN-signalled congestion " + "recovery episodes if loss also needs to be repaired"); diff --git a/sys/netinet/cc/cc.h b/sys/netinet/cc/cc.h index 9b6279ded69a..7f16a7cbf046 100644 --- a/sys/netinet/cc/cc.h +++ b/sys/netinet/cc/cc.h @@ -64,6 +64,12 @@ extern struct cc_algo newreno_cc_algo; VNET_DECLARE(struct cc_algo *, default_cc_ptr); #define V_default_cc_ptr VNET(default_cc_ptr) +VNET_DECLARE(int, cc_do_abe); +#define V_cc_do_abe VNET(cc_do_abe) + +VNET_DECLARE(int, cc_abe_frlossreduce); +#define V_cc_abe_frlossreduce VNET(cc_abe_frlossreduce) + /* Define the new net.inet.tcp.cc sysctl tree. */ SYSCTL_DECL(_net_inet_tcp_cc); diff --git a/sys/netinet/cc/cc_newreno.c b/sys/netinet/cc/cc_newreno.c index 107c719b3dd8..a3b29e529cfa 100644 --- a/sys/netinet/cc/cc_newreno.c +++ b/sys/netinet/cc/cc_newreno.c @@ -3,7 +3,7 @@ * * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995 * The Regents of the University of California. - * Copyright (c) 2007-2008,2010 + * Copyright (c) 2007-2008,2010,2014 * Swinburne University of Technology, Melbourne, Australia. * Copyright (c) 2009-2010 Lawrence Stewart * Copyright (c) 2010 The FreeBSD Foundation @@ -48,6 +48,11 @@ * University Research Program Fund at Community Foundation Silicon Valley. * More details are available at: * http://caia.swin.edu.au/urp/newtcp/ + * + * Dec 2014 garmitage@swin.edu.au + * Borrowed code fragments from cc_cdg.c to add modifiable beta + * via sysctls. + * */ #include @@ -69,20 +74,54 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include + +static MALLOC_DEFINE(M_NEWRENO, "newreno data", + "newreno beta values"); + +#define CAST_PTR_INT(X) (*((int*)(X))) +static int newreno_cb_init(struct cc_var *ccv); static void newreno_ack_received(struct cc_var *ccv, uint16_t type); static void newreno_after_idle(struct cc_var *ccv); static void newreno_cong_signal(struct cc_var *ccv, uint32_t type); static void newreno_post_recovery(struct cc_var *ccv); +static int newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf); + +static VNET_DEFINE(uint32_t, newreno_beta) = 50; +static VNET_DEFINE(uint32_t, newreno_beta_ecn) = 80; +#define V_newreno_beta VNET(newreno_beta) +#define V_newreno_beta_ecn VNET(newreno_beta_ecn) struct cc_algo newreno_cc_algo = { .name = "newreno", + .cb_init = newreno_cb_init, .ack_received = newreno_ack_received, .after_idle = newreno_after_idle, .cong_signal = newreno_cong_signal, .post_recovery = newreno_post_recovery, + .ctl_output = newreno_ctl_output, +}; + +struct newreno { + uint32_t beta; + uint32_t beta_ecn; }; +int +newreno_cb_init(struct cc_var *ccv) +{ + struct newreno *nreno; + + nreno = malloc(sizeof(struct newreno), M_NEWRENO, M_NOWAIT|M_ZERO); + if (nreno != NULL) { + nreno->beta = V_newreno_beta; + nreno->beta_ecn = V_newreno_beta_ecn; + } + + return (0); +} + static void newreno_ack_received(struct cc_var *ccv, uint16_t type) { @@ -184,27 +223,48 @@ newreno_after_idle(struct cc_var *ccv) static void newreno_cong_signal(struct cc_var *ccv, uint32_t type) { - u_int win; + struct newreno *nreno; + uint32_t cwin, factor; + u_int mss; + + factor = V_newreno_beta; + nreno = ccv->cc_data; + if (nreno != NULL) { + if (V_cc_do_abe) + factor = (type == CC_ECN ? nreno->beta_ecn: nreno->beta); + else + factor = nreno->beta; + } + + cwin = CCV(ccv, snd_cwnd); + mss = CCV(ccv, t_maxseg); /* Catch algos which mistakenly leak private signal types. */ KASSERT((type & CC_SIGPRIVMASK) == 0, ("%s: congestion signal type 0x%08x is private\n", __func__, type)); - win = max(CCV(ccv, snd_cwnd) / 2 / CCV(ccv, t_maxseg), 2) * - CCV(ccv, t_maxseg); + cwin = max(((uint64_t)cwin * (uint64_t)factor) / (100ULL * (uint64_t)mss), + 2) * mss; switch (type) { case CC_NDUPACK: if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { + if (IN_CONGRECOVERY(CCV(ccv, t_flags) && + V_cc_do_abe && V_cc_abe_frlossreduce)) { + CCV(ccv, snd_ssthresh) = + ((uint64_t)CCV(ccv, snd_ssthresh) * + (uint64_t)nreno->beta) / + (100ULL * (uint64_t)nreno->beta_ecn); + } if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) - CCV(ccv, snd_ssthresh) = win; + CCV(ccv, snd_ssthresh) = cwin; ENTER_RECOVERY(CCV(ccv, t_flags)); } break; case CC_ECN: if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { - CCV(ccv, snd_ssthresh) = win; - CCV(ccv, snd_cwnd) = win; + CCV(ccv, snd_ssthresh) = cwin; + CCV(ccv, snd_cwnd) = cwin; ENTER_CONGRECOVERY(CCV(ccv, t_flags)); } break; @@ -242,5 +302,75 @@ newreno_post_recovery(struct cc_var *ccv) } } +int +newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf) +{ + struct newreno *nreno; + struct cc_newreno_opts *opt; + + if (sopt->sopt_valsize != sizeof(struct cc_newreno_opts)) + return (EMSGSIZE); + + nreno = ccv->cc_data; + opt = buf; + + switch (sopt->sopt_dir) { + case SOPT_SET: + switch (opt->name) { + case CC_NEWRENO_BETA: + nreno->beta = opt->val; + break; + case CC_NEWRENO_BETA_ECN: + if (!V_cc_do_abe) + return (EACCES); + nreno->beta_ecn = opt->val; + break; + default: + return (ENOPROTOOPT); + } + case SOPT_GET: + switch (opt->name) { + case CC_NEWRENO_BETA: + opt->val = nreno->beta; + break; + case CC_NEWRENO_BETA_ECN: + opt->val = nreno->beta_ecn; + break; + default: + return (ENOPROTOOPT); + } + default: + return (EINVAL); + } + + return (0); +} + +static int +newreno_beta_handler(SYSCTL_HANDLER_ARGS) +{ + if (req->newptr != NULL ) { + if (arg1 == &VNET_NAME(newreno_beta_ecn) && !V_cc_do_abe) + return (EACCES); + if (CAST_PTR_INT(req->newptr) <= 0 || CAST_PTR_INT(req->newptr) > 100) + return (EINVAL); + } + + return (sysctl_handle_int(oidp, arg1, arg2, req)); +} + +SYSCTL_DECL(_net_inet_tcp_cc_newreno); +SYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, newreno, CTLFLAG_RW, NULL, + "New Reno related settings"); + +SYSCTL_PROC(_net_inet_tcp_cc_newreno, OID_AUTO, beta, + CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, + &VNET_NAME(newreno_beta), 3, &newreno_beta_handler, "IU", + "New Reno beta, specified as number between 1 and 100"); + +SYSCTL_PROC(_net_inet_tcp_cc_newreno, OID_AUTO, beta_ecn, + CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, + &VNET_NAME(newreno_beta_ecn), 3, &newreno_beta_handler, "IU", + "New Reno beta ecn, specified as number between 1 and 100"); DECLARE_CC_MODULE(newreno, &newreno_cc_algo); diff --git a/sys/netinet/cc/cc_newreno.h b/sys/netinet/cc/cc_newreno.h new file mode 100644 index 000000000000..9e2a3cff5fe9 --- /dev/null +++ b/sys/netinet/cc/cc_newreno.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2017 Tom Jones + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CC_NEWRENO_H +#define _CC_NEWRENO_H + +#define CCALGONAME_NEWRENO "newreno" + +struct cc_newreno_opts { + int name; + uint32_t val; +}; + +#define CC_NEWRENO_BETA 1 +#define CC_NEWRENO_BETA_ECN 2 + +#endif /* _CC_NEWRENO_H */ -- cgit v1.2.3