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; uint32_t mss, pipe; @@ -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 @@ -476,25 +496,16 @@ cubic_data->undo_cwnd_prior = cubic_data->cwnd_prior; cubic_data->undo_W_max = cubic_data->W_max; cubic_data->undo_K = cubic_data->K; - if (V_tcp_do_newsack) { - pipe = tcp_compute_pipe(ccv->ccvc.tcp); - } else { - pipe = CCV(ccv, snd_max) - - CCV(ccv, snd_fack) + - CCV(ccv, sackhint.sack_bytes_rexmit); - } - CCV(ccv, snd_ssthresh) = max(2, - (((uint64_t)min(CCV(ccv, snd_wnd), pipe) * - CUBIC_BETA) >> CUBIC_SHIFT) / mss) * mss; + ssthresh = ((uint64_t)cubic_compute_pipe(ccv) * CUBIC_BETA) >> CUBIC_SHIFT; + CCV(ccv, snd_ssthresh) = ulmax(ssthresh, 2 * mss); } - 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_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; @@ -514,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 @@ -534,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; @@ -547,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)) /* @@ -560,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. */ @@ -591,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 @@ -600,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); @@ -626,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 @@ -735,5 +741,21 @@ 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(ccv, snd_fack) + + CCV(ccv, sackhint.sack_bytes_rexmit); + } + pipe = min(CCV(ccv, snd_wnd), pipe); + return pipe; +} + DECLARE_CC_MODULE(cubic, &cubic_cc_algo); MODULE_VERSION(cubic, 2); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -479,6 +479,10 @@ INP_WLOCK_ASSERT(tptoinpcb(tp)); if (CC_ALGO(tp)->post_recovery != NULL) { + if (SEQ_LT(tp->snd_fack, th->th_ack) || + SEQ_GT(tp->snd_fack, tp->snd_max)) { + tp->snd_fack = th->th_ack; + } tp->t_ccv.curack = th->th_ack; CC_ALGO(tp)->post_recovery(&tp->t_ccv); }