Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/cc/cc_cubic.c
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/socketvar.h> | #include <sys/socketvar.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <net/route.h> | |||||
#include <net/route/nhop.h> | |||||
#include <netinet/in_pcb.h> | |||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#include <netinet/tcp_seq.h> | #include <netinet/tcp_seq.h> | ||||
#include <netinet/tcp_timer.h> | #include <netinet/tcp_timer.h> | ||||
#include <netinet/tcp_var.h> | #include <netinet/tcp_var.h> | ||||
#include <netinet/cc/cc.h> | #include <netinet/cc/cc.h> | ||||
#include <netinet/cc/cc_cubic.h> | #include <netinet/cc/cc_cubic.h> | ||||
#include <netinet/cc/cc_module.h> | #include <netinet/cc/cc_module.h> | ||||
static void cubic_ack_received(struct cc_var *ccv, uint16_t type); | static void cubic_ack_received(struct cc_var *ccv, uint16_t type); | ||||
static void cubic_cb_destroy(struct cc_var *ccv); | static void cubic_cb_destroy(struct cc_var *ccv); | ||||
static int cubic_cb_init(struct cc_var *ccv); | static int cubic_cb_init(struct cc_var *ccv, void *ptr); | ||||
static void cubic_cong_signal(struct cc_var *ccv, uint32_t type); | static void cubic_cong_signal(struct cc_var *ccv, uint32_t type); | ||||
static void cubic_conn_init(struct cc_var *ccv); | static void cubic_conn_init(struct cc_var *ccv); | ||||
static int cubic_mod_init(void); | static int cubic_mod_init(void); | ||||
static void cubic_post_recovery(struct cc_var *ccv); | static void cubic_post_recovery(struct cc_var *ccv); | ||||
static void cubic_record_rtt(struct cc_var *ccv); | static void cubic_record_rtt(struct cc_var *ccv); | ||||
static void cubic_ssthresh_update(struct cc_var *ccv, uint32_t maxseg); | static void cubic_ssthresh_update(struct cc_var *ccv, uint32_t maxseg); | ||||
static void cubic_after_idle(struct cc_var *ccv); | static void cubic_after_idle(struct cc_var *ccv); | ||||
static size_t cubic_data_sz(void); | |||||
struct cubic { | struct cubic { | ||||
/* Cubic K in fixed point form with CUBIC_SHIFT worth of precision. */ | /* Cubic K in fixed point form with CUBIC_SHIFT worth of precision. */ | ||||
int64_t K; | int64_t K; | ||||
/* Sum of RTT samples across an epoch in ticks. */ | /* Sum of RTT samples across an epoch in ticks. */ | ||||
int64_t sum_rtt_ticks; | int64_t sum_rtt_ticks; | ||||
/* cwnd at the most recent congestion event. */ | /* cwnd at the most recent congestion event. */ | ||||
unsigned long max_cwnd; | unsigned long max_cwnd; | ||||
Show All 18 Lines | #define CUBICFLAG_RTO_EVENT 0x00000008 /* RTO experienced */ | ||||
*/ | */ | ||||
int t_last_cong; | int t_last_cong; | ||||
/* Timestamp (in ticks) of a previous congestion event. Used for | /* Timestamp (in ticks) of a previous congestion event. Used for | ||||
* CC_RTO_ERR. | * CC_RTO_ERR. | ||||
*/ | */ | ||||
int t_last_cong_prev; | int t_last_cong_prev; | ||||
}; | }; | ||||
static MALLOC_DEFINE(M_CUBIC, "cubic data", | |||||
"Per connection data required for the CUBIC congestion control algorithm"); | |||||
struct cc_algo cubic_cc_algo = { | struct cc_algo cubic_cc_algo = { | ||||
.name = "cubic", | .name = "cubic", | ||||
.ack_received = cubic_ack_received, | .ack_received = cubic_ack_received, | ||||
.cb_destroy = cubic_cb_destroy, | .cb_destroy = cubic_cb_destroy, | ||||
.cb_init = cubic_cb_init, | .cb_init = cubic_cb_init, | ||||
.cong_signal = cubic_cong_signal, | .cong_signal = cubic_cong_signal, | ||||
.conn_init = cubic_conn_init, | .conn_init = cubic_conn_init, | ||||
.mod_init = cubic_mod_init, | .mod_init = cubic_mod_init, | ||||
.post_recovery = cubic_post_recovery, | .post_recovery = cubic_post_recovery, | ||||
.after_idle = cubic_after_idle, | .after_idle = cubic_after_idle, | ||||
.cc_data_sz = cubic_data_sz | |||||
}; | }; | ||||
static void | static void | ||||
cubic_ack_received(struct cc_var *ccv, uint16_t type) | cubic_ack_received(struct cc_var *ccv, uint16_t type) | ||||
{ | { | ||||
struct cubic *cubic_data; | struct cubic *cubic_data; | ||||
unsigned long w_tf, w_cubic_next; | unsigned long w_tf, w_cubic_next; | ||||
int ticks_since_cong; | int ticks_since_cong; | ||||
cubic_data = ccv->cc_data; | cubic_data = ccv->cc_data; | ||||
cubic_record_rtt(ccv); | cubic_record_rtt(ccv); | ||||
/* | /* | ||||
* For a regular ACK and we're not in cong/fast recovery and | * For a regular ACK and we're not in cong/fast recovery and | ||||
* we're cwnd limited, always recalculate cwnd. | * we're cwnd limited, always recalculate cwnd. | ||||
*/ | */ | ||||
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)) { | ||||
/* Use the logic in NewReno ack_received() for slow start. */ | /* Use the logic in NewReno ack_received() for slow start. */ | ||||
if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh) || | if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh) || | ||||
cubic_data->min_rtt_ticks == TCPTV_SRTTBASE) { | cubic_data->min_rtt_ticks == TCPTV_SRTTBASE) { | ||||
cubic_data->flags |= CUBICFLAG_IN_SLOWSTART; | cubic_data->flags |= CUBICFLAG_IN_SLOWSTART; | ||||
newreno_cc_algo.ack_received(ccv, type); | newreno_cc_ack_received(ccv, type); | ||||
} else { | } else { | ||||
if ((cubic_data->flags & CUBICFLAG_RTO_EVENT) && | if ((cubic_data->flags & CUBICFLAG_RTO_EVENT) && | ||||
(cubic_data->flags & CUBICFLAG_IN_SLOWSTART)) { | (cubic_data->flags & CUBICFLAG_IN_SLOWSTART)) { | ||||
/* RFC8312 Section 4.7 */ | /* RFC8312 Section 4.7 */ | ||||
cubic_data->flags &= ~(CUBICFLAG_RTO_EVENT | | cubic_data->flags &= ~(CUBICFLAG_RTO_EVENT | | ||||
CUBICFLAG_IN_SLOWSTART); | CUBICFLAG_IN_SLOWSTART); | ||||
cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | ||||
cubic_data->K = 0; | cubic_data->K = 0; | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct cubic *cubic_data; | struct cubic *cubic_data; | ||||
cubic_data = ccv->cc_data; | cubic_data = ccv->cc_data; | ||||
cubic_data->max_cwnd = ulmax(cubic_data->max_cwnd, CCV(ccv, snd_cwnd)); | cubic_data->max_cwnd = ulmax(cubic_data->max_cwnd, CCV(ccv, snd_cwnd)); | ||||
cubic_data->K = cubic_k(cubic_data->max_cwnd / CCV(ccv, t_maxseg)); | cubic_data->K = cubic_k(cubic_data->max_cwnd / CCV(ccv, t_maxseg)); | ||||
newreno_cc_algo.after_idle(ccv); | newreno_cc_after_idle(ccv); | ||||
cubic_data->t_last_cong = ticks; | cubic_data->t_last_cong = ticks; | ||||
} | } | ||||
static void | static void | ||||
cubic_cb_destroy(struct cc_var *ccv) | cubic_cb_destroy(struct cc_var *ccv) | ||||
{ | { | ||||
free(ccv->cc_data, M_CUBIC); | free(ccv->cc_data, M_CC_MEM); | ||||
} | } | ||||
static size_t | |||||
cubic_data_sz(void) | |||||
{ | |||||
return (sizeof(struct cubic)); | |||||
} | |||||
static int | static int | ||||
cubic_cb_init(struct cc_var *ccv) | cubic_cb_init(struct cc_var *ccv, void *ptr) | ||||
{ | { | ||||
struct cubic *cubic_data; | struct cubic *cubic_data; | ||||
cubic_data = malloc(sizeof(struct cubic), M_CUBIC, M_NOWAIT|M_ZERO); | INP_WLOCK_ASSERT(ccv->ccvc.tcp->t_inpcb); | ||||
if (ptr == NULL) { | |||||
cubic_data = malloc(sizeof(struct cubic), M_CC_MEM, M_NOWAIT|M_ZERO); | |||||
if (cubic_data == NULL) | if (cubic_data == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} else | |||||
cubic_data = ptr; | |||||
/* Init some key variables with sensible defaults. */ | /* Init some key variables with sensible defaults. */ | ||||
cubic_data->t_last_cong = ticks; | cubic_data->t_last_cong = ticks; | ||||
cubic_data->min_rtt_ticks = TCPTV_SRTTBASE; | cubic_data->min_rtt_ticks = TCPTV_SRTTBASE; | ||||
cubic_data->mean_rtt_ticks = 1; | cubic_data->mean_rtt_ticks = 1; | ||||
ccv->cc_data = cubic_data; | ccv->cc_data = cubic_data; | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | cubic_ssthresh_update(struct cc_var *ccv, uint32_t maxseg) | ||||
} else { | } else { | ||||
ssthresh = ((uint64_t)cwnd * | ssthresh = ((uint64_t)cwnd * | ||||
CUBIC_BETA) >> CUBIC_SHIFT; | CUBIC_BETA) >> CUBIC_SHIFT; | ||||
} | } | ||||
CCV(ccv, snd_ssthresh) = max(ssthresh, 2 * maxseg); | CCV(ccv, snd_ssthresh) = max(ssthresh, 2 * maxseg); | ||||
} | } | ||||
DECLARE_CC_MODULE(cubic, &cubic_cc_algo); | DECLARE_CC_MODULE(cubic, &cubic_cc_algo); | ||||
MODULE_VERSION(cubic, 1); | MODULE_VERSION(cubic, 2); |