Page MenuHomeFreeBSD

D41715.id131749.diff
No OneTemporary

D41715.id131749.diff

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
@@ -141,32 +147,36 @@
extern int hz;
/*
- * Implementation based on the formulae found in the CUBIC Internet Draft
- * "draft-ietf-tcpm-cubic-04".
+ * Implementation based on the formulae found in the CUBIC RFC9438.
*
*/
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 +188,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 W_est, 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 (W_est >= cwnd_prior)
+ cubic_alpha = 1.0;
+ else
+ cubic_alpha = (3.0 * (1.0 - 0.7)) / (1.0 + 0.7);
+
+ return (W_est + (cubic_alpha * (bytes_acked / (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 RFC9438.
+ * 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 +219,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) {
@@ -224,8 +246,8 @@
}
/*
- * Compute the new cwnd value using an implementation of eqn 1 from the I-D.
- * Thanks to Kip Macy for help debugging this function.
+ * Compute the new cwnd value using an implementation mentioned in Fig. 1
+ * of RFC9438. Thanks to Kip Macy for help debugging this function.
*
* XXXLAS: Characterise bounds for overflow.
*/
@@ -271,7 +293,7 @@
* rather tricky to understand and it turns out this function is not required.
* It is left here for reference.
*
- * XXX: Not used
+ * XXX: Not used in the RFC9438 specification.
*/
static __inline unsigned long
reno_cwnd(int usecs_since_epoch, int rtt_usecs, unsigned long wmax,
@@ -288,22 +310,22 @@
}
/*
- * Compute an approximation of the "TCP friendly" cwnd some number of usecs
- * after a congestion event that is designed to yield the same average cwnd as
- * NewReno while using CUBIC's beta of 0.7. RTT should be the average RTT
- * estimate for the path measured over the previous congestion epoch and wmax is
- * the value of cwnd at the last congestion event.
+ * Compute the "Reno-friendly" cwnd estimate as mentioned in Fig. 4 of
+ * RFC9438. This function provides a new updated estimate given the old
+ * estimate, the number of bytes acked by the current ACK packet and the
+ * current cwnd size. Depending on whether W_est has exceeded cwnd_prior,
+ * the formula will toggle the value of cubic_alpha.
*/
static __inline unsigned long
-tf_cwnd(int usecs_since_epoch, int rtt_usecs, unsigned long wmax,
- uint32_t smss)
+tf_cwnd(unsigned long W_est, unsigned long bytes_acked, unsigned long cwnd,
+ unsigned long cwnd_prior, unsigned long smss)
{
+ int cubic_alpha;
+
+ /* cubic_alpha is in fixed point form with CUBIC_SHIFT worth of precision. */
+ cubic_alpha = (W_est >= cwnd_prior) ? CUBIC_ALPHA_ONE : CUBIC_ALPHA;
- /* Equation 4 of I-D. */
- return (((wmax * CUBIC_BETA) +
- (((THREE_X_PT3 * (unsigned long)usecs_since_epoch *
- (unsigned long)smss) << CUBIC_SHIFT) / (TWO_SUB_PT3 * rtt_usecs)))
- >> CUBIC_SHIFT);
+ return ((((cubic_alpha * bytes_acked) / cwnd) >> CUBIC_SHIFT) + W_est);
}
#endif /* _NETINET_CC_CUBIC_H_ */
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
@@ -38,7 +38,7 @@
/*
* An implementation of the CUBIC congestion control algorithm for FreeBSD,
- * based on the Internet Draft "draft-rhee-tcpm-cubic-02" by Rhee, Xu and Ha.
+ * based on the Internet RFC9438 by Xu, Ha, Rhee, Goel, and Eggert.
* Originally released as part of the NewTCP research project at Swinburne
* University of Technology's Centre for Advanced Internet Architectures,
* Melbourne, Australia, which was made possible in part by a grant from the
@@ -81,12 +81,13 @@
static int cubic_mod_init(void);
static void cubic_post_recovery(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 unsigned long cubic_get_ssthresh(struct cc_var *ccv, uint32_t maxseg);
static void cubic_after_idle(struct cc_var *ccv);
static size_t cubic_data_sz(void);
static void cubic_newround(struct cc_var *ccv, uint32_t round_cnt);
static void cubic_rttsample(struct cc_var *ccv, uint32_t usec_rtt,
uint32_t rxtcnt, uint32_t fas);
+static unsigned long cubic_compute_pipe(struct cc_var *ccv);
struct cc_algo cubic_cc_algo = {
.name = "cubic",
@@ -236,7 +237,7 @@
cubic_ack_received(struct cc_var *ccv, uint16_t type)
{
struct cubic *cubic_data;
- unsigned long W_est, W_cubic;
+ unsigned long W_est, W_cubic, target, incr;
int usecs_since_epoch;
cubic_data = ccv->cc_data;
@@ -251,6 +252,7 @@
/* Use the logic in NewReno ack_received() for slow start. */
if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh) ||
cubic_data->min_rtt_usecs == TCPTV_SRTTBASE) {
+ cubic_data->t_epoch = 0;
cubic_does_slow_start(ccv, cubic_data);
} else {
if (cubic_data->flags & CUBICFLAG_HYSTART_IN_CSS) {
@@ -264,80 +266,96 @@
cubic_data->flags &= ~CUBICFLAG_HYSTART_ENABLED;
cubic_log_hystart_event(ccv, cubic_data, 11, CCV(ccv, snd_ssthresh));
}
- if ((cubic_data->flags & CUBICFLAG_RTO_EVENT) &&
- (cubic_data->flags & CUBICFLAG_IN_SLOWSTART)) {
- /* RFC8312 Section 4.7 */
- cubic_data->flags &= ~(CUBICFLAG_RTO_EVENT |
- CUBICFLAG_IN_SLOWSTART);
- cubic_data->W_max = CCV(ccv, snd_cwnd);
- cubic_data->K = 0;
- } else if (cubic_data->flags & (CUBICFLAG_IN_SLOWSTART |
- CUBICFLAG_IN_APPLIMIT)) {
- cubic_data->flags &= ~(CUBICFLAG_IN_SLOWSTART |
- CUBICFLAG_IN_APPLIMIT);
+
+ /*
+ * The epoch variables are updated in the following
+ * three cases:
+ *
+ * 1) If we just exited the slow start
+ *
+ * 2) Section 5.8:
+ * If we were application-limited for a while before
+ *
+ * 3) If there was a 3-dupack / ECN congestion event
+ *
+ * In all of the above cases, the t_epoch value will
+ * be set to zero to indicate that the new congestion
+ * avoidance stage has begun.
+ */
+ if (cubic_data->t_epoch == 0) {
cubic_data->t_epoch = ticks;
- cubic_data->K = cubic_k(cubic_data->W_max /
- CCV(ccv, t_maxseg));
+ cubic_data->cwnd_epoch = 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));
+ cubic_data->W_est = cubic_data->cwnd_epoch;
+ }
+ cubic_data->flags &= ~(CUBICFLAG_IN_SLOWSTART | CUBICFLAG_IN_APPLIMIT);
+
+ /*
+ * If we're not in slow start and we're probing for a
+ * new cwnd limit at the start of a connection
+ * (happens when hostcache has a relevant entry),
+ * keep updating our current estimate of the
+ * cwnd_prior and W_max.
+ */
+ if ((cubic_data->num_cong_events == 0) &&
+ (cubic_data->cwnd_prior < CCV(ccv, snd_cwnd))) {
+ cubic_data->cwnd_prior = CCV(ccv, snd_cwnd);
+ cubic_data->W_max = cubic_data->cwnd_prior;
+ cubic_data->K = 0;
}
+
usecs_since_epoch = (ticks - cubic_data->t_epoch) * tick;
if (usecs_since_epoch < 0) {
- /*
- * dragging t_epoch along
- */
+ /* dragging t_epoch along */
usecs_since_epoch = INT_MAX;
cubic_data->t_epoch = ticks - INT_MAX;
}
/*
- * The mean RTT is used to best reflect the equations in
- * the I-D. Using min_rtt in the tf_cwnd calculation
- * causes W_est to grow much faster than it should if the
- * RTT is dominated by network buffering rather than
- * propagation delay.
+ * RFC9438 Section 4.8:
+ * Prevent sudden increase in congestion window in
+ * the first congestion avoidance stage after a RTO.
*/
- W_est = tf_cwnd(usecs_since_epoch, cubic_data->mean_rtt_usecs,
- cubic_data->W_max, CCV(ccv, t_maxseg));
+ if (cubic_data->flags & CUBICFLAG_RTO_EVENT) {
+ cubic_data->flags &= ~CUBICFLAG_RTO_EVENT;
+ W_est = CCV(ccv, snd_cwnd);
+ cubic_data->W_est = cubic_data->W_max = W_est;
+ cubic_data->K = 0;
+ } else {
+ /* Get the Reno-friendly window estimate */
+ W_est = cubic_data->W_est = tf_cwnd(cubic_data->W_est,
+ ccv->bytes_this_ack, CCV(ccv, snd_cwnd),
+ cubic_data->cwnd_prior, CCV(ccv, t_maxseg));
+ }
- W_cubic = cubic_cwnd(usecs_since_epoch +
- cubic_data->mean_rtt_usecs,
- cubic_data->W_max,
- CCV(ccv, t_maxseg),
- cubic_data->K);
+ /* Get CUBIC window */
+ W_cubic = cubic_cwnd(usecs_since_epoch + cubic_data->mean_rtt_usecs,
+ cubic_data->W_max, CCV(ccv, t_maxseg), cubic_data->K);
ccv->flags &= ~CCF_ABC_SENTAWND;
if (W_cubic < W_est) {
- /*
- * TCP-friendly region, follow tf
- * cwnd growth.
- */
+ /* If we are in the Reno-friendly region */
if (CCV(ccv, snd_cwnd) < W_est)
- CCV(ccv, snd_cwnd) = ulmin(W_est, INT_MAX);
- } else if (CCV(ccv, snd_cwnd) < W_cubic) {
- /*
- * Concave or convex region, follow CUBIC
- * cwnd growth.
- * Only update snd_cwnd, if it doesn't shrink.
- */
- CCV(ccv, snd_cwnd) = ulmin(W_cubic, INT_MAX);
- }
-
- /*
- * If we're not in slow start and we're probing for a
- * new cwnd limit at the start of a connection
- * (happens when hostcache has a relevant entry),
- * keep updating our current estimate of the
- * W_max.
- */
- if (((cubic_data->flags & CUBICFLAG_CONG_EVENT) == 0) &&
- 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));
+ CCV(ccv, snd_cwnd) = ulmin(W_est, UINT_MAX);
+ } else {
+ /* If we are in the CUBIC concave/convex region */
+ if (W_cubic < CCV(ccv, snd_cwnd)) /* Lower bound */
+ target = CCV(ccv, snd_cwnd);
+ else if (W_cubic > ((CCV(ccv, snd_cwnd) * 3) >> 1)) /* Upper bound */
+ target = (CCV(ccv, snd_cwnd) * 3) >> 1;
+ else
+ target = W_cubic;
+ /* Increase the congestion window by (target - cwnd) / cwnd */
+ incr = (((target - CCV(ccv, snd_cwnd)) << CUBIC_SHIFT) /
+ CCV(ccv, snd_cwnd)) >> CUBIC_SHIFT;
+ CCV(ccv, snd_cwnd) = ulmin(CCV(ccv, snd_cwnd) + incr, UINT_MAX);
}
}
} else if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) &&
!(ccv->flags & CCF_CWND_LIMITED)) {
cubic_data->flags |= CUBICFLAG_IN_APPLIMIT;
+ cubic_data->t_epoch = 0;
}
}
@@ -353,8 +371,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.
@@ -364,7 +383,6 @@
cubic_log_hystart_event(ccv, cubic_data, 12, CCV(ccv, snd_ssthresh));
}
newreno_cc_after_idle(ccv);
- cubic_data->t_epoch = ticks;
}
static void
@@ -393,9 +411,10 @@
cubic_data = ptr;
/* Init some key variables with sensible defaults. */
- cubic_data->t_epoch = ticks;
+ cubic_data->t_epoch = 0;
cubic_data->min_rtt_usecs = TCPTV_SRTTBASE;
cubic_data->mean_rtt_usecs = 1;
+ cubic_data->num_cong_events = 0;
ccv->cc_data = cubic_data;
cubic_data->flags = CUBICFLAG_HYSTART_ENABLED;
@@ -419,6 +438,7 @@
static void
cubic_cong_signal(struct cc_var *ccv, uint32_t type)
{
+ unsigned long ssthresh;
struct cubic *cubic_data;
u_int mss;
@@ -435,10 +455,10 @@
}
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);
+ ssthresh = cubic_get_ssthresh(ccv, mss);
+ CCV(ccv, snd_ssthresh) = ulmax(ssthresh, 2 * mss);
+ cubic_data->num_cong_events++;
+ cubic_data->t_epoch = 0; /* This will recalculate K */
}
ENTER_RECOVERY(CCV(ccv, t_flags));
}
@@ -452,17 +472,17 @@
cubic_log_hystart_event(ccv, cubic_data, 9, CCV(ccv, snd_ssthresh));
}
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);
- CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh);
+ ssthresh = cubic_get_ssthresh(ccv, mss);
+ CCV(ccv, snd_ssthresh) = ulmax(ssthresh, 2 * mss);
+ CCV(ccv, snd_cwnd) = ulmax(ssthresh, mss);
+ cubic_data->num_cong_events++;
+ cubic_data->t_epoch = 0; /* This will recalculate K */
ENTER_CONGRECOVERY(CCV(ccv, t_flags));
}
break;
case CC_RTO:
- /* RFC8312 Section 4.7 */
+ /* RFC9438 Section 4.9 */
if (CCV(ccv, t_rxtshift) == 1) {
/*
* Remember the state only for the first RTO event. This
@@ -477,16 +497,15 @@
cubic_data->undo_W_max = cubic_data->W_max;
cubic_data->undo_K = cubic_data->K;
}
- cubic_data->flags |= CUBICFLAG_CONG_EVENT | CUBICFLAG_RTO_EVENT;
- cubic_data->undo_W_max = cubic_data->W_max;
+ cubic_data->flags |= CUBICFLAG_RTO_EVENT;
cubic_data->num_cong_events++;
- CCV(ccv, snd_ssthresh) = ((uint64_t)CCV(ccv, snd_cwnd) *
- CUBIC_BETA) >> CUBIC_SHIFT;
+ ssthresh = (cubic_compute_pipe(ccv) * CUBIC_BETA) >> CUBIC_SHIFT;
+ CCV(ccv, snd_ssthresh) = ulmax(ssthresh, 2 * mss);
CCV(ccv, snd_cwnd) = mss;
break;
case CC_RTO_ERR:
- cubic_data->flags &= ~(CUBICFLAG_CONG_EVENT | CUBICFLAG_RTO_EVENT);
+ cubic_data->flags &= ~CUBICFLAG_RTO_EVENT;
cubic_data->num_cong_events--;
cubic_data->K = cubic_data->undo_K;
cubic_data->cwnd_prior = cubic_data->undo_cwnd_prior;
@@ -506,11 +525,14 @@
cubic_data = ccv->cc_data;
/*
- * Ensure we have a sane initial value for W_max recorded. Without
+ * Ensure we have a sane initial value for a few variables here. Without
* this here bad things happen when entries from the TCP hostcache
* get used.
*/
- cubic_data->W_max = CCV(ccv, snd_cwnd);
+ cubic_data->cwnd_prior = CCV(ccv, snd_cwnd);
+ cubic_data->W_max = cubic_data->cwnd_prior;
+ cubic_data->cwnd_epoch = cubic_data->cwnd_prior;
+ cubic_data->K = 0;
}
static int
@@ -526,7 +548,7 @@
cubic_post_recovery(struct cc_var *ccv)
{
struct cubic *cubic_data;
- int pipe;
+ unsigned long pipe;
cubic_data = ccv->cc_data;
pipe = 0;
@@ -539,10 +561,7 @@
*
* XXXLAS: Find a way to do this without needing curack
*/
- if (V_tcp_do_newsack)
- pipe = tcp_compute_pipe(ccv->ccvc.tcp);
- else
- pipe = CCV(ccv, snd_max) - ccv->curack;
+ pipe = cubic_compute_pipe(ccv);
if (pipe < CCV(ccv, snd_ssthresh))
/*
@@ -552,10 +571,7 @@
CCV(ccv, snd_cwnd) = max(pipe, CCV(ccv, t_maxseg)) +
CCV(ccv, t_maxseg);
else
- /* Update cwnd based on beta and adjusted W_max. */
- CCV(ccv, snd_cwnd) = max(((uint64_t)cubic_data->W_max *
- CUBIC_BETA) >> CUBIC_SHIFT,
- 2 * CCV(ccv, t_maxseg));
+ CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh);
}
/* Calculate the average RTT between congestion epochs. */
@@ -583,6 +599,7 @@
cubic_data = ccv->cc_data;
t_srtt_usecs = tcp_get_srtt(ccv->ccvc.tcp,
TCP_TMR_GRANULARITY_USEC);
+
/*
* Record the current SRTT as our minrtt if it's the smallest
* we've seen or minrtt is currently equal to its initialised
@@ -592,8 +609,10 @@
*/
if ((t_srtt_usecs < cubic_data->min_rtt_usecs ||
cubic_data->min_rtt_usecs == TCPTV_SRTTBASE)) {
- /* A minimal rtt is a single unshifted tick of a ticks
- * timer. */
+ /*
+ * A minimal rtt is a single unshifted tick of a
+ * ticks timer.
+ */
cubic_data->min_rtt_usecs = max(tick >> TCP_RTT_SHIFT,
t_srtt_usecs);
@@ -618,38 +637,33 @@
/*
* Update the ssthresh in the event of congestion.
*/
-static void
-cubic_ssthresh_update(struct cc_var *ccv, uint32_t maxseg)
+static unsigned long
+cubic_get_ssthresh(struct cc_var *ccv, uint32_t maxseg)
{
struct cubic *cubic_data;
- uint32_t ssthresh;
uint32_t cwnd;
+ unsigned long pipe;
cubic_data = ccv->cc_data;
cwnd = CCV(ccv, snd_cwnd);
- /* Fast convergence heuristic. */
+ cubic_data->cwnd_prior = cwnd;
+
+ /*
+ * RFC9438 Section 4.7:
+ * Fast convergence heuristic
+ */
if (cwnd < cubic_data->W_max) {
cwnd = ((uint64_t)cwnd * CUBIC_FC_FACTOR) >> CUBIC_SHIFT;
}
- cubic_data->undo_W_max = cubic_data->W_max;
cubic_data->W_max = cwnd;
/*
- * On the first congestion event, set ssthresh to cwnd * 0.5
- * and reduce W_max to cwnd * beta. This aligns the cubic concave
- * region appropriately. On subsequent congestion events, set
- * ssthresh to cwnd * beta.
+ * RFC9438 Section 4.6:
+ * Calculate the ssthresh using the outstanding unacknowledged data
*/
- if ((cubic_data->flags & CUBICFLAG_CONG_EVENT) == 0) {
- ssthresh = cwnd >> 1;
- cubic_data->W_max = ((uint64_t)cwnd *
- CUBIC_BETA) >> CUBIC_SHIFT;
- } else {
- ssthresh = ((uint64_t)cwnd *
- CUBIC_BETA) >> CUBIC_SHIFT;
- }
- CCV(ccv, snd_ssthresh) = max(ssthresh, 2 * maxseg);
+ pipe = cubic_compute_pipe(ccv);
+ return ((pipe * CUBIC_BETA) >> CUBIC_SHIFT);
}
static void
@@ -727,5 +741,17 @@
cubic_log_hystart_event(ccv, cubicd, 4, round_cnt);
}
+static unsigned long
+cubic_compute_pipe(struct cc_var *ccv)
+{
+ unsigned long pipe;
+
+ if (V_tcp_do_newsack)
+ pipe = tcp_compute_pipe(ccv->ccvc.tcp);
+ else
+ pipe = CCV(ccv, snd_max) - ccv->curack;
+ return pipe;
+}
+
DECLARE_CC_MODULE(cubic, &cubic_cc_algo);
MODULE_VERSION(cubic, 2);

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 26, 8:57 PM (7 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26225968
Default Alt Text
D41715.id131749.diff (19 KB)

Event Timeline