Index: sys/netinet/cc/cc_cubic.h =================================================================== --- sys/netinet/cc/cc_cubic.h +++ sys/netinet/cc/cc_cubic.h @@ -42,6 +42,8 @@ /* Number of bits of precision for fixed point math calcs. */ #define CUBIC_SHIFT 8 +#define CUBIC_SCALE (1 << CUBIC_SHIFT) + #define CUBIC_SHIFT_4 32 /* 0.5 << CUBIC_SHIFT. */ Index: sys/netinet/cc/cc_cubic.c =================================================================== --- sys/netinet/cc/cc_cubic.c +++ sys/netinet/cc/cc_cubic.c @@ -96,11 +96,20 @@ int epoch_ack_count; /* Time of last congestion event in ticks. */ 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", "Per connection data required for the CUBIC congestion control algorithm"); +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"); + struct cc_algo cubic_cc_algo = { .name = "cubic", .ack_received = cubic_ack_received, @@ -247,7 +256,6 @@ if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { cubic_ssthresh_update(ccv); cubic_data->num_cong_events++; - cubic_data->prev_max_cwnd = cubic_data->max_cwnd; cubic_data->max_cwnd = win; CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); } @@ -259,9 +267,12 @@ if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { cubic_ssthresh_update(ccv); cubic_data->num_cong_events++; - cubic_data->prev_max_cwnd = cubic_data->max_cwnd; cubic_data->max_cwnd = win; 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); ENTER_CONGRECOVERY(CCV(ccv, t_flags)); } @@ -275,13 +286,19 @@ * 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->t_last_cong = ticks; - cubic_ssthresh_update(ccv); - cubic_data->max_cwnd = win; - CCV(ccv, snd_cwnd) = mss; - } + if (CCV(ccv, t_rxtshift) == 1) + cubic_data->t_last_cong_prev = cubic_data->t_last_cong; + cubic_ssthresh_update(ccv); + cubic_data->num_cong_events++; + cubic_data->max_cwnd = win; + cubic_data->t_last_cong = ticks; + CCV(ccv, snd_cwnd) = mss; + 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; } } @@ -411,18 +428,52 @@ cubic_ssthresh_update(struct cc_var *ccv) { struct cubic *cubic_data; + u_long snd_ssthresh, snd_cwnd; cubic_data = ccv->cc_data; /* - * On the first congestion event, set ssthresh to cwnd * 0.5, on - * subsequent congestion events, set it to cwnd * beta. + * 3.5. Multiplicative decrease + * + * 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) - CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd) >> 1; + snd_ssthresh = (CCV(ccv, snd_cwnd) * CUBIC_BETA) >> CUBIC_SHIFT; + 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 < cubic_data->prev_max_cwnd && fast_convergence) + cubic_data->prev_max_cwnd = (snd_cwnd * + (CUBIC_SCALE + CUBIC_BETA)) / (2 * CUBIC_SCALE); else - CCV(ccv, snd_ssthresh) = ((u_long)CCV(ccv, snd_cwnd) * - CUBIC_BETA) >> CUBIC_SHIFT; + cubic_data->prev_max_cwnd = snd_cwnd; }