Skip to main content

CUBACK: CUBIC Driven by the ACK Clock
draft-kazuho-ccwg-cuback-00

Document Type Active Internet-Draft (individual)
Author Kazuho Oku
Last updated 2026-09-25
RFC stream (None)
Intended RFC status (None)
Formats
Stream Stream state (No stream defined)
Consensus boilerplate Unknown
RFC Editor Note (None)
IESG IESG state I-D Exists
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-kazuho-ccwg-cuback-00
Congestion Control Working Group                        奥 一穂 (K. Oku)
Internet-Draft                                                    Fastly
Intended status: Standards Track                       25 September 2026
Expires: 29 March 2027

                 CUBACK: CUBIC Driven by the ACK Clock
                      draft-kazuho-ccwg-cuback-00

Abstract

   This document specifies Cuback, an ACK-driven reformulation of CUBIC
   congestion control.  It simplifies implementation by replacing
   CUBIC's mutable time- and ACK-driven state with pure functions over
   immutable per-epoch parameters, for which test vectors are provided.
   Congestion-window growth uses the same ACK-driven mechanism as Reno,
   removing several sources of implementation error.  When entering a
   high-capacity path, a newcomer converges on its share sooner than
   under CUBIC, so short flows complete earlier.

Discussion Venues

   This note is to be removed before publishing as an RFC.

   Discussion of this document takes place on the Congestion Control
   Working Group Working Group mailing list (ccwg@ietf.org), which is
   archived at https://mailarchive.ietf.org/arch/browse/ccwg/.

   Source for this draft and an issue tracker can be found at
   https://github.com/kazuho/draft-kazuho-ccwg-cuback.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 29 March 2027.

Oku                       Expires 29 March 2027                 [Page 1]
Internet-Draft                   cuback                   September 2026

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.  Code Components
   extracted from this document must include Revised BSD License text as
   described in Section 4.e of the Trust Legal Provisions and are
   provided without warranty as described in the Revised BSD License.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   2
   2.  Conventions and Definitions . . . . . . . . . . . . . . . . .   4
   3.  Cuback Congestion Avoidance . . . . . . . . . . . . . . . . .   4
     3.1.  Fast Convergence  . . . . . . . . . . . . . . . . . . . .   6
     3.2.  Spurious Congestion Events  . . . . . . . . . . . . . . .   6
     3.3.  Application-Limited Senders . . . . . . . . . . . . . . .   6
   4.  Relationship to RFC 9438  . . . . . . . . . . . . . . . . . .   6
     4.1.  Sensitivity to the Bandwidth Estimate . . . . . . . . . .   7
     4.2.  Convergence under the ACK Clock . . . . . . . . . . . . .   7
     4.3.  Sensitivity to the Timing of Clock Transitions  . . . . .   8
     4.4.  The Reno-Friendly Estimate  . . . . . . . . . . . . . . .   8
     4.5.  Smoothing the Cubic Growth  . . . . . . . . . . . . . . .   9
     4.6.  Calculation Overhead  . . . . . . . . . . . . . . . . . .   9
   5.  Security Considerations . . . . . . . . . . . . . . . . . . .  10
   6.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  10
   7.  References  . . . . . . . . . . . . . . . . . . . . . . . . .  10
     7.1.  Normative References  . . . . . . . . . . . . . . . . . .  10
     7.2.  Informative References  . . . . . . . . . . . . . . . . .  10
   Appendix A.  Derivation of the Increase Function  . . . . . . . .  11
   Appendix B.  Test Vectors . . . . . . . . . . . . . . . . . . . .  12
   Appendix C.  An Approximation of the Cube Root  . . . . . . . . .  13
   Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . .  14
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  14

1.  Introduction

   CUBIC [CUBIC] is a widely deployed congestion-control algorithm that
   improves scalability over Reno [RENO] by defining congestion-window
   growth as a cubic function of elapsed time.  Its implementation,
   however, is more complex than the growth function itself might
   suggest.

Oku                       Expires 29 March 2027                 [Page 2]
Internet-Draft                   cuback                   September 2026

   During congestion avoidance, a CUBIC sender maintains two
   independently evolving window estimates: the time-driven cubic window
   and the ACK-driven Reno-friendly window.  The sender must update both
   estimates and select the larger of the two.  In addition, because the
   cubic window advances with wall-clock time, the sender needs mutable
   epoch state and a state machine that pauses the cubic clock when the
   sender ceases to be congestion-control limited and resumes it when
   transmission becomes limited by the congestion window again.
   Correctly maintaining these states complicates implementations and
   their interaction with application-limited periods and other
   congestion-control transitions.

   This document specifies Cuback, an ACK-driven reformulation of CUBIC.
   Cuback expresses both the cubic and Reno-friendly growth functions in
   terms of the amount of data that must be acknowledged for the
   congestion window to reach a given value.  The parameters defining
   those functions are established at the beginning of a congestion-
   avoidance epoch and remain immutable for the duration of that epoch.
   Congestion-window growth can therefore be calculated from a pure
   function of the current congestion window and the per-epoch
   parameters, without maintaining separately evolving cubic and Reno-
   friendly window estimates.

   This formulation also eliminates the need to pause and resume a wall-
   clock-driven CUBIC epoch.  When acknowledgments stop arriving,
   advancement along the Cuback curves stops naturally.  The remaining
   runtime state is essentially the same as in Reno: the sender tracks
   how many additional bytes need to be acknowledged before increasing
   the congestion window by one MSS.

   Cuback therefore retains the characteristic growth behavior of CUBIC
   while reducing congestion avoidance to the same ACK-driven window-
   increase mechanism used by Reno.  In both Reno and Cuback,
   acknowledged bytes are accumulated until enough have been received to
   increase the congestion window by one MSS.  The difference lies only
   in how the required number of acknowledged bytes is calculated: Reno
   derives it directly from the current congestion window, whereas
   Cuback obtains it by evaluating the pure functions defined in this
   document.

   What remains of CUBIC's complexity is confined to a pure function of
   the congestion window and the per-epoch immutables, which can be
   validated directly from its inputs and outputs without exercising a
   sequence of state-machine transitions.  An implementation can
   therefore be checked against known values, and is correspondingly
   less prone to error.  This document includes test vectors for that
   purpose.

Oku                       Expires 29 March 2027                 [Page 3]
Internet-Draft                   cuback                   September 2026

   The use of the ACK clock has a performance benefit as well.  When a
   new flow joins a high-capacity path already carrying an established
   flow, it acquires its share more rapidly than it would under CUBIC.
   Cuback derives its growth rate from the congestion window and round-
   trip time recorded at the previous congestion event.  Because the
   cubic function gives a flow with a smaller window a larger
   proportional increase, a newcomer gains share; its ACK rate, and
   hence its ACK clock, runs faster than originally anticipated.  This
   gain compounds over successive round trips, and reduces the time to
   completion of short flows, such as the delivery of HTTP objects.  The
   advantage diminishes as the flow's rate converges on the value it
   recorded.

   Cuback alters only the congestion avoidance stage of CUBIC.  All
   other behavior specified in [CUBIC] applies unchanged.

2.  Conventions and Definitions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
   "OPTIONAL" in this document are to be interpreted as described in
   BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
   capitals, as shown here.

   This document uses the notation of [CUBIC], in which window sizes are
   expressed in segments.  An implementation that counts bytes instead
   scales each window value by SMSS, divides the sums appearing in
   Section 3 by SMSS, and expresses the lower bound on D(w) as 2 * SMSS.

3.  Cuback Congestion Avoidance

   During congestion avoidance, a Reno sender accumulates the data
   acknowledged and increases cwnd by one segment each time a threshold
   D(cwnd) is reached:

   on entering congestion avoidance:
     pending = 0

   on receiving an acknowledgement, while cwnd >= ssthresh:
     pending = pending + segments_acked
     while pending >= D(cwnd):
       pending = pending - D(cwnd)
       cwnd = cwnd + 1

   In Reno, that threshold is the congestion window itself:

   D_reno(cwnd) = cwnd

Oku                       Expires 29 March 2027                 [Page 4]
Internet-Draft                   cuback                   September 2026

   Cuback retains the mechanism above unchanged and replaces only the
   threshold, where A(w) is the amount of data, counted from the
   beginning of the current congestion avoidance stage, that has to be
   acknowledged for the congestion window to reach w:

D(w)       = max(2, A(w + 1) - A(w))

A(w)       = min(A_cubic(w), A_reno(w))

A_cubic(w) = bandwidth * (K(W_max, cwnd_epoch) + cbrt((w - W_max) / C))

A_reno(w)  = (w - cwnd_epoch) * (w + cwnd_epoch - 1)
               / (2 * alpha_cubic)                            w <= W_max

           = (W_max - cwnd_epoch) * (W_max + cwnd_epoch - 1)
               / (2 * alpha_cubic)
             + (w - W_max) * (w + W_max - 1) / 2              w >  W_max

K(W_max, cwnd_epoch) = cbrt((W_max - cwnd_epoch) / C)

   W_max, bandwidth, and cwnd_epoch are fixed when the congestion
   avoidance stage begins and do not change until the next congestion
   event:

   *  W_max is as defined in Section 4.1.2 of [CUBIC].  It is set to
      cwnd_prior, the congestion window before the reduction at the
      congestion event that began the stage.

   *  bandwidth is an estimate of the rate at which the bottleneck
      delivers data, in segments per second.  It is set at the
      congestion event to cwnd_prior divided by the smoothed round-trip
      time.

   *  cwnd_epoch is the congestion window at the beginning of the
      congestion avoidance stage, as defined in Section 4.1.2 of
      [CUBIC].

   alpha_cubic, beta_cubic, and C are the constants defined in [CUBIC],
   with recommended values:

   beta_cubic  = 0.7
   alpha_cubic = 0.529  # 3 * (1 - beta_cubic) / (1 + beta_cubic)
   C           = 0.4

   A sender that derives ssthresh from flight_size rather than from cwnd
   (Section 4.6 of [CUBIC]) MUST use flight_size in place of cwnd_prior
   throughout this section.  W_max, cwnd_epoch, and bandwidth MUST be
   derived from the same quantity.

Oku                       Expires 29 March 2027                 [Page 5]
Internet-Draft                   cuback                   September 2026

   When congestion avoidance is entered without a congestion event, such
   as on exiting slow start, the parameters are established at that
   point instead. cwnd is not reduced, so W_max equals cwnd_epoch and K
   is zero, and A(w) describes growth along the convex region alone.

   The expressions above are derived in Appendix A.

3.1.  Fast Convergence

   Fast convergence is applied as described in Section 4.7 of [CUBIC]:
   on a congestion event, if cwnd is below W_max, W_max is reduced
   before cwnd is:

   W_max = cwnd * (1 + beta_cubic) / 2

   Section 4.3 of [CUBIC] keys the switch to alpha_cubic = 1 to
   cwnd_prior rather than to W_max, so A_reno in Section 3 uses
   cwnd_prior in its place; a sender that does not retain it can recover
   it as cwnd_epoch / beta_cubic.

3.2.  Spurious Congestion Events

   When a congestion event is determined to have been spurious
   (Section 4.9 of [CUBIC]), a sender that reverts cwnd and ssthresh
   MUST also restore W_max, bandwidth, and cwnd_epoch to the values they
   held before the event.

3.3.  Application-Limited Senders

   The application-limited clock handling required by Section 4.2 of
   [CUBIC] has no counterpart in Cuback, there being no clock to pause
   and resume.

   The rules of [I-D.ietf-ccwg-ratelimited-increase], which update
   [CUBIC], bound the increase of a rate-limited sender without any
   determination of its state.  Even without them, growth is governed by
   acknowledged data rather than by elapsed time: an idle sender accrues
   no growth, while a sender that continues to deliver data below cwnd
   grows only in proportion to that delivered data; see Section 4.3.

4.  Relationship to RFC 9438

Oku                       Expires 29 March 2027                 [Page 6]
Internet-Draft                   cuback                   September 2026

4.1.  Sensitivity to the Bandwidth Estimate

   bandwidth scales A_cubic linearly, so an error in it is an error in
   the rate at which the cubic curve is traversed: an underestimate
   traverses the curve more quickly than elapsed time would, and an
   overestimate more slowly.  The round-trip time it is derived from has
   to describe the path as it was while cwnd was at its peak, with the
   bottleneck queue at its deepest.

   The error is bounded in either direction by mechanisms already
   present.  An overstated bandwidth makes A_cubic large, and A_reno
   carries no bandwidth term at all, so A(w) becomes A_reno(w): the flow
   then grows at the Reno-friendly rate, and no error in bandwidth can
   slow it below that.  An understated bandwidth makes A_cubic small,
   and the lower bound of two segments on D(w) caps growth at half the
   congestion window per round trip, which [CUBIC] adopts to keep the
   increase below that of slow start.

   Between those bounds the estimate matters only at windows large
   enough for the cubic curve to govern.  Windows that large deliver
   many acknowledgements per round trip, and a QUIC sender takes a
   round-trip sample from every acknowledgement that advances the
   largest acknowledged packet number [RFC9002], so the smoothed round-
   trip time follows the path closely by the time the estimate matters.

4.2.  Convergence under the ACK Clock

   Deriving the clock from acknowledgements reinforces the convergence
   that AIMD provides, because bandwidth records the rate the flow was
   achieving before it reduced.  A flow holding a large share gives up
   the most at a congestion event, so the rate it goes on to achieve
   falls below the value it recorded and its clock runs slow.  A flow
   arriving with a small share records a correspondingly small rate and
   then achieves more than it recorded, so its clock runs fast.  The
   congestion window advances fastest for the flow gaining share and
   slowest for the one giving it up.

   The curve advances at the ratio of the rate the flow is currently
   achieving to the rate recorded at the last congestion event.  A flow
   that has since doubled its share traverses the curve twice as fast as
   elapsed time would carry it; one that has halved its share, half as
   fast.  The advantage therefore decays as the achieved rate converges
   on the recorded one.

Oku                       Expires 29 March 2027                 [Page 7]
Internet-Draft                   cuback                   September 2026

4.3.  Sensitivity to the Timing of Clock Transitions

   Section 4.2 of [CUBIC] requires that elapsed time exclude periods
   during which cwnd was not updated because the sender was application
   limited.  A CUBIC sender therefore has to pause its clock as the flow
   becomes application limited and resume it as the flow ceases to be,
   and an error at either edge is an error in the elapsed time the curve
   is read against.

   Treating an application-limited sender as congestion-window limited
   leaves the clock running.  W_cubic(t) advances while the flow is not
   filling cwnd, and cwnd grows on evidence the path never supplied;
   Section 5.8 of [CUBIC] names the consequence, that W_cubic(t) "might
   be very high after restarting from these periods".  Treating a
   congestion-window-limited sender as application limited stops the
   clock instead, so the elapsed time that should have advanced the
   curve is never accrued and the flow grows too slowly.

   Neither edge is easy to observe.  A sender might emit as many
   datagrams as it can in one pass and so appear limited by the
   congestion controller, even though its bytes in flight are below
   cwnd.  Conversely, an in-stack pacer might withhold emission after a
   train of acknowledgements, leaving bytes in flight below cwnd
   although the connection is still limited by the congestion window.
   [I-D.ietf-ccwg-ratelimited-increase] updates [CUBIC], mitigating the
   impact of such overgrowth by capping cwnd at a value derived from the
   largest FlightSize observed, but a CUBIC sender is still required to
   pause and resume its clock at the correct moments.

   Cuback has no clock to stop or start.  When the sender stops, the
   advance of A(w) stops with it: no acknowledgements arrive, and
   nothing accrues to be caught up when transmission resumes.  The case
   in which a mistimed CUBIC clock does the most damage therefore does
   not arise.

   A sender that keeps sending but holds less than cwnd in flight is not
   protected altogether, only bounded.  Growth is governed by the amount
   of data acknowledged, as in Reno, so cwnd advances in proportion to
   what the path delivered rather than in proportion to elapsed time.
   Applying [I-D.ietf-ccwg-ratelimited-increase] caps what remains,
   holding cwnd to what one window of the largest FlightSize observed
   would yield.

4.4.  The Reno-Friendly Estimate

   Section 4.3 of [CUBIC] advances W_est on each acknowledgement:

   W_est = W_est + alpha_cubic * segments_acked / cwnd

Oku                       Expires 29 March 2027                 [Page 8]
Internet-Draft                   cuback                   September 2026

   where cwnd is the congestion window in effect.  While the cubic curve
   governs, that window is larger than W_est, so the growth of W_est
   depends on the trajectory of the other curve.  This coupling cannot
   be expressed as a function of W_est alone, and A_reno instead inverts
   the standalone recurrence, in which the divisor is the Reno-friendly
   window itself.

   Where A_reno is the smaller of the two curves, cwnd is the Reno-
   friendly window and the two formulations coincide exactly: both
   increase the window by one segment for every cwnd / alpha_cubic
   segments acknowledged.  They differ only in where that region is
   entered.  Because the standalone recurrence uses the smaller divisor,
   it advances faster while the cubic curve governs, and a Cuback sender
   enters the Reno-friendly region somewhat earlier than a sender
   following [CUBIC].

4.5.  Smoothing the Cubic Growth

   Section 4.4 of [CUBIC] and Section 4.5 of [CUBIC] advance cwnd toward
   a target one round trip ahead, W_cubic(t + RTT), rather than
   assigning W_cubic(t) to cwnd directly.  Because the CUBIC curve is
   driven by elapsed time, the growth owed at an acknowledgement depends
   on how long has passed since the previous one, and assigning the
   curve directly would turn a gap in acknowledgements into a step in
   cwnd, which is a burst.  The one-round-trip target, together with the
   per-acknowledgement increase of (target - cwnd) / cwnd, spreads one
   round trip of the curve across one round trip of acknowledgements,
   making the increase proportional to the data acknowledged however the
   acknowledgements are distributed in time.

   Cuback needs no such smoothing.  D(w) is a function of acknowledged
   data alone, so a gap in acknowledgements accrues no growth to be
   caught up, and the increase is proportional to the ack stream by
   construction.

4.6.  Calculation Overhead

   A_reno is arithmetic, but A_cubic requires a cube root.  [CUBIC]
   evaluates one when the epoch begins, to obtain K, and thereafter only
   cubes; Cuback evaluates one whenever it computes D(w).

   Storing the data still needed to increase the window by one segment,
   rather than recomputing D(w) on every acknowledgement, moves the
   evaluation from once per acknowledgement to once per increase.  Each
   increase then evaluates three roots: K, A_cubic(w), and A_cubic(w +
   1).

Oku                       Expires 29 March 2027                 [Page 9]
Internet-Draft                   cuback                   September 2026

   Calculating a cube root to the accuracy required here is cheap.  The
   approximation must be continuous in slope, adjacent evaluations being
   differenced, and one meeting that condition is given in Appendix C.
   It runs in about nine cycles on contemporary hardware, against
   roughly nine hundred to encrypt a 1460-byte segment through an AES-
   GCM-128 pipeline at 1.6 bytes per cycle.  In the worst case, the
   window growing by one segment for every segment acknowledged, the
   overhead is therefore around three percent of the cost of encrypting
   the data that drove it; during congestion avoidance the window
   typically grows far more slowly than that.

   Furthermore, K is fixed for the duration of the epoch and could be
   retained rather than recomputed, and A(w + 1) for one increase is
   A(w) for the next and could be carried forward.  Together these leave
   a single cube root per increase.

5.  Security Considerations

   TODO Security

6.  IANA Considerations

   This document has no IANA actions.

7.  References

7.1.  Normative References

   [CUBIC]    Xu, L., Ha, S., Rhee, I., Goel, V., and L. Eggert, Ed.,
              "CUBIC for Fast and Long-Distance Networks", RFC 9438,
              DOI 10.17487/RFC9438, August 2023,
              <https://www.rfc-editor.org/rfc/rfc9438>.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/rfc/rfc2119>.

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/rfc/rfc8174>.

7.2.  Informative References

   [I-D.ietf-ccwg-ratelimited-increase]
              Welzl, M., Henderson, T., Fairhurst, G., and M. P.
              Tahiliani, "Increase of the Congestion Window when the
              Sender Is Rate-Limited", Work in Progress, Internet-Draft,

Oku                       Expires 29 March 2027                [Page 10]
Internet-Draft                   cuback                   September 2026

              draft-ietf-ccwg-ratelimited-increase-11, 6 September 2026,
              <https://datatracker.ietf.org/doc/html/draft-ietf-ccwg-
              ratelimited-increase-11>.

   [RENO]     Allman, M., Paxson, V., and E. Blanton, "TCP Congestion
              Control", RFC 5681, DOI 10.17487/RFC5681, September 2009,
              <https://www.rfc-editor.org/rfc/rfc5681>.

   [RFC9002]  Iyengar, J., Ed. and I. Swett, Ed., "QUIC Loss Detection
              and Congestion Control", RFC 9002, DOI 10.17487/RFC9002,
              May 2021, <https://www.rfc-editor.org/rfc/rfc9002>.

Appendix A.  Derivation of the Increase Function

   The lower bound of two segments in D(w) limits the increase to one
   half of the congestion window per round trip: cwnd segments are
   acknowledged per round trip, and each one-segment increase consumes
   at least two of them.  It is the counterpart of the constraint target
   <= 1.5 * cwnd in Section 4.4 of [CUBIC] and Section 4.5 of [CUBIC].
   No lower bound on the increase is needed, as A(w) is monotonically
   increasing and D(w) is therefore always positive.

   CUBIC sets its congestion window to the larger of two window growth
   functions.  Both are monotonically increasing, so their maximum is
   monotonically increasing as well, and the inverse of that maximum is
   the minimum of the two inverses.  A(w) is therefore obtained by
   inverting each function separately and taking the smaller of the two
   results.

   A_cubic is the inverse of W_cubic(t) of Section 4.2 of [CUBIC],
   multiplied by bandwidth to express elapsed time as acknowledged data.
   That the curve is zero at w = cwnd_epoch follows from the definition
   of K.

   Sampling bandwidth as cwnd_prior / RTT is the rate at which the flow
   was delivering data over the round trip preceding the congestion
   event.  It carries an identity:

   bandwidth * RTT = cwnd_prior

   While the congestion window is at cwnd_prior, one round trip of
   acknowledgements advances A(w) by exactly one round trip along the
   underlying cubic curve.

Oku                       Expires 29 March 2027                [Page 11]
Internet-Draft                   cuback                   September 2026

   A_reno is the inverse of the Reno-friendly increase of Section 4.3 of
   [CUBIC]: one segment for every cwnd / alpha_cubic segments
   acknowledged, with alpha_cubic replaced by one once the window
   reaches W_max.  Summing those thresholds over the segment-spaced
   windows from cwnd_epoch to w yields the expression in Section 3.

   Differencing A_reno recovers exactly the threshold from which it was
   built:

   A_reno(w + 1) - A_reno(w) = w / alpha_cubic

   The Reno-friendly region is therefore not a separate mechanism in
   Cuback.  It is the value that D(w) takes wherever A_reno is the
   smaller of the two curves.  The closed form exists only so that the
   two curves can be compared.

   Differencing A_cubic eliminates K, so an implementation need not
   evaluate it when the cubic curve is the smaller of the two:

   A_cubic(w + 1) - A_cubic(w)
     = bandwidth * (cbrt((w + 1 - W_max) / C) - cbrt((w - W_max) / C))

Appendix B.  Test Vectors

   A(w) and D(w) are pure functions of the congestion window and the
   parameters of Section 3, so they can be checked directly.  Both
   vectors below use the recommended constants, with alpha_cubic taken
   as 3 * (1 - beta_cubic) / (1 + beta_cubic) rather than the rounded
   0.529.

   The first exercises the Reno-friendly curve. bandwidth is large
   enough here that A_cubic exceeds A_reno at every window shown, so
   A(w) is A_reno(w) throughout.  The window reaches cwnd_prior at 10
   segments, where alpha_cubic is replaced by one and each further
   segment costs exactly its own window in acknowledged data.

Oku                       Expires 29 March 2027                [Page 12]
Internet-Draft                   cuback                   September 2026

   cwnd_epoch = 7 segments
   cwnd_prior = 10 segments
   W_max      = 10 segments
   RTT        = 0.1 s
   bandwidth  = 100 segments/s

      w      A(w)      D(w)
      7    0.0000   13.2222
      8   13.2222   15.1111
      9   28.3333   17.0000
     10   45.3333   10.0000
     11   55.3333   11.0000
     12   66.3333

   The second exercises the cubic curve, the parameters being chosen so
   that K is exactly 10 seconds.  A_reno exceeds A_cubic at every window
   shown, so A(w) is A_cubic(w) throughout.  A(W_max) divided by
   bandwidth recovers K, and the data needed to climb the 50 segments
   below W_max equals that needed for the 50 above, the curve being
   point-symmetric about W_max.

   cwnd_epoch = 600 segments
   cwnd_prior = 1000 segments
   W_max      = 1000 segments
   RTT        = 0.1 s
   bandwidth  = 10000 segments/s
   K          = 10 s

         w        A(w)
       600           0
       950      50 000
      1000     100 000
      1050     150 000
      1400     200 000

   D(w) on the cubic curve is the difference of two cube roots taken at
   adjacent windows, so an implementation using an approximation should
   compare accumulated values, as above, rather than individual
   increases; see Section 4.6.

Appendix C.  An Approximation of the Cube Root

   The cube root function below is provided for reference and is placed
   in the public domain.  It assumes IEEE 754 binary64.  Its maximum
   relative error is about 3.5e-5 and the relative error of its slope is
   below 8.5e-4, holding each per-segment increase to roughly 0.1
   percent, and it runs in about nine cycles on a Zen 3 core.

Oku                       Expires 29 March 2027                [Page 13]
Internet-Draft                   cuback                   September 2026

   #define DBL2BITS(x) (((union { double f; uint64_t u; }){x}).u)
   #define BITS2DBL(x) (((union { uint64_t u; double f; }){x}).f)

   double approx_cbrt(double x)
   {
       uint64_t u = DBL2BITS(x);
       uint64_t abs_u = u & 0x7fffffffffffffff;
       uint64_t exp = abs_u >> 52;

       if (abs_u == 0)
           return x;
       if (exp == 0 || exp == 0x7ff)
           return cbrt(x);

       int e = (int)exp - 1023;
       int q = e / 3;
       int r = e - 3 * q;
       if (r < 0) {
           r += 3;
           --q;
       }

       uint64_t mant = abs_u & 0xfffffffffffff;
       double m = BITS2DBL(mant | ((uint64_t)1023 << 52));

       double y = -0.010279630422175424;
       y = 0.08469719299100167 + m * y;
       y = -0.2988437245358902 + m * y;
       y = 0.7177663288981584 + m * y;
       y = 0.5066598330689034 + m * y;

       static const double cbrt2_to_r[3] = {1.0, 1.2599210498948731648,
                                            1.5874010519681994748};
       double two_to_q = BITS2DBL((uint64_t)(q + 1023) << 52);

       y *= cbrt2_to_r[r] * two_to_q;
       return (u >> 63) ? -y : y;
   }

Acknowledgments

   TODO acknowledge.

Author's Address

   Kazuho Oku
   Fastly
   Email: kazuhooku@gmail.com

Oku                       Expires 29 March 2027                [Page 14]
Internet-Draft                   cuback                   September 2026

   Additional contact information:

      奥 一穂
      Fastly

Oku                       Expires 29 March 2027                [Page 15]