Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/cc/cc_cubic.c
Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | struct cubic { | ||||
/* Minimum observed rtt in ticks. */ | /* Minimum observed rtt in ticks. */ | ||||
int min_rtt_ticks; | int min_rtt_ticks; | ||||
/* Mean observed rtt between congestion epochs. */ | /* Mean observed rtt between congestion epochs. */ | ||||
int mean_rtt_ticks; | int mean_rtt_ticks; | ||||
/* ACKs since last congestion event. */ | /* ACKs since last congestion event. */ | ||||
int epoch_ack_count; | int epoch_ack_count; | ||||
/* Time of last congestion event in ticks. */ | /* Time of last congestion event in ticks. */ | ||||
int t_last_cong; | int t_last_cong; | ||||
/* Time of last congestion event in ticks for previous event. */ | |||||
int t_last_cong_prev; | |||||
}; | }; | ||||
static MALLOC_DEFINE(M_CUBIC, "cubic data", | static MALLOC_DEFINE(M_CUBIC, "cubic data", | ||||
"Per connection data required for the CUBIC congestion control algorithm"); | "Per connection data required for the CUBIC congestion control algorithm"); | ||||
/* Declare sysctl tree and populate it. */ | |||||
SYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, cubic, CTLFLAG_RW, NULL, | |||||
"cubic congestion control related settings"); | |||||
static int fast_convergence = 1; | |||||
SYSCTL_INT(_net_inet_tcp_cc_cubic, OID_AUTO, fast_convergence, CTLFLAG_RWTUN, | |||||
&fast_convergence, 0, "Enable fast convergence as specified in Section 3.6."); | |||||
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, | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | cubic_cong_signal(struct cc_var *ccv, uint32_t type) | ||||
cubic_data = ccv->cc_data; | cubic_data = ccv->cc_data; | ||||
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))) { | ||||
cubic_ssthresh_update(ccv); | cubic_ssthresh_update(ccv); | ||||
cubic_data->num_cong_events++; | cubic_data->num_cong_events++; | ||||
cubic_data->prev_max_cwnd = cubic_data->max_cwnd; | |||||
cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | ||||
} | } | ||||
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))) { | ||||
cubic_ssthresh_update(ccv); | cubic_ssthresh_update(ccv); | ||||
cubic_data->num_cong_events++; | cubic_data->num_cong_events++; | ||||
cubic_data->prev_max_cwnd = cubic_data->max_cwnd; | |||||
cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | ||||
cubic_data->t_last_cong = ticks; | cubic_data->t_last_cong = ticks; | ||||
/* | |||||
* cubic_ssthresh_update(ccv) sets ssthresh to cwnd scaled by beta | |||||
* so this assignment is equivalent | |||||
*/ | |||||
CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); | CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); | ||||
ENTER_CONGRECOVERY(CCV(ccv, t_flags)); | ENTER_CONGRECOVERY(CCV(ccv, t_flags)); | ||||
} | } | ||||
break; | break; | ||||
case CC_RTO: | case CC_RTO: | ||||
/* | if (CCV(ccv, t_rxtshift) == 1) | ||||
* Grab the current time and record it so we know when the | cubic_data->t_last_cong_prev = cubic_data->t_last_cong; | ||||
* most recent congestion event was. Only record it when the | cubic_ssthresh_update(ccv); | ||||
* timeout has fired more than once, as there is a reasonable | |||||
* chance the first one is a false alarm and may not indicate | |||||
* congestion. | |||||
*/ | |||||
if (CCV(ccv, t_rxtshift) >= 2) | |||||
cubic_data->num_cong_events++; | cubic_data->num_cong_events++; | ||||
cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | |||||
cubic_data->t_last_cong = ticks; | cubic_data->t_last_cong = ticks; | ||||
CCV(ccv, snd_cwnd) = CCV(ccv, t_maxseg); | |||||
break; | break; | ||||
case CC_RTO_ERR: | |||||
cubic_data->num_cong_events--; | |||||
cubic_data->t_last_cong = cubic_data->t_last_cong_prev; | |||||
cubic_data->max_cwnd = max(cubic_data->max_cwnd, cubic_data->prev_max_cwnd); | |||||
break; | |||||
} | } | ||||
} | } | ||||
static void | static void | ||||
cubic_conn_init(struct cc_var *ccv) | cubic_conn_init(struct cc_var *ccv) | ||||
{ | { | ||||
struct cubic *cubic_data; | struct cubic *cubic_data; | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Update the ssthresh in the event of congestion. | * Update the ssthresh in the event of congestion. | ||||
*/ | */ | ||||
static void | static void | ||||
cubic_ssthresh_update(struct cc_var *ccv) | cubic_ssthresh_update(struct cc_var *ccv) | ||||
{ | { | ||||
struct cubic *cubic_data; | struct cubic *cd; | ||||
u_long snd_ssthresh, snd_cwnd; | |||||
cubic_data = ccv->cc_data; | cd = ccv->cc_data; | ||||
/* | /* 3.5. Multiplicative decrease | ||||
* On the first congestion event, set ssthresh to cwnd * 0.5, on | * | ||||
* subsequent congestion events, set it to cwnd * beta. | * When a packet loss occurs, CUBIC reduces its window size by a factor | ||||
* of beta. Parameter beta_cubic SHOULD be set to 0.7. | |||||
* | |||||
* W_max = cwnd; // save window size before reduction | |||||
* cwnd = cwnd * beta_cubic; // window reduction | |||||
*/ | */ | ||||
if (cubic_data->num_cong_events == 0) | snd_ssthresh = (CCV(ccv, snd_cwnd) * CUBIC_BETA) >> CUBIC_SHIFT; | ||||
CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd) >> 1; | CCV(ccv, snd_ssthresh) = max(snd_ssthresh, 2*CCV(ccv, t_maxseg)); | ||||
/* 3.6. Fast convergence | |||||
* | |||||
* To improve the convergence speed of CUBIC, we add a heuristic in the | |||||
* protocol. When a new flow joins the network, existing flows in the | |||||
* network need to give up their bandwidth shares to allow the flow some | |||||
* room for growth if the existing flows have been using all the | |||||
* bandwidth of the network. To increase this release of bandwidth by | |||||
* existing flows, the following mechanism called fast convergence | |||||
* SHOULD be implemented. | |||||
* | |||||
* With fast convergence, when a loss event occurs, before a window | |||||
* reduction of congestion window, a flow remembers the last value of | |||||
* W_max before it updates W_max for the current loss event. Let us | |||||
* call the last value of W_max to be W_last_max. | |||||
* | |||||
* if (W_max < W_last_max){ // check downward trend | |||||
* W_last_max = W_max; // remember the last W_max | |||||
* W_max = W_max*(1+beta_cubic)/2; // further reduce W_max | |||||
* } else { // check upward trend | |||||
* W_last_max = W_max // remember the last W_max | |||||
* } | |||||
*/ | |||||
snd_cwnd = CCV(ccv, snd_cwnd); | |||||
if (snd_cwnd < cd->prev_max_cwnd && fast_convergence) | |||||
cd->prev_max_cwnd = (snd_cwnd * (CUBIC_SCALE + CUBIC_BETA)) | |||||
/ (2 * CUBIC_SCALE); | |||||
else | else | ||||
CCV(ccv, snd_ssthresh) = (CCV(ccv, snd_cwnd) * CUBIC_BETA) | cd->prev_max_cwnd = snd_cwnd; | ||||
>> CUBIC_SHIFT; | |||||
} | } | ||||
DECLARE_CC_MODULE(cubic, &cubic_cc_algo); | DECLARE_CC_MODULE(cubic, &cubic_cc_algo); |