Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137788019
D41715.id131749.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
19 KB
Referenced Files
None
Subscribers
None
D41715.id131749.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D41715: tcp: Align cubic cc with rfc9438
Attached
Detach File
Event Timeline
Log In to Comment