Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/cc/cc_newreno.c
Show First 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | |||||
#include <netinet/cc/cc_module.h> | #include <netinet/cc/cc_module.h> | ||||
#include <netinet/cc/cc_newreno.h> | #include <netinet/cc/cc_newreno.h> | ||||
static MALLOC_DEFINE(M_NEWRENO, "newreno data", | static MALLOC_DEFINE(M_NEWRENO, "newreno data", | ||||
"newreno beta values"); | "newreno beta values"); | ||||
#define CAST_PTR_INT(X) (*((int*)(X))) | #define CAST_PTR_INT(X) (*((int*)(X))) | ||||
static int newreno_cb_init(struct cc_var *ccv); | static void newreno_cb_destroy(struct cc_var *ccv); | ||||
static void newreno_ack_received(struct cc_var *ccv, uint16_t type); | static void newreno_ack_received(struct cc_var *ccv, uint16_t type); | ||||
static void newreno_after_idle(struct cc_var *ccv); | static void newreno_after_idle(struct cc_var *ccv); | ||||
static void newreno_cong_signal(struct cc_var *ccv, uint32_t type); | static void newreno_cong_signal(struct cc_var *ccv, uint32_t type); | ||||
static void newreno_post_recovery(struct cc_var *ccv); | static void newreno_post_recovery(struct cc_var *ccv); | ||||
static int newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf); | 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) = 50; | ||||
static VNET_DEFINE(uint32_t, newreno_beta_ecn) = 80; | static VNET_DEFINE(uint32_t, newreno_beta_ecn) = 80; | ||||
#define V_newreno_beta VNET(newreno_beta) | #define V_newreno_beta VNET(newreno_beta) | ||||
#define V_newreno_beta_ecn VNET(newreno_beta_ecn) | #define V_newreno_beta_ecn VNET(newreno_beta_ecn) | ||||
struct cc_algo newreno_cc_algo = { | struct cc_algo newreno_cc_algo = { | ||||
.name = "newreno", | .name = "newreno", | ||||
.cb_init = newreno_cb_init, | .cb_destroy = newreno_cb_destroy, | ||||
.ack_received = newreno_ack_received, | .ack_received = newreno_ack_received, | ||||
.after_idle = newreno_after_idle, | .after_idle = newreno_after_idle, | ||||
.cong_signal = newreno_cong_signal, | .cong_signal = newreno_cong_signal, | ||||
.post_recovery = newreno_post_recovery, | .post_recovery = newreno_post_recovery, | ||||
.ctl_output = newreno_ctl_output, | .ctl_output = newreno_ctl_output, | ||||
}; | }; | ||||
struct newreno { | struct newreno { | ||||
uint32_t beta; | uint32_t beta; | ||||
uint32_t beta_ecn; | uint32_t beta_ecn; | ||||
}; | }; | ||||
int | static inline struct newreno * | ||||
newreno_cb_init(struct cc_var *ccv) | newreno_malloc(struct cc_var *ccv) | ||||
{ | { | ||||
struct newreno *nreno; | struct newreno *nreno; | ||||
nreno = malloc(sizeof(struct newreno), M_NEWRENO, M_NOWAIT|M_ZERO); | nreno = malloc(sizeof(struct newreno), M_NEWRENO, M_NOWAIT); | ||||
if (nreno != NULL) { | if (nreno != NULL) { | ||||
/* NB: nreno is not zeroed, so initialise all fields. */ | |||||
nreno->beta = V_newreno_beta; | nreno->beta = V_newreno_beta; | ||||
nreno->beta_ecn = V_newreno_beta_ecn; | nreno->beta_ecn = V_newreno_beta_ecn; | ||||
ccv->cc_data = nreno; | |||||
} | } | ||||
return (0); | return (nreno); | ||||
} | } | ||||
static void | static void | ||||
newreno_cb_destroy(struct cc_var *ccv) | |||||
{ | |||||
if (ccv->cc_data != NULL) | |||||
free(ccv->cc_data, M_NEWRENO); | |||||
} | |||||
static void | |||||
newreno_ack_received(struct cc_var *ccv, uint16_t type) | newreno_ack_received(struct cc_var *ccv, uint16_t type) | ||||
{ | { | ||||
if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && | if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && | ||||
(ccv->flags & CCF_CWND_LIMITED)) { | (ccv->flags & CCF_CWND_LIMITED)) { | ||||
u_int cw = CCV(ccv, snd_cwnd); | u_int cw = CCV(ccv, snd_cwnd); | ||||
u_int incr = CCV(ccv, t_maxseg); | u_int incr = CCV(ccv, t_maxseg); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Perform any necessary tasks before we enter congestion recovery. | * Perform any necessary tasks before we enter congestion recovery. | ||||
*/ | */ | ||||
static void | static void | ||||
newreno_cong_signal(struct cc_var *ccv, uint32_t type) | newreno_cong_signal(struct cc_var *ccv, uint32_t type) | ||||
{ | { | ||||
struct newreno *nreno; | struct newreno *nreno; | ||||
uint32_t cwin, factor; | uint32_t beta, beta_ecn, cwin, factor; | ||||
u_int mss; | u_int mss; | ||||
factor = V_newreno_beta; | cwin = CCV(ccv, snd_cwnd); | ||||
mss = CCV(ccv, t_maxseg); | |||||
nreno = ccv->cc_data; | nreno = ccv->cc_data; | ||||
if (nreno != NULL) { | beta = (nreno == NULL) ? V_newreno_beta : nreno->beta; | ||||
if (V_cc_do_abe) | beta_ecn = (nreno == NULL) ? V_newreno_beta_ecn : nreno->beta_ecn; | ||||
factor = (type == CC_ECN ? nreno->beta_ecn: nreno->beta); | if (V_cc_do_abe && type == CC_ECN) | ||||
factor = beta_ecn; | |||||
else | else | ||||
factor = nreno->beta; | factor = beta; | ||||
} | |||||
cwin = CCV(ccv, snd_cwnd); | |||||
mss = CCV(ccv, t_maxseg); | |||||
/* Catch algos which mistakenly leak private signal types. */ | /* Catch algos which mistakenly leak private signal types. */ | ||||
KASSERT((type & CC_SIGPRIVMASK) == 0, | KASSERT((type & CC_SIGPRIVMASK) == 0, | ||||
("%s: congestion signal type 0x%08x is private\n", __func__, type)); | ("%s: congestion signal type 0x%08x is private\n", __func__, type)); | ||||
cwin = max(((uint64_t)cwin * (uint64_t)factor) / (100ULL * (uint64_t)mss), | cwin = max(((uint64_t)cwin * (uint64_t)factor) / (100ULL * (uint64_t)mss), | ||||
2) * mss; | 2) * mss; | ||||
switch (type) { | switch (type) { | ||||
case CC_NDUPACK: | case CC_NDUPACK: | ||||
if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { | if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { | ||||
if (IN_CONGRECOVERY(CCV(ccv, t_flags) && | if (IN_CONGRECOVERY(CCV(ccv, t_flags) && | ||||
V_cc_do_abe && V_cc_abe_frlossreduce)) { | V_cc_do_abe && V_cc_abe_frlossreduce)) { | ||||
CCV(ccv, snd_ssthresh) = | CCV(ccv, snd_ssthresh) = | ||||
((uint64_t)CCV(ccv, snd_ssthresh) * | ((uint64_t)CCV(ccv, snd_ssthresh) * | ||||
(uint64_t)nreno->beta) / | (uint64_t)beta) / | ||||
(100ULL * (uint64_t)nreno->beta_ecn); | (100ULL * (uint64_t)beta_ecn); | ||||
} | } | ||||
if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) | if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) | ||||
CCV(ccv, snd_ssthresh) = cwin; | CCV(ccv, snd_ssthresh) = cwin; | ||||
ENTER_RECOVERY(CCV(ccv, t_flags)); | ENTER_RECOVERY(CCV(ccv, t_flags)); | ||||
} | } | ||||
break; | break; | ||||
case CC_ECN: | case CC_ECN: | ||||
if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { | if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { | ||||
CCV(ccv, snd_ssthresh) = cwin; | CCV(ccv, snd_ssthresh) = cwin; | ||||
CCV(ccv, snd_cwnd) = cwin; | CCV(ccv, snd_cwnd) = cwin; | ||||
ENTER_CONGRECOVERY(CCV(ccv, t_flags)); | ENTER_CONGRECOVERY(CCV(ccv, t_flags)); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Perform any necessary tasks before we exit congestion recovery. | * Perform any necessary tasks before we exit congestion recovery. | ||||
*/ | */ | ||||
static void | static void | ||||
newreno_post_recovery(struct cc_var *ccv) | newreno_post_recovery(struct cc_var *ccv) | ||||
{ | { | ||||
int pipe; | int pipe; | ||||
pipe = 0; | |||||
if (IN_FASTRECOVERY(CCV(ccv, t_flags))) { | if (IN_FASTRECOVERY(CCV(ccv, t_flags))) { | ||||
/* | /* | ||||
* Fast recovery will conclude after returning from this | * Fast recovery will conclude after returning from this | ||||
* function. Window inflation should have left us with | * function. Window inflation should have left us with | ||||
* approximately snd_ssthresh outstanding data. But in case we | * approximately snd_ssthresh outstanding data. But in case we | ||||
* would be inclined to send a burst, better to do it via the | * would be inclined to send a burst, better to do it via the | ||||
* slow start mechanism. | * slow start mechanism. | ||||
* | * | ||||
* XXXLAS: Find a way to do this without needing curack | * XXXLAS: Find a way to do this without needing curack | ||||
*/ | */ | ||||
if (V_tcp_do_rfc6675_pipe) | if (V_tcp_do_rfc6675_pipe) | ||||
pipe = tcp_compute_pipe(ccv->ccvc.tcp); | pipe = tcp_compute_pipe(ccv->ccvc.tcp); | ||||
else | else | ||||
pipe = CCV(ccv, snd_max) - ccv->curack; | pipe = CCV(ccv, snd_max) - ccv->curack; | ||||
if (pipe < CCV(ccv, snd_ssthresh)) | if (pipe < CCV(ccv, snd_ssthresh)) | ||||
CCV(ccv, snd_cwnd) = pipe + CCV(ccv, t_maxseg); | CCV(ccv, snd_cwnd) = pipe + CCV(ccv, t_maxseg); | ||||
else | else | ||||
CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); | CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); | ||||
} | } | ||||
} | } | ||||
int | static int | ||||
newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf) | newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf) | ||||
{ | { | ||||
struct newreno *nreno; | struct newreno *nreno; | ||||
struct cc_newreno_opts *opt; | struct cc_newreno_opts *opt; | ||||
if (sopt->sopt_valsize != sizeof(struct cc_newreno_opts)) | if (sopt->sopt_valsize != sizeof(struct cc_newreno_opts)) | ||||
return (EMSGSIZE); | return (EMSGSIZE); | ||||
nreno = ccv->cc_data; | nreno = ccv->cc_data; | ||||
opt = buf; | opt = buf; | ||||
switch (sopt->sopt_dir) { | switch (sopt->sopt_dir) { | ||||
case SOPT_SET: | case SOPT_SET: | ||||
/* We cannot set without cc_data memory. */ | |||||
if (nreno == NULL) { | |||||
nreno = newreno_malloc(ccv); | |||||
if (nreno == NULL) | |||||
return (ENOMEM); | |||||
} | |||||
switch (opt->name) { | switch (opt->name) { | ||||
case CC_NEWRENO_BETA: | case CC_NEWRENO_BETA: | ||||
nreno->beta = opt->val; | nreno->beta = opt->val; | ||||
break; | break; | ||||
case CC_NEWRENO_BETA_ECN: | case CC_NEWRENO_BETA_ECN: | ||||
if (!V_cc_do_abe) | if (!V_cc_do_abe) | ||||
return (EACCES); | return (EACCES); | ||||
nreno->beta_ecn = opt->val; | nreno->beta_ecn = opt->val; | ||||
break; | break; | ||||
default: | default: | ||||
return (ENOPROTOOPT); | return (ENOPROTOOPT); | ||||
} | } | ||||
break; | |||||
case SOPT_GET: | case SOPT_GET: | ||||
switch (opt->name) { | switch (opt->name) { | ||||
case CC_NEWRENO_BETA: | case CC_NEWRENO_BETA: | ||||
opt->val = nreno->beta; | opt->val = (nreno == NULL) ? | ||||
V_newreno_beta : nreno->beta; | |||||
break; | break; | ||||
case CC_NEWRENO_BETA_ECN: | case CC_NEWRENO_BETA_ECN: | ||||
opt->val = nreno->beta_ecn; | opt->val = (nreno == NULL) ? | ||||
V_newreno_beta_ecn : nreno->beta_ecn; | |||||
break; | break; | ||||
default: | default: | ||||
return (ENOPROTOOPT); | return (ENOPROTOOPT); | ||||
} | } | ||||
break; | |||||
default: | default: | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
newreno_beta_handler(SYSCTL_HANDLER_ARGS) | newreno_beta_handler(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
if (req->newptr != NULL ) { | if (req->newptr != NULL ) { | ||||
if (arg1 == &VNET_NAME(newreno_beta_ecn) && !V_cc_do_abe) | if (arg1 == &VNET_NAME(newreno_beta_ecn) && !V_cc_do_abe) | ||||
return (EACCES); | return (EACCES); | ||||
if (CAST_PTR_INT(req->newptr) <= 0 || CAST_PTR_INT(req->newptr) > 100) | if (CAST_PTR_INT(req->newptr) <= 0 || CAST_PTR_INT(req->newptr) > 100) | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
return (sysctl_handle_int(oidp, arg1, arg2, req)); | return (sysctl_handle_int(oidp, arg1, arg2, req)); | ||||
Show All 17 Lines |