diff --git a/sys/netinet/cc/cc_cubic.h b/sys/netinet/cc/cc_cubic.h --- a/sys/netinet/cc/cc_cubic.h +++ b/sys/netinet/cc/cc_cubic.h @@ -52,6 +52,12 @@ /* ~0.7 << CUBIC_SHIFT. */ #define CUBIC_BETA 179 +/* ~0.53 << CUBIC_SHIFT: 3 * (1-beta_cubic)/(1+beta_cubic). */ +#define CUBIC_ALPHA 135 + +/* 1 << CUBIC_SHIFT. */ +#define CUBIC_ALPHA_ONE 256 + /* ~0.3 << CUBIC_SHIFT. */ #define ONE_SUB_CUBIC_BETA 77 @@ -142,31 +148,36 @@ /* * Implementation based on the formulae found in the CUBIC Internet Draft - * "draft-ietf-tcpm-cubic-04". + * "draft-ietf-tcpm-rfc8312bis-15". * */ static __inline float -theoretical_cubic_k(double wmax_pkts) +theoretical_cubic_k(double wmax_pkts, double cwnd_epoch_pkts) { double C; C = 0.4; - return (pow((wmax_pkts * 0.3) / C, (1.0 / 3.0)) * pow(2, CUBIC_SHIFT)); + if (wmax_pkts <= cwnd_epoch_pkts) + return 0.0; + + return (pow((wmax_pkts - cwnd_epoch_pkts) / C, (1.0 / 3.0)) * pow(2, CUBIC_SHIFT)); } static __inline unsigned long -theoretical_cubic_cwnd(int ticks_since_epoch, unsigned long wmax, uint32_t smss) +theoretical_cubic_cwnd(int ticks_since_epoch, unsigned long wmax, + unsigned long cwnd_epoch, uint32_t smss) { - double C, wmax_pkts; + double C, wmax_pkts, cwnd_epoch_pkts; C = 0.4; wmax_pkts = wmax / (double)smss; + cwnd_epoch_pkts = cwnd_epoch / (double)smss; return (smss * (wmax_pkts + (C * pow(ticks_since_epoch / (double)hz - - theoretical_cubic_k(wmax_pkts) / pow(2, CUBIC_SHIFT), 3.0)))); + theoretical_cubic_k(wmax_pkts, cwnd_epoch_pkts) / pow(2, CUBIC_SHIFT), 3.0)))); } static __inline unsigned long @@ -178,23 +189,30 @@ } static __inline unsigned long -theoretical_tf_cwnd(int ticks_since_epoch, int rtt_ticks, unsigned long wmax, - uint32_t smss) +theoretical_tf_cwnd(unsigned long west, unsigned long bytes_acked, unsigned long cwnd, + unsigned long cwnd_prior, unsigned long smss) { - return ((wmax * 0.7) + ((3 * 0.3) / (2 - 0.3) * - (ticks_since_epoch / (float)rtt_ticks) * smss)); + float cubic_alpha; + + if (west >= cwnd_prior) + cubic_alpha = 1.0; + else + cubic_alpha = (3.0 * (1.0 - 0.7)) / (1.0 + 0.7); + + return (west + (cubic_alpha * ((bytes_acked * smss) / (float)cwnd))); } #endif /* !_KERNEL */ /* * Compute the CUBIC K value used in the cwnd calculation, using an - * implementation of eqn 2 in the I-D. The method used - * here is adapted from Apple Computer Technical Report #KT-32. + * implementation mentioned in Fig. 2 of draft-ietf-tcpm-rfc8312bis-15. + * The method used here is adapted from Apple Computer Technical + * Report #KT-32. */ static __inline int64_t -cubic_k(unsigned long wmax_pkts) +cubic_k(unsigned long wmax_pkts, unsigned long cwnd_epoch_pkts) { int64_t s, K; uint16_t p; @@ -202,8 +220,13 @@ K = s = 0; p = 0; - /* (wmax * beta)/C with CUBIC_SHIFT worth of precision. */ - s = ((wmax_pkts * ONE_SUB_CUBIC_BETA) << CUBIC_SHIFT) / CUBIC_C_FACTOR; + /* Handle the corner case where W_max <= cwnd_epoch */ + if (wmax_pkts <= cwnd_epoch_pkts) { + return 0; + } + + /* (wmax - cwnd_epoch) / C with CUBIC_SHIFT worth of precision. */ + s = ((wmax_pkts - cwnd_epoch_pkts) << (2 * CUBIC_SHIFT)) / CUBIC_C_FACTOR; /* Rebase s to be between 1 and 1/8 with a shift of CUBIC_SHIFT. */ while (s >= 256) { diff --git a/sys/netinet/cc/cc_cubic.c b/sys/netinet/cc/cc_cubic.c --- a/sys/netinet/cc/cc_cubic.c +++ b/sys/netinet/cc/cc_cubic.c @@ -278,6 +278,8 @@ CUBICFLAG_IN_APPLIMIT); cubic_data->t_epoch = ticks; cubic_data->K = cubic_k(cubic_data->W_max / + CCV(ccv, t_maxseg), + cubic_data->cwnd_epoch / CCV(ccv, t_maxseg)); } usecs_since_epoch = (ticks - cubic_data->t_epoch) * tick; @@ -333,6 +335,7 @@ cubic_data->W_max < CCV(ccv, snd_cwnd)) { cubic_data->W_max = CCV(ccv, snd_cwnd); cubic_data->K = cubic_k(cubic_data->W_max / + CCV(ccv, t_maxseg), cubic_data->cwnd_epoch / CCV(ccv, t_maxseg)); } } @@ -354,8 +357,9 @@ cubic_data = ccv->cc_data; - cubic_data->W_max = ulmax(cubic_data->W_max, CCV(ccv, snd_cwnd)); - cubic_data->K = cubic_k(cubic_data->W_max / CCV(ccv, t_maxseg)); + cubic_data->cwnd_prior = ulmax(cubic_data->cwnd_prior, CCV(ccv, snd_cwnd)); + cubic_data->W_max = cubic_data->cwnd_prior; + cubic_data->t_epoch = 0; /* This will recalculate K */ if ((cubic_data->flags & CUBICFLAG_HYSTART_ENABLED) == 0) { /* * Re-enable hystart if we have been idle. @@ -437,9 +441,8 @@ if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { cubic_ssthresh_update(ccv, mss); - cubic_data->flags |= CUBICFLAG_CONG_EVENT; - cubic_data->t_epoch = ticks; - cubic_data->K = cubic_k(cubic_data->W_max / mss); + cubic_data->num_cong_events++; + cubic_data->t_epoch = 0; /* This will recalculate K */ } ENTER_RECOVERY(CCV(ccv, t_flags)); } @@ -454,9 +457,8 @@ } if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { cubic_ssthresh_update(ccv, mss); - cubic_data->flags |= CUBICFLAG_CONG_EVENT; - cubic_data->t_epoch = ticks; - cubic_data->K = cubic_k(cubic_data->W_max / mss); + cubic_data->num_cong_events++; + cubic_data->t_epoch = 0; /* This will recalculate K */ CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); ENTER_CONGRECOVERY(CCV(ccv, t_flags)); }