RFC 9438

CUBIC for Fast and Long-Distance Networks

๐Ÿ“… published August 2023, from ietf

๐ŸŽ€ CUBIC for Fast and Long-Distance Networks ๐ŸŽ€

okay bestie, let's get into this ๐Ÿ’… RFC 9438 is the spec for CUBIC, a TCP congestion control algorithm, and it's giving main character energy โœจ It was written by L. Xu (UNL), S. Ha (Colorado), I. Rhee (Bowery), V. Goel (Apple Inc.), and L. Eggert, Ed. (NetApp). It's dated August 2023, it's a Standards Track document ๐Ÿ”ฅ, it obsoletes RFC 8312, and it updates RFC 5681 ๐Ÿฆ‹. The ISSN is 2070-1721 ๐ŸŒธ

Here's the tea ๐Ÿต Internet Engineering Task Force (IETF) is the org behind it, and it's been published under the Standards Track.

Abstract

CUBIC is a standard TCP congestion control algorithm ๐ŸŽ€ It swaps the linear congestion window increase for a cubic function so things get more scalable and stable on fast, long-distance networks ๐Ÿš€ CUBIC has already been adopted as the default TCP congestion control algorithm by the Linux, Windows, and Apple stacks ๐Ÿ‘‘

This document updates the CUBIC spec to add algorithmic improvements based on those implementations and recent academic work ๐Ÿ’– Since CUBIC has been deployed so extensively, the spec now moves to the Standards Track and obsoletes RFC 8312 โœจ It also updates RFC 5681 so CUBIC's occasionally more aggressive sending behavior is allowed ๐Ÿซถ

Status of This Memo

This is an Internet Standards Track document ๐Ÿฆ‹

This document is a product of the Internet Engineering Task Force (IETF) ๐Ÿ’… It represents the consensus of the IETF community, received public review, and was approved for publication by the Internet Engineering Steering Group (IESG) ๐ŸŒˆ More info on Internet Standards is in Section 2 of RFC 7841 ๐Ÿ“

Info about the current status, any errata, and how to give feedback can be found at https://www.rfc-editor.org/info/rfc9438 ๐Ÿ’œ

Copyright (c) 2023 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 ๐Ÿ“œ Please review these carefully, since they describe your rights and restrictions. 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.  Conventions
3.  Design Principles of CUBIC
  3.1.  Principle 1 for the CUBIC Increase Function
  3.2.  Principle 2 for Reno-Friendliness
  3.3.  Principle 3 for RTT-Fairness
  3.4.  Principle 4 for the CUBIC Decrease Factor
4.  CUBIC Congestion Control
  4.1.  Definitions
    4.1.1.  Constants of Interest
    4.1.2.  Variables of Interest
  4.2.  Window Increase Function
  4.3.  Reno-Friendly Region
  4.4.  Concave Region
  4.5.  Convex Region
  4.6.  Multiplicative Decrease
  4.7.  Fast Convergence
  4.8.  Timeout
  4.9.  Spurious Congestion Events
    4.9.1.  Spurious Timeouts
    4.9.2.  Spurious Fast Retransmits
  4.10. Slow Start
5.  Discussion
  5.1.  Fairness to Reno
  5.2.  Using Spare Capacity
  5.3.  Difficult Environments
  5.4.  Investigating a Range of Environments
  5.5.  Protection against Congestion Collapse
  5.6.  Fairness within the Alternative Congestion Control
        Algorithm
  5.7.  Performance with Misbehaving Nodes and Outside Attackers
  5.8.  Behavior for Application-Limited Flows
  5.9.  Responses to Sudden or Transient Events
  5.10. Incremental Deployment
6.  Security Considerations
7.  IANA Considerations
8.  References
  8.1.  Normative References
  8.2.  Informative References
Appendix A.  Evolution of CUBIC since the Original Paper
Appendix B.  Proof of the Average CUBIC Window Size
Acknowledgments
Authors' Addresses

1. Introduction ๐ŸŒธ

okay so CUBIC is now the default TCP congestion control algorithm in Linux, Windows, and Apple stacks, and it's been used and deployed globally ๐ŸŒ Decade-long deployment in super different Internet scenarios has shown that CUBIC is safe for the global Internet and gives real benefits over classical Reno congestion control [RFC5681] ๐Ÿ’– That's why it's considered the most widely deployed standard for TCP congestion control ๐Ÿ‘‘ CUBIC can also be used for other transport protocols like QUIC [RFC9000] and the Stream Control Transmission Protocol (SCTP) [RFC9260] as a default congestion controller ๐Ÿฆ‹

The design of CUBIC was motivated by a well-documented problem with classical Reno TCP: low utilization over fast and long-distance networks [K03] [RFC3649] ๐Ÿ˜ญ The issue is a slow increase of the congestion window (cwnd) after a congestion event on a network with a large bandwidth-delay product (BDP) ๐Ÿข [HLRX07] notes this shows up even with congestion window sizes of several hundred packets ๐Ÿ’€ It's equally a problem for every Reno-style standard and variant, including TCP-Reno [RFC5681], TCP-NewReno [RFC6582] [RFC6675], SCTP [RFC9260], TCP Friendly Rate Control (TFRC) [RFC5348], and QUIC congestion control [RFC9002], since they all use the same linear increase function for window growth ๐Ÿ™„ In this document, all Reno-style standards and their variants are collectively called "Reno" ๐Ÿซถ

CUBIC, originally proposed in [HRX08], is a modification to classical Reno's congestion control algorithm that fixes this ๐ŸŽ€ Specifically, CUBIC uses a cubic function instead of Reno's linear window increase function to improve scalability and stability under fast and long-distance networks โœจ

This document updates the CUBIC spec to include algorithmic improvements based on the Linux, Windows, and Apple implementations and recent academic work ๐Ÿ’… Since deployment has been so extensive, it also moves the spec to the Standards Track and obsoletes [RFC8312] ๐Ÿฆ‹ That requires updating Section 3 of [RFC5681], which limits how aggressive Reno TCP implementations can be ๐Ÿ˜ค Since CUBIC is sometimes more aggressive than the algorithms in [RFC5681], this document updates the first paragraph of Section 3 of [RFC5681] and replaces it with a normative reference to guideline (1) in Section 3 of [RFC5033], which allows for CUBIC's behavior as defined here ๐ŸŒˆ

Specifically, CUBIC may increase the congestion window more aggressively than Reno during the congestion avoidance phase ๐Ÿ”ฅ According to [RFC5681], during congestion avoidance the sender MUST NOT increment cwnd by more than Sender Maximum Segment Size (SMSS) bytes once per round-trip time (RTT) ๐Ÿ™…โ€โ™€๏ธ CUBIC, on the other hand, may increase cwnd much more aggressively ๐Ÿ’– CUBIC also recommends the HyStart++ algorithm [RFC9406] for slow start ๐Ÿš€ That lets cwnd increase by more than SMSS bytes for incoming acknowledgments during slow start, which the standard behavior in [RFC5681] does not allow ๐Ÿ™ˆ

Binary Increase Congestion Control (BIC-TCP) [XHR04] was the predecessor of CUBIC ๐Ÿ“ Linux selected it as the default TCP congestion control algorithm in 2005, and the wider Internet community used it for several years ๐Ÿงš

CUBIC uses a window increase function similar to BIC-TCP's, but it's designed to be less aggressive and fairer to Reno in bandwidth usage ๐Ÿฆ‹ It keeps BIC-TCP's strengths, like stability, window scalability, and RTT-fairness ๐Ÿ’œ

[RFC5033] documents the IETF's best current practices for specifying new congestion control algorithms, especially ones that differ from the general principles in [RFC2914] ๐Ÿ“š It explains what kind of evaluation the IETF expects to understand whether a new algorithm is suitable, and the process for getting a spec approved for widespread deployment across the global Internet ๐ŸŒ

There are areas where CUBIC differs from congestion control algorithms already published in Standards Track RFCs, and those changes are specified in this document ๐ŸŽ€ It isn't obvious that these changes go beyond the general principles in [RFC2914], so the process in [RFC5033] may not apply ๐Ÿค”

Also, CUBIC spread across the Internet mainly because it was directly adopted by most popular operating systems, and that didn't follow the practices documented in [RFC5033] ๐Ÿ˜… However, because of the Internet-scale deployment experience over a long time, the IETF decided CUBIC could be published as a Standards Track spec โœจ That decision doesn't change the general guidance in [RFC2914] ๐Ÿ’…

The following sections ๐ŸŒท

  1. briefly explain the design principles of CUBIC ๐ŸŽ€
  2. provide the exact specification of CUBIC ๐Ÿ’–
  3. discuss the safety features of CUBIC, following the guidelines in [RFC5033] ๐Ÿ›ก๏ธ

2. Conventions ๐Ÿซถ

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 ๐Ÿ’… (These are the only words that get the strict BCP 14 treatment, so if you see them in all caps, pay attention ๐Ÿ‘€)

3. Design Principles of CUBIC ๐Ÿงš

okay so CUBIC is designed around these principles โœจ

Principle 1: For better network utilization and stability, CUBIC uses both the concave and convex profiles of a cubic function to increase the congestion window size ๐ŸŒˆ It doesn't just use a convex function ๐Ÿฆ‹

Principle 2: To be Reno-friendly, CUBIC is designed to behave like Reno in networks with short RTTs and small bandwidth, where Reno already performs well ๐Ÿซถ

Principle 3: For RTT-fairness, CUBIC is designed to achieve linear bandwidth sharing among flows with different RTTs ๐Ÿ’œ

Principle 4: CUBIC sets its multiplicative window decrease factor so it balances scalability and convergence speed ๐Ÿ”ฅ


(Part 1 of 8. More parts coming, bestie, so stay tuned ๐Ÿ’–๐ŸŽ€)

3.1. Principle 1 for the CUBIC Increase Function

Okay so, CUBIC [HRX08] uses a cubic window increase function ๐Ÿ˜ For better network utilization and stability, it measures growth by the elapsed time since the last congestion event. Most Reno alternatives grow their windows with convex functions, but CUBIC is extra and uses both the concave and convex sides of a cubic curve ๐ŸŒˆ

After a window reduction triggered by a congestion event, CUBIC remembers the congestion window size it had when the event arrived and then does a multiplicative decrease of the window. The congestion event can be detected by duplicate acknowledgments (ACKs), Explicit Congestion Notification-Echo (ECN-Echo (ECE)) ACKs [RFC3168], RACK-TLP for TCP [RFC8985], or QUIC loss detection [RFC9002] โœจ

When CUBIC enters congestion avoidance, it starts growing the window with the concave profile of the cubic function. The cubic function is set to have its plateau at the remembered window size, so the concave growth keeps going until it gets there. After that, the curve flips into the convex profile and convex growth begins ๐ŸŽข

This concave-then-convex style is what makes it so stable while still keeping the network busy [CEHRX09] ๐Ÿ’… The window basically stays put near a plateau around the remembered window size from the last congestion event, which is where network utilization is considered highest. In steady state, most window samples land close to that remembered size, so utilization stays high and things stay stable ๐Ÿฆ‹

Note that congestion control algorithms that only use convex functions to grow the window have their biggest increments right around the remembered window size of the last congestion event. That means lots of packet bursts around the network's saturation point, which can cause frequent global loss synchronizations ๐Ÿ˜ญ

3.2. Principle 2 for Reno-Friendliness

CUBIC promotes per-flow fairness to Reno ๐Ÿค Reno actually does fine on paths with small BDPs. It only runs into trouble when it tries to push bandwidth utilization up on paths with large BDPs ๐Ÿ™ˆ

A congestion control algorithm that wants to be friendly to Reno on a per-flow basis has to grow its window less aggressively in small-BDP networks than in large-BDP networks.

CUBIC's aggressiveness mainly depends on the maximum window size before a window reduction, and that maximum is smaller in small-BDP networks than in large-BDP networks. So CUBIC grows its window less aggressively in small-BDP networks than in large-BDP networks ๐ŸŒธ

Here's the bonus part: whenever the cubic function would grow the window less aggressively than Reno, CUBIC just follows Reno's window size instead. That way CUBIC gets at least the same throughput as Reno in small-BDP networks ๐Ÿ’– The region where CUBIC acts like Reno is called the "Reno-friendly region" ๐Ÿงš

3.3. Principle 3 for RTT-Fairness

Two CUBIC flows with different RTTs have a throughput ratio that's linearly proportional to the inverse of their RTT ratio. A flow's throughput is roughly its congestion window divided by its RTT, so this is literally the math ๐Ÿงฎโœจ

More specifically, CUBIC keeps a window increase rate that doesn't depend on RTT outside the Reno-friendly region. That means flows with different RTTs end up with similar congestion window sizes at steady state when they're operating outside the Reno-friendly region ๐Ÿ‘‘

This linear throughput ratio is kind of like Reno's under an asynchronous loss model, where flows with different RTTs have the same packet loss rate but get their loss events at different times ๐Ÿ•ฐ๏ธ Under a synchronous loss model, though, where flows with different RTTs get loss events at the same time but have different packet loss rates, Reno's throughput ratio becomes quadratically proportional to the inverse of the RTT ratio [XHR04] ๐Ÿ˜ฌ

CUBIC always keeps a linear throughput ratio no matter what the loss environment looks like, which is a real upgrade over Reno ๐Ÿ”ฅ Nobody has agreed on the single best throughput ratio for flows with different RTTs. Still, over wired Internet paths, a linear throughput ratio seems more reasonable than equal throughputs (the same throughput for flows with different RTTs) or a higher-order ratio, like the quadratic throughput ratio Reno gets in synchronous loss environments ๐Ÿ“

3.4. Principle 4 for the CUBIC Decrease Factor

To balance scalability with convergence speed, CUBIC sets its multiplicative window decrease factor to 0.7, while Reno uses 0.5 ๐ŸŽ€

This boosts CUBIC's scalability, but there's a side effect: slower convergence, especially when statistical multiplexing is low. The design follows an observation that HighSpeed TCP (HSTCP) [RFC3649] and other approaches (e.g., [GV02]) also made: the current Internet is getting more asynchronous, with less frequent loss synchronizations under high statistical multiplexing ๐ŸŒ

In environments like that, even strict Multiplicative-Increase Multiplicative-Decrease (MIMD) can converge ๐Ÿฆ‹ CUBIC flows with the same RTT always converge to the same throughput regardless of statistical multiplexing, which gets us intra-algorithm fairness ๐Ÿซถ With sufficient statistical multiplexing, CUBIC's convergence speed is reasonable too โœจ

4. CUBIC Congestion Control

This section walks through how the congestion window gets updated during each of the different stages of the CUBIC congestion controller ๐ŸŽ€

4.1. Definitions

The unit of all window sizes in this document is segments of the SMSS, and the unit of all times is seconds โฑ๏ธ Implementations can use bytes to express window sizes instead. That would mean factoring in the SMSS wherever it's needed, and swapping segments_acked (Figure 4) for the number of acknowledged bytes ๐Ÿ’…

4.1.1. Constants of Interest

  • ฮฒ_cubic: CUBIC multiplicative decrease factor, as described in Section 4.6.
  • ฮฑ_cubic: CUBIC additive increase factor used in the Reno-friendly region, as described in Section 4.3.
  • C: Constant that determines how aggressive CUBIC is when it's competing with other congestion control algorithms in high-BDP networks. Please see Section 5 for more explanation on how it's set. The unit for C is:
                                  segment
                                  โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                                        3
                                  second

4.1.2. Variables of Interest

This section defines the variables you need to implement CUBIC ๐Ÿง 

  • RTT: Smoothed round-trip time in seconds, calculated as described in [RFC6298].
  • cwnd: Current congestion window in segments.
  • ssthresh: Current slow start threshold in segments.
  • cwnd_prior: Size of cwnd in segments at the time of setting ssthresh most recently, either upon exiting the first slow start or just before cwnd was reduced in the last congestion event.
  • W_max: Size of cwnd in segments just before cwnd was reduced in the last congestion event when fast convergence is disabled (same as cwnd_prior on a congestion event). However, if fast convergence is enabled, W_max may be further reduced based on the current saturation point ๐Ÿ“‰
  • K: The time period in seconds it takes to increase the congestion window size at the beginning of the current congestion avoidance stage to W_max โณ
  • t_current: Current time of the system in seconds.
  • t_epoch: The time in seconds at which the current congestion avoidance stage started.
  • cwnd_epoch: The cwnd at the beginning of the current congestion avoidance stage, i.e., at time t_epoch.
  • W_cubic(t): The congestion window in segments at time t in seconds based on the cubic increase function, as described in Section 4.2 ๐Ÿ“ˆ
  • target: Target value of the congestion window in segments after the next RTT -- that is, W_cubic(t + RTT), as described in Section 4.2 ๐ŸŽฏ
  • W_est: An estimate for the congestion window in segments in the Reno-friendly region -- that is, an estimate for the congestion window of Reno ๐Ÿค
  • segments_acked: Number of SMSS-sized segments acked when a "new ACK" is received, i.e., an ACK that cumulatively acknowledges the delivery of previously unacknowledged data. This number will be a decimal value when a new ACK acknowledges an amount of data that is not SMSS-sized. Specifically, it can be less than 1 when a new ACK acknowledges a segment smaller than the SMSS ๐Ÿฅน

4.2. Window Increase Function โœจ

Okay bestie, CUBIC keeps the ACK clocking that Reno has ๐Ÿ’… by only growing the congestion window when a brand new ACK shows up. It doesn't touch the TCP Fast Recovery and Fast Retransmit algorithms at all [RFC6582] [RFC6675] ๐Ÿซถ

During congestion avoidance, once a congestion event gets detected (see Section 3.1), CUBIC switches to a window increase function that is totally different from Reno's ๐Ÿฆ‹

CUBIC's window increase function looks like this:

                                             3
                      W     (t) = C * (t - K)  + W
                       cubic                      max

                                  Figure 1

Here t is the elapsed time in seconds since the start of the current congestion avoidance stage, aka:

                           t = t        - t
                                current    epoch

and t_epoch is the moment that current congestion avoidance stage kicks off. K is the time the function needs to grow the window from its size at the start of the stage back up to W_max, assuming no more congestion events show up. Main character energy, no drama ๐ŸŽ€ K comes from this equation:

                                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                             3  โ”‚W    - cwnd
                             โ•ฒ  โ”‚ max       epoch
                         K =  โ•ฒ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                               โ•ฒโ”‚       C

                                  Figure 2

where cwnd_epoch is the congestion window at the beginning of the current congestion avoidance stage.

When a new ACK comes in during congestion avoidance, CUBIC works out a target congestion window size for after the next RTT, using Figure 1. RTT is the smoothed round-trip time. The lower and upper bounds below keep CUBIC's congestion window increase rate non-decreasing and below the increase rate of slow start [SXEZ19]. It's giving careful and steady ๐ŸŒธ

                 โŽง
                 โŽชcwnd            if  W     (t + RTT) < cwnd
                 โŽช                     cubic
                 โŽจ1.5 * cwnd      if  W     (t + RTT) > 1.5 * cwnd
        target = โŽช                     cubic
                 โŽชW     (t + RTT) otherwise
                 โŽฉ cubic

The elapsed time t in Figure 1 MUST NOT include periods during which cwnd has not been updated due to application-limited behavior (see Section 5.8). So if the app wasn't sending anything, that time doesn't count ๐Ÿ™ˆ

Depending on the current congestion window size cwnd, CUBIC runs in one of three regions ๐ŸŒˆ

  1. The Reno-friendly region, which makes sure CUBIC gets at least the same throughput as Reno ๐Ÿ’–
  2. The concave region, if CUBIC is not in the Reno-friendly region and cwnd is less than W_max. ๐ŸŒŠ
  3. The convex region, if CUBIC is not in the Reno-friendly region and cwnd is greater than W_max. ๐Ÿš€

To summarize: on each new ACK in congestion avoidance, CUBIC computes both W_cubic(t) and W_est (see Section 4.3), then picks the larger of the two ๐Ÿ‘‘

The next sections break down exactly what CUBIC does in each region ๐Ÿงš


4.3. Reno-Friendly Region ๐Ÿฆ‹

Reno performs really well in certain networks, like ones with short RTTs and small bandwidths (or small BDPs). In those networks, CUBIC stays in the Reno-friendly region so it gets at least the same throughput as Reno ๐Ÿ“

The Reno-friendly region comes from the analysis in [FHP00], which studies an AIMD algorithm with an additive factor of ฮฑ (segments per RTT) and a multiplicative factor of ฮฒ, written AIMD(ฮฑ, ฮฒ). p is the packet loss rate. The average congestion window size of AIMD(ฮฑ, ฮฒ) is figured out with Figure 3:

                                      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                      โ”‚  ฮฑ * (1 + ฮฒ)
                   AVG_AIMD(ฮฑ, ฮฒ) = โ•ฒ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                                     โ•ฒโ”‚2 * (1 - ฮฒ) * p

                                  Figure 3

Using that same analysis, to get an average window size similar to Reno (which uses AIMD(1, 0.5)), ฮฑ has to equal:

                                     1 - ฮฒ
                                 3 * โ”€โ”€โ”€โ”€โ”€
                                     1 + ฮฒ

So CUBIC uses Figure 4 to estimate the window size W_est in the Reno-friendly region, with:

                                       1 - ฮฒ
                                            cubic
                          ฮฑ      = 3 * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                           cubic       1 + ฮฒ
                                            cubic

This gets approximately the same average window size as Reno in many cases ๐Ÿฅฐ The model used to calculate ฮฑ_cubic isn't totally precise, but analysis and simulation in [AIMD-friendliness], plus over a decade of CUBIC running on the public Internet, show it produces acceptable levels of rate fairness between CUBIC and Reno flows. No significant drawbacks of the model have been reported. Still, more detailed analysis of this approach would be super beneficial ๐Ÿ”ฅ When a new ACK arrives in congestion avoidance (where cwnd could be greater than or less than W_max), CUBIC checks whether W_cubic(t) is less than W_est. If it is, CUBIC is in the Reno-friendly region and cwnd SHOULD be set to W_est on each new ACK reception.

W_est gets set equal to cwnd_epoch at the start of the congestion avoidance stage. After that, on every new ACK, W_est is updated using Figure 4. This equation uses segments_acked, and cwnd is measured in segments. An implementation that measures cwnd in bytes should adjust the equation to use the number of acknowledged bytes and the SMSS instead. This also works for connections with delayed ACKs enabled or disabled [RFC5681], since segments_acked depends on which segments a new ACK actually acknowledges ๐Ÿง

                                          segments_acked
                   W    = W    + ฮฑ      * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                    est    est    cubic        cwnd

                                  Figure 4

Once W_est has grown to reach the cwnd from the moment ssthresh was most recently set (that is, W_est >= cwnd_prior), the sender SHOULD set ฮฑ_cubic to 1. That way it matches the same congestion window increment rate as Reno, which uses AIMD(1, 0.5) โœจ

The next two sections assume CUBIC is not in the Reno-friendly region and uses the window increase function from Section 4.2. Even though cwnd grows the same way in both the concave and convex regions, they get their own sections so you can see the difference between them ๐Ÿซง


4.4. Concave Region ๐ŸŒ™

When a new ACK arrives in congestion avoidance, if CUBIC is not in the Reno-friendly region and cwnd is less than W_max, then CUBIC is in the concave region. In this region, cwnd MUST be incremented by

                               target - cwnd
                               โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                                    cwnd

for each received new ACK, where target is calculated as described in Section 4.2. ๐Ÿญ


4.5. Convex Region ๐ŸŒท

When a new ACK arrives in congestion avoidance, if CUBIC is not in the Reno-friendly region and cwnd is larger than or equal to W_max, then CUBIC is in the convex region.

The convex region tells you the network conditions might have changed since the last congestion event, which could mean more bandwidth is free after some flows left ๐Ÿฆ‹ The Internet is super asynchronous, so some amount of perturbation is always possible without causing a major change in available bandwidth.

Unless the cwnd is overridden by the AIMD window increase, CUBIC gets cautious in this region ๐Ÿ™ˆ The convex profile aims to increase the window very slowly at first, when cwnd is around W_max, and then gradually speeds up. This region is also called the "maximum probing phase", since CUBIC is searching for a new W_max ๐Ÿ” In this region, cwnd MUST be incremented by

                               target - cwnd
                               โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                                    cwnd

for each received new ACK, where target is calculated as described in Section 4.2. slay, that's the whole convex region ๐ŸŒˆ๐Ÿ’–

4.6. Multiplicative Decrease ๐Ÿ’ฅ

okay so when a congestion event gets caught by the mechanisms in Section 3.1, CUBIC updates W_max and drops cwnd and ssthresh right away, as described below ๐Ÿ“‰. For packet loss, the sender MUST reduce cwnd and ssthresh immediately once it enters loss recovery, same vibe as [RFC5681] (and [RFC6675]) ๐Ÿซถ. Fun fact: other stuff like Proportional Rate Reduction [RFC6937] can be used to slow the sending rate down more gently during loss recovery ๐ŸŒธ. And the ฮฒ_cubic parameter SHOULD be set to 0.7 ๐Ÿ’œ. That's different from the multiplicative decrease factor used during fast recovery in [RFC5681] (and [RFC6675]), so don't mix them up bestie ๐Ÿ™ˆ.

In Figure 5, flight_size is the outstanding (unacknowledged) data in the network, as defined in [RFC5681] โœจ. Now here's the tea. A rate-limited app with idle periods, or times when it can't send at the full rate cwnd allows, can easily see the amount of data it sends jump around from one RTT to the next ๐Ÿ˜ญ. So when congestion hits, flight_size can be way smaller than cwnd, and the response would then drop cwnd to a much lower value than it needs to ๐Ÿ’€. To dodge that suboptimal performance, you can use the mechanisms in [RFC7661] ๐Ÿฆ‹. [RFC7661] explains how to manage and use cwnd and ssthresh during a rate-limited interval, and how to update them after congestion is detected โœจ. And it's safe even when cwnd is bigger than the receive window, because it validates cwnd based on how much data the network acknowledged in an RTT, which implicitly accounts for the allowed receive window ๐Ÿ‘‘.

Some CUBIC implementations currently use cwnd instead of flight_size when calculating a new ssthresh ๐Ÿ™ƒ. Implementations that use cwnd MUST use other measures to stop cwnd from growing when the bytes in flight are smaller than cwnd ๐Ÿšซ. That also effectively keeps cwnd from growing past the receive window ๐ŸŽ€. These measures matter a LOT because they stop a CUBIC sender from using an arbitrarily high cwnd value when it calculates new ssthresh and cwnd values after congestion is detected ๐Ÿ˜ค. Still, this might not be as robust as the mechanisms in [RFC7661] ๐Ÿฅบ.

A QUIC sender that uses a cwnd value to calculate new cwnd and ssthresh values after detecting a congestion event is REQUIRED to apply similar mechanisms [RFC9002] ๐Ÿ”ฅ.

    ssthresh =  flight_size * ฮฒ      new  ssthresh
                               cubic
    cwnd      = cwnd                 save  cwnd
        prior
                โŽงmax(ssthresh, 2)    reduction on loss, cwnd >= 2 SMSS
    cwnd =      โŽจmax(ssthresh, 1)    reduction on ECE, cwnd >= 1 SMSS
                โŽฉ
    ssthresh =  max(ssthresh, 2)     ssthresh >= 2 SMSS

                                  Figure 5

A side effect of setting ฮฒ_cubic to something bigger than 0.5 is that packet loss can happen across more than one RTT in certain cases ๐Ÿซ . But it can work efficiently in other cases, like when HyStart++ [RFC9406] is used with CUBIC or when the sending rate is limited by the application ๐Ÿ’…. A more adaptive setting of ฮฒ_cubic could help keep packet loss to a single round, but validating those algorithms would take detailed analyses and large-scale evaluations ๐Ÿงช.

Now, CUBIC MUST keep reducing cwnd in response to congestion events signaled by ECN-Echo ACKs until it hits 1 SMSS ๐ŸŒˆ. If those ECN-Echo congestion signals keep coming, a sender with a cwnd of 1 SMSS MUST reduce its sending rate even further โญ. You can do that with a retransmission timer that uses exponential backoff, as described in [RFC3168] ๐Ÿ’–.

4.7. Fast Convergence ๐Ÿงš

To speed up convergence, CUBIC uses a heuristic ๐Ÿ“. When a new flow joins the network, the existing flows need to give up some of their bandwidth so the new flow has room to grow, if the existing flows have been hogging all the bandwidth ๐Ÿ‘€. To speed up that bandwidth release, the following fast convergence mechanism SHOULD be implemented ๐Ÿ’œ.

With fast convergence, when a congestion event happens, W_max gets updated like this, before the window reduction from Section 4.6 ๐ŸŽ€:

       โŽง       1 + ฮฒ
       โŽช            cubic
       โŽชcwnd * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ if  cwnd < W     and fast convergence enabled,
W    = โŽจ           2                  max
 max   โŽช                  further reduce  W
       โŽช                                   max
       โŽฉcwnd             otherwise, remember cwnd before reduction

During a congestion event, if the current cwnd is less than W_max, that means the saturation point this flow experiences is shrinking because the available bandwidth changed ๐Ÿฆ‹. The flow can then release even more bandwidth by reducing W_max further ๐Ÿซถ. That effectively stretches out how long this flow takes to grow its congestion window, because the lower W_max makes the flow plateau earlier โณ. That gives the new flow more time to catch up to its congestion window size ๐ŸŒธ.

Fast convergence is designed for network environments with multiple CUBIC flows โœจ. In an environment with only a single CUBIC flow and no other traffic, fast convergence SHOULD be disabled ๐Ÿ™…โ€โ™€๏ธ.

4.8. Timeout โฐ

When a timeout happens, CUBIC follows Reno to reduce cwnd [RFC5681], but it sets ssthresh using ฮฒ_cubic (same as in Section 4.6) in a way that's different from Reno TCP [RFC5681] ๐Ÿ’….

During the first congestion avoidance stage after a timeout, CUBIC grows its congestion window using Figure 1 ๐Ÿฆ‹. Here t is the elapsed time since the start of the current congestion avoidance stage, K is set to 0, and W_max is set to the congestion window size at the start of that stage ๐ŸŒท. For the Reno-friendly region, W_est SHOULD be set to the congestion window size at the start of the current congestion avoidance stage ๐Ÿซถ.

4.9. Spurious Congestion Events ๐Ÿ‘ป

Sometimes CUBIC shrinks its congestion window because it thinks there was packet loss, through duplicate ACKs or timeouts ๐Ÿ˜ฌ. But the "missing" ACK could arrive after the window reduction and the matching packet retransmission ๐Ÿคฏ. Packet reordering could be the reason, for example ๐Ÿ”€. If there's a LOT of reordering, you get multiple congestion window reduction events, where spurious losses get misread as congestion signals, and CUBIC's performance tanks big time ๐Ÿ˜ญ.

For TCP, there are two kinds of spurious events: spurious timeouts and spurious fast retransmits ๐Ÿ’–. With QUIC there are no spurious timeouts, because loss only gets detected after an ACK comes in โœจ.

4.9.1. Spurious Timeouts โฑ๏ธ

An implementation MAY detect spurious timeouts using the mechanisms in Forward RTO-Recovery [RFC5682] ๐Ÿ”. Experimental alternatives include the Eifel detection algorithm [RFC3522] ๐Ÿงช. When a spurious timeout is detected, a TCP implementation MAY follow the response algorithm in [RFC4015] to restore the congestion control state and adjust the retransmission timer, so it avoids more spurious timeouts ๐Ÿฉน.

4.9.2. Spurious Fast Retransmits ๐Ÿƒโ€โ™€๏ธ

When an ACK comes in, a TCP implementation MAY detect spurious fast retransmits using either TCP Timestamps or D-SACK [RFC2883] ๐Ÿ•ต๏ธโ€โ™€๏ธ. Like we said above, experimental alternatives include the Eifel detection algorithm [RFC3522], which uses TCP Timestamps, and DSACK-based detection [RFC3708], which uses DSACK information ๐Ÿงช. A QUIC implementation can easily spot a spurious fast retransmit if a QUIC packet gets acknowledged after it was marked as lost and its original data was already retransmitted in a new QUIC packet ๐Ÿ’œ.

This section specifies a simple response algorithm for when acknowledgments detect a spurious fast retransmit ๐ŸŽฏ. Implementations would need to carefully evaluate how using this algorithm affects different environments, especially ones with a sudden change in available capacity (for example, from variable radio capacity, a routing change, or a mobility event) ๐ŸŒ.

When acknowledgments detect packet loss, a CUBIC implementation MAY save the current value of these variables before the congestion window is reduced ๐Ÿ’พ:

                        undo_cwnd =      cwnd
                        undo_cwnd      = cwnd
                                 prior       prior
                        undo_ssthresh =  ssthresh
                        undo_W    =      W
                              max         max
                        undo_K =         K
                        undo_t      =    t
                              epoch       epoch
                        undo_W    =      W
                              est         est

Once the earlier packet loss is confirmed as spurious, CUBIC MAY restore the original values of those variables as shown below, if the current cwnd is lower than cwnd_prior ๐Ÿ”„. Restoring the original values means CUBIC's performance looks similar to what it would be without the spurious losses ๐Ÿฅน.

              cwnd =      undo_cwnd      โŽซ
              cwnd      = undo_cwnd      โŽฎ
                  prior            prior โŽฎ
              ssthresh =  undo_ssthresh  โŽฎ
              W    =      undo_W         โŽฎ
               max              max      โŽฌif cwnd < cwnd
              K =         undo_K         โŽฎ              prior
              t      =    undo_t         โŽฎ
               epoch            epoch    โŽฎ
              W    =      undo_W         โŽฎ
               est              est      โŽญ

In rare cases, when the detection happens long after a spurious fast retransmit and the current cwnd is already higher than cwnd_prior, CUBIC SHOULD keep using the current and most recent values of these variables ๐Ÿซง.

4.10. Slow Start ๐Ÿฃ

When cwnd is no more than ssthresh, CUBIC MUST employ a slow start algorithm ๐Ÿš€. In general, CUBIC SHOULD use the HyStart++ slow start algorithm [RFC9406], or it MAY use the Reno TCP slow start algorithm [RFC5681] in the rare cases where HyStart++ isn't suitable ๐Ÿ™Œ. Experimental alternatives include hybrid slow start [HR11], a predecessor to HyStart++ that some CUBIC implementations have used as the default for the last decade, and limited slow start [RFC3742] ๐Ÿ•ฐ๏ธ. Whichever startup algorithm you use, work might be needed to make sure the end of slow start and the first multiplicative decrease of congestion avoidance work well together ๐Ÿค.

When CUBIC uses HyStart++ [RFC9406], it may exit the first slow start without any packet loss, so W_max is undefined ๐Ÿคทโ€โ™€๏ธ. In this special case, CUBIC sets cwnd_prior = cwnd and switches to congestion avoidance โœจ. Then it grows its congestion window using Figure 1, where t is the elapsed time since the start of the current congestion avoidance stage, K is set to 0, and W_max is set to the congestion window size at the start of that stage ๐Ÿ’–.

5. Discussion โœจ

Okay bestie, this part is all about the safety side of CUBIC ๐Ÿ›ก๏ธ. We're following the guidelines in [RFC5033] so it plays nice with everyone else on the internet ๐Ÿซถ

Here's the fun bit: with a deterministic loss model where the number of packets between two successive packet losses is always 1/p, CUBIC always operates with the concave window profile ๐ŸŒธ That makes the performance analysis SO much easier to do. The average window size of CUBIC (see Appendix B) comes out of this formula:

                           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   4 โ”Œโ”€โ”€โ”€โ”€โ”
                           โ”‚C * (3 + ฮฒ     )    โ•ฒ โ”‚   3
                        4  โ”‚          cubic      โ•ฒโ”‚RTT
           AVG_W      = โ•ฒ  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                cubic    โ•ฒ โ”‚4 * (1 - ฮฒ     )     4 โ”Œโ”€โ”€โ”
                          โ•ฒโ”‚          cubic      โ•ฒ โ”‚ 3
                                                  โ•ฒโ”‚p

                              Figure 6

With ฮฒ__cubic_ set to 0.7, the above formula reduces to:

                                           4 โ”Œโ”€โ”€โ”€โ”€โ”
                               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ•ฒ โ”‚   3
                             4 โ”‚C * 3.7     โ•ฒโ”‚RTT
                AVG_W      = โ•ฒ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€  * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                     cubic    โ•ฒโ”‚  1.2       4 โ”Œโ”€โ”€โ”
                                            โ•ฒ โ”‚ 3
                                             โ•ฒโ”‚p

                              Figure 7

Next up, the following subsection figures out the value of C using Figure 7 ๐Ÿงฎ

5.1. Fairness to Reno

In environments where Reno can make reasonable use of the available bandwidth, CUBIC doesn't really change that vibe ๐Ÿ’•

Reno performs well in these two types of networks:

  1. networks with a small bandwidth-delay product (BDP)
  2. networks with short RTTs, but not necessarily a small BDP

CUBIC is designed to act super similar to Reno in both of those situations ๐ŸŽ€ The two tables below show the average window sizes of Reno TCP, HSTCP, and CUBIC TCP. The Reno TCP and HSTCP numbers come from [RFC3649]. The CUBIC numbers are calculated using Figure 7 and the CUBIC Reno-friendly region, for three different values of C.

+=============+=======+========+================+=========+========+
| Loss Rate P |  Reno |  HSTCP | CUBIC (C=0.04) |   CUBIC |  CUBIC |
|             |       |        |                | (C=0.4) |  (C=4) |
+=============+=======+========+================+=========+========+
|     1.0e-02 |    12 |     12 |             12 |      12 |     12 |
+-------------+-------+--------+----------------+---------+--------+
|     1.0e-03 |    38 |     38 |             38 |      38 |     59 |
+-------------+-------+--------+----------------+---------+--------+
|     1.0e-04 |   120 |    263 |            120 |     187 |    333 |
+-------------+-------+--------+----------------+---------+--------+
|     1.0e-05 |   379 |   1795 |            593 |    1054 |   1874 |
+-------------+-------+--------+----------------+---------+--------+
|     1.0e-06 |  1200 |  12280 |           3332 |    5926 |  10538 |
+-------------+-------+--------+----------------+---------+--------+
|     1.0e-07 |  3795 |  83981 |          18740 |   33325 |  59261 |
+-------------+-------+--------+----------------+---------+--------+
|     1.0e-08 | 12000 | 574356 |         105383 |  187400 | 333250 |
+-------------+-------+--------+----------------+---------+--------+

     Table 1: Reno TCP, HSTCP, and CUBIC with RTT = 0.1 Seconds

Table 1 shows the response function of Reno TCP, HSTCP, and CUBIC in networks with RTT = 0.1 seconds ๐Ÿ“Š The average window size is in SMSS-sized segments.

 +=============+=======+========+================+=========+=======+
 | Loss Rate P |  Reno |  HSTCP | CUBIC (C=0.04) |   CUBIC | CUBIC |
 |             |       |        |                | (C=0.4) | (C=4) |
 +=============+=======+========+================+=========+=======+
 |     1.0e-02 |    12 |     12 |             12 |      12 |    12 |
 +-------------+-------+--------+----------------+---------+-------+
 |     1.0e-03 |    38 |     38 |             38 |      38 |    38 |
 +-------------+-------+--------+----------------+---------+-------+
 |     1.0e-04 |   120 |    263 |            120 |     120 |   120 |
 +-------------+-------+--------+----------------+---------+-------+
 |     1.0e-05 |   379 |   1795 |            379 |     379 |   379 |
 +-------------+-------+--------+----------------+---------+-------+
 |     1.0e-06 |  1200 |  12280 |           1200 |    1200 |  1874 |
 +-------------+-------+--------+----------------+---------+-------+
 |     1.0e-07 |  3795 |  83981 |           3795 |    5926 | 10538 |
 +-------------+-------+--------+----------------+---------+-------+
 |     1.0e-08 | 12000 | 574356 |          18740 |   33325 | 59261 |
 +-------------+-------+--------+----------------+---------+-------+

     Table 2: Reno TCP, HSTCP, and CUBIC with RTT = 0.01 Seconds

Table 2 shows the response function of Reno TCP, HSTCP, and CUBIC in networks with RTT = 0.01 seconds ๐Ÿš€ Again, the average window size is in SMSS-sized segments.

Both tables show that CUBIC with any of these three C values is more friendly to Reno TCP than HSTCP is, especially in networks with a short RTT, where Reno TCP already does pretty well ๐Ÿฅน For example, in a network with RTT = 0.01 seconds and p=10^-6, Reno TCP has an average window of 1200 packets. If the packet size is 1500 bytes, then Reno TCP can achieve an average rate of 1.44 Gbps ๐Ÿคฏ In this case, CUBIC with C=0.04 or C=0.4 achieves exactly the same rate as Reno TCP, whereas HSTCP is about ten times more aggressive than Reno TCP. Not it, HSTCP ๐Ÿ’€

C is basically the aggressiveness dial for CUBIC when it's competing with other congestion control algorithms for bandwidth ๐ŸŽš๏ธ CUBIC is more friendly to Reno TCP if the value of C is lower. However, it is NOT RECOMMENDED to set C to a very low value like 0.04, because CUBIC with a low C can't efficiently use the bandwidth in fast and long-distance networks ๐Ÿ˜ฉ Based on these observations and a ton of real deployment experience, C=0.4 seems to give a good balance between Reno-friendliness and how aggressively the window grows ๐Ÿ’– So C SHOULD be set to 0.4. With C set to 0.4, Figure 7 gets reduced to:

                                         4 โ”Œโ”€โ”€โ”€โ”€โ”
                                         โ•ฒ โ”‚   3
                                          โ•ฒโ”‚RTT
                    AVG_W      = 1.054 * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                         cubic            4 โ”Œโ”€โ”€โ”
                                          โ•ฒ โ”‚ 3
                                           โ•ฒโ”‚p

                              Figure 8

Figure 8 is then used in the next subsection to show how scalable CUBIC is ๐Ÿ“ˆ

5.2. Using Spare Capacity

CUBIC uses a more aggressive window increase function than Reno for fast and long-distance networks ๐ŸŽ๏ธโœจ

Table 3 shows that to hit a 10 Gbps rate, Reno TCP needs a packet loss rate of 2.0e-10, while CUBIC TCP only needs a packet loss rate of 2.9e-8. Iconic ๐Ÿ‘‘

   +===================+===========+=========+=========+=========+
   | Throughput (Mbps) | Average W |  Reno P | HSTCP P | CUBIC P |
   +===================+===========+=========+=========+=========+
   |                 1 |       8.3 |  2.0e-2 |  2.0e-2 |  2.0e-2 |
   +-------------------+-----------+---------+---------+---------+
   |                10 |      83.3 |  2.0e-4 |  3.9e-4 |  2.9e-4 |
   +-------------------+-----------+---------+---------+---------+
   |               100 |     833.3 |  2.0e-6 |  2.5e-5 |  1.4e-5 |
   +-------------------+-----------+---------+---------+---------+
   |              1000 |    8333.3 |  2.0e-8 |  1.5e-6 |  6.3e-7 |
   +-------------------+-----------+---------+---------+---------+
   |             10000 |   83333.3 | 2.0e-10 |  1.0e-7 |  2.9e-8 |
   +-------------------+-----------+---------+---------+---------+

     Table 3: Required Packet Loss Rate for Reno TCP, HSTCP, and
                CUBIC to Achieve a Certain Throughput

Table 3 describes the required packet loss rate for Reno TCP, HSTCP, and CUBIC to hit a certain throughput, with 1500-byte packets and an RTT of 0.1 seconds ๐Ÿ“

The test results in [HLRX07] show that, in typical cases with some background traffic, CUBIC uses the spare bandwidth that Reno TCP flows leave unused on the same bottleneck link, without taking away much bandwidth from those existing flows ๐Ÿฆ‹

5.3. Difficult Environments

CUBIC is designed to fix the poor performance of Reno in fast and long-distance networks ๐Ÿ› ๏ธ๐Ÿ’…

5.4. Investigating a Range of Environments

CUBIC has been studied SO extensively, using simulations, testbed emulations, Internet experiments, and Internet measurements, across a wide range of network environments [HLRX07] [H16] [CEHRX09] [HR11] [BSCLU13] [LBEWK16] ๐Ÿค“ They've convincingly shown that CUBIC gives real benefits over classic Reno congestion control [RFC5681]. Main character energy ๐ŸŒŸ

Same as Reno, CUBIC is a loss-based congestion control algorithm. Because CUBIC is designed to be more aggressive than Reno in fast and long-distance networks (thanks to a faster window increase function and a bigger multiplicative decrease factor), it can fill large drop-tail buffers more quickly than Reno does, which raises the risk of a standing queue [RFC8511] ๐Ÿ˜ฌ In that case, proper queue sizing and management [RFC7567] could help reduce that risk to some extent and cut down the packet queuing delay ๐Ÿงน Also, in large-BDP networks after a congestion event, CUBIC recovers quickly to the highest link utilization point, thanks to its cubic window increase function ๐Ÿš„ This means link utilization is less sensitive to an active queue management (AQM) target that is lower than the amplitude of the whole sawtooth.

Similar to Reno, CUBIC's performance as a loss-based algorithm suffers in networks where packet loss isn't a good indication of bandwidth utilization, such as wireless or mobile networks [LIU16] ๐Ÿ“ถ๐Ÿ’”

5.5. Protection against Congestion Collapse

When it comes to the potential for causing congestion collapse, CUBIC acts like Reno, since CUBIC only modifies the window adjustment algorithm of Reno ๐Ÿ™Œ So it doesn't change the ACK clocking and timeout behaviors of Reno either.

CUBIC also satisfies the "full backoff" requirement described in [RFC5033] ๐Ÿ”™ After it drops the sending rate to one packet per RTT in response to congestion events detected by ECN-Echo ACKs, CUBIC then exponentially increases the transmission timer for each packet retransmission while congestion persists โณ

5.6. Fairness within the Alternative Congestion Control Algorithm

CUBIC makes sure competing CUBIC flows with the same RTT on the same bottleneck links converge to an equal throughput ๐Ÿค When competing flows have different RTT values, their throughput ratio is linearly proportional to the inverse of their RTT ratios. This is true, and it's independent of the level of statistical multiplexing on the link. The convergence time depends on the network environment (e.g., bandwidth, RTT) and the level of statistical multiplexing, as mentioned in Section 3.4 ๐Ÿฆ„โœจ

5.7. Performance with Misbehaving Nodes and Outside Attackers ๐Ÿ•ต๏ธ

okay so CUBIC doesn't bring in any new entities or signals ๐Ÿ™…โ€โ™€๏ธ, which means its vulnerability to misbehaving nodes or attackers is exactly the same as Reno's. no new door, no new drama ๐Ÿ’…

5.8. Behavior for Application-Limited Flows ๐Ÿข

a flow is application limited if it's currently sending less than what the congestion window allows ๐Ÿซ . this can happen when the sender's app is the thing holding it back, or when the receiver's app is (through the receiver's advertised window), so it ends up sending less data than the sender's congestion window would permit.

CUBIC does not increase its congestion window if a flow is application limited ๐Ÿ›‘. per Section 4.2, it is required that t in Figure 1 not include application-limited periods, like idle periods. otherwise, W_cubic(t) could be super high after restarting from those periods ๐Ÿ˜ญ

5.9. Responses to Sudden or Transient Events โšก

if there's a sudden increase in capacity, like variable radio capacity, a routing change, or a mobility event, CUBIC is designed to grab the newly available capacity faster than Reno โœจ

on the flip side, if there's a sudden decrease in capacity, CUBIC reduces more slowly than Reno ๐ŸŒ. this stays true whether or not CUBIC is in Reno-friendly mode, and whether or not fast convergence is enabled. no cap ๐Ÿงข

5.10. Incremental Deployment ๐Ÿš€

CUBIC only needs changes to congestion control at the sender, and receivers don't need any changes at all ๐Ÿซถ. so a CUBIC sender works correctly with Reno receivers. plus, CUBIC doesn't need any changes to routers and doesn't need any help from routers either. easy peasy ๐Ÿ“


6. Security Considerations ๐Ÿ”

okay bestie, this one is serious, so read it carefully ๐Ÿ˜ค

CUBIC makes no changes to the underlying security of a transport protocol, and it inherits the general security concerns described in [RFC5681]. specifically, changing the window computation on the sender may allow an attacker, through dropping or injecting ACKs (as described in [RFC5681]), to either force the CUBIC implementation to reduce its bandwidth or convince it that there is no congestion when congestion does exist. it could also use the CUBIC implementation as an attack vector against other hosts ๐Ÿ’€. these attacks are not new to CUBIC. they are inherently part of any transport protocol like TCP ๐Ÿฅฒ.

7. IANA Considerations ๐Ÿ“‹

this document does not require any IANA actions ๐ŸŒธ.

8. References ๐Ÿ“š

8.1. Normative References

8.2. Informative References โœจ

okay bestie, these are the extra-credit reads ๐Ÿ“š๐Ÿ’– the whole reading list is right here so you can go deeper whenever you're obsessed enough ๐Ÿค“

[AIMD-friendliness] Briscoe, B. and O. Albisser, "Friendliness between AIMD Algorithms", DOI 10.48550/arXiv.2305.10581, May 2023, https://arxiv.org/abs/2305.10581.

[BSCLU13] Belhareth, S., Sassatelli, L., Collange, D., Lopez-Pacheco, D., and G. Urvoy-Keller, "Understanding TCP cubic performance in the cloud: A mean-field approach", 2013 IEEE 2nd International Conference on Cloud Networking (CloudNet), DOI 10.1109/cloudnet.2013.6710576, November 2013, https://doi.org/10.1109/cloudnet.2013.6710576.

[CEHRX09] Cai, H., Eun, D., Ha, S., Rhee, I., and L. Xu, "Stochastic convex ordering for multiplicative decrease internet congestion control", Computer Networks, vol. 53, no. 3, pp. 365-381, DOI 10.1016/j.comnet.2008.10.012, February 2009, https://doi.org/10.1016/j.comnet.2008.10.012.

[FHP00] Floyd, S., Handley, M., and J. Padhye, "A Comparison of Equation-Based and AIMD Congestion Control", May 2000, https://www.icir.org/tfrc/aimd.pdf.

[GV02] Gorinsky, S. and H. Vin, "Extended Analysis of Binary Adjustment Algorithms", Technical Report TR2002-39, Department of Computer Sciences, The University of Texas at Austin, August 2002, https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=1828bdcef118b02d3996b8e00b8aaa92b50abb0f.

[H16] Ha, S., "Deployment, Testbed, and Simulation Results for CUBIC", Wayback Machine archive, 3 November 2016, https://web.archive.org/web/20161118125842/http://netsrv.csc.ncsu.edu/wiki/index.php/TCP_Testing.

[HLRX07] Ha, S., Le, L., Rhee, I., and L. Xu, "Impact of background traffic on performance of high-speed TCP variant protocols", Computer Networks, vol. 51, no. 7, pp. 1748-1762, DOI 10.1016/j.comnet.2006.11.005, May 2007, https://doi.org/10.1016/j.comnet.2006.11.005.

[HR11] Ha, S. and I. Rhee, "Taming the elephants: New TCP slow start", Computer Networks, vol. 55, no. 9, pp. 2092-2110, DOI 10.1016/j.comnet.2011.01.014, June 2011, https://doi.org/10.1016/j.comnet.2011.01.014.

[HRX08] Ha, S., Rhee, I., and L. Xu, "CUBIC: a new TCP-friendly high-speed TCP variant", ACM SIGOPS Operating Systems Review, vol. 42, no. 5, pp. 64-74, DOI 10.1145/1400097.1400105, July 2008, https://doi.org/10.1145/1400097.1400105.

[K03] Kelly, T., "Scalable TCP: improving performance in highspeed wide area networks", ACM SIGCOMM Computer Communication Review, vol. 33, no. 2, pp. 83-91, DOI 10.1145/956981.956989, April 2003, https://doi.org/10.1145/956981.956989.

[LBEWK16] Lukaseder, T., Bradatsch, L., Erb, B., Van Der Heijden, R., and F. Kargl, "A Comparison of TCP Congestion Control Algorithms in 10G Networks", 2016 IEEE 41st Conference on Local Computer Networks (LCN), DOI 10.1109/lcn.2016.121, November 2016, https://doi.org/10.1109/lcn.2016.121.

[LIU16] Liu, K. and J. Lee, "On Improving TCP Performance over Mobile Data Networks", IEEE Transactions on Mobile Computing, vol. 15, no. 10, pp. 2522-2536, DOI 10.1109/tmc.2015.2500227, October 2016, https://doi.org/10.1109/tmc.2015.2500227.

[RFC3522] Ludwig, R. and M. Meyer, "The Eifel Detection Algorithm for TCP", RFC 3522, DOI 10.17487/RFC3522, April 2003, https://www.rfc-editor.org/info/rfc3522.

[RFC3649] Floyd, S., "HighSpeed TCP for Large Congestion Windows", RFC 3649, DOI 10.17487/RFC3649, December 2003, https://www.rfc-editor.org/info/rfc3649.

[RFC3708] Blanton, E. and M. Allman, "Using TCP Duplicate Selective Acknowledgement (DSACKs) and Stream Control Transmission Protocol (SCTP) Duplicate Transmission Sequence Numbers (TSNs) to Detect Spurious Retransmissions", RFC 3708, DOI 10.17487/RFC3708, February 2004, https://www.rfc-editor.org/info/rfc3708.

[RFC3742] Floyd, S., "Limited Slow-Start for TCP with Large Congestion Windows", RFC 3742, DOI 10.17487/RFC3742, March 2004, https://www.rfc-editor.org/info/rfc3742.

[RFC6937] Mathis, M., Dukkipati, N., and Y. Cheng, "Proportional Rate Reduction for TCP", RFC 6937, DOI 10.17487/RFC6937, May 2013, https://www.rfc-editor.org/info/rfc6937.

[RFC7661] Fairhurst, G., Sathiaseelan, A., and R. Secchi, "Updating TCP to Support Rate-Limited Traffic", RFC 7661, DOI 10.17487/RFC7661, October 2015, https://www.rfc-editor.org/info/rfc7661.

[RFC8312] Rhee, I., Xu, L., Ha, S., Zimmermann, A., Eggert, L., and R. Scheffenegger, "CUBIC for Fast Long-Distance Networks", RFC 8312, DOI 10.17487/RFC8312, February 2018, https://www.rfc-editor.org/info/rfc8312.

[RFC8511] Khademi, N., Welzl, M., Armitage, G., and G. Fairhurst, "TCP Alternative Backoff with ECN (ABE)", RFC 8511, DOI 10.17487/RFC8511, December 2018, https://www.rfc-editor.org/info/rfc8511.

[RFC9000] Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, May 2021, https://www.rfc-editor.org/info/rfc9000.

[RFC9260] Stewart, R., Tรผxen, M., and K. Nielsen, "Stream Control Transmission Protocol", RFC 9260, DOI 10.17487/RFC9260, June 2022, https://www.rfc-editor.org/info/rfc9260.

[SXEZ19] Sun, W., Xu, L., Elbaum, S., and D. Zhao, "Model-Agnostic and Efficient Exploration of Numerical Congestion Control State Space of Real-World TCP Implementations", IEEE/ACM Transactions on Networking, vol. 29, no. 5, pp. 1990-2004, DOI 10.1109/tnet.2021.3078161, October 2021, https://doi.org/10.1109/tnet.2021.3078161.

[XHR04] Xu, L., Harfoush, K., and I. Rhee, "Binary increase congestion control (BIC) for fast long-distance networks", IEEE INFOCOM 2004, DOI 10.1109/infcom.2004.1354672, March 2004, https://doi.org/10.1109/infcom.2004.1354672.


Appendix A. Evolution of CUBIC since the Original Paper ๐Ÿฆ‹

CUBIC has had a few glow-ups since the initial release [HRX08] of its algorithm and implementation ๐Ÿ’… this appendix spills the tea on the differences between the original paper and [RFC8312] ๐Ÿซถ

  • The original paper [HRX08] includes the pseudocode of CUBIC implementation using Linux's pluggable congestion control framework, which excludes system-specific optimizations. The simplified pseudocode might be a good starting point for learning about CUBIC. ๐ŸŒธ
  • [HRX08] also includes experimental results showing its performance and fairness. โœจ
  • The definition of the ฮฒ__cubic_ constant was changed in [RFC8312]. For example, ฮฒ__cubic_ in the original paper was referred to as the window decrease constant, while [RFC8312] changed it to "CUBIC multiplicative decrease factor". With this change, the current congestion window size after a congestion event as listed in [RFC8312] was ฮฒ__cubic_ * _W_max_, while it was (1-ฮฒ__cubic_) * _W_max_ in the original paper. this is the kind of detail that makes or breaks an implementation ๐Ÿ‘‘
  • Its pseudocode used _W_(last_max)_, while [RFC8312] used _W_max_. ๐Ÿงš
  • Its AIMD-friendly window was _W_tcp_, while [RFC8312] used _W_est_. ๐Ÿ’œ

Appendix B. Proof of the Average CUBIC Window Size ๐Ÿงฎโœจ

okay so this appendix is where we actually prove the average CUBIC window size, which is called _AVG_W_cubic_ and shows up in Figure 6. ๐Ÿ’… it's giving math, but make it cute bestie ๐ŸŽ€

we find _AVG_W_cubic_ under a deterministic loss model, where the number of packets between two successive packet losses is 1/_p_. with this model, CUBIC always operates with the concave window profile, and the time period between two successive packet losses is _K_. ๐Ÿฆ‹

the average window size _AVG_W_cubic_ is defined like this: the numerator 1/_p_ is the total number of packets between two successive packet losses, and the denominator _K_/_RTT_ is the total number of RTTs between two successive packet losses. ๐ŸŒธ

                                        1
                                        โ”€
                                        p
                          AVG_W      = โ”€โ”€โ”€
                               cubic    K
                                       โ”€โ”€โ”€
                                       RTT

Figure 9 โœจ

below, we find _K_ as a function of the CUBIC parameters ฮฒ_cubic and _C_, and the network parameters _p_ and _RTT_. ๐Ÿงš according to the definition of _K_ in Figure 2, we have:

                           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                        3  โ”‚W    - W    * ฮฒ
                        โ•ฒ  โ”‚ max    max    cubic
                    K =  โ•ฒ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
                          โ•ฒโ”‚         C

Figure 10 ๐Ÿ’–

the total number of packets between two successive packet losses can also be obtained using the window increase function in Figure 1. specifically, the window size in the first RTT (that's _n_=1, or equivalently _t_=0) is _C_(-_K_)^3+_W_max_, and the window size in the last RTT (that's _n_=_K_/_RTT_, or equivalently _t_=_K_-_RTT_) is _C_(-_RTT_)^3+_W_max_. ๐Ÿ“

                    K
                   โ”€โ”€โ”€
                   RTT
                   โŽฏโŽฏ
               1   โ•ฒ  โŽ›                3       โŽž
               โ”€ = โ•ฑ  โŽœC((n-1) * RTT-K)  + W   โŽŸ
               p   โŽบโŽบ โŽ                     maxโŽ 
                   n=1
                    K
                   โ”€โ”€โ”€
                   RTT
                   โŽฏโŽฏ
                   โ•ฒ  โŽ›       3    3       โŽž
                 = โ•ฑ  โŽœC * RTT (-n)  + W   โŽŸ
                   โŽบโŽบ โŽ                 maxโŽ 
                   n=1
                                K
                               โ”€โ”€โ”€
                               RTT
                               โŽฏโŽฏ
                           3   โ•ฒ    3           K
                 = -C * RTT  * โ•ฑ   n  + W    * โ”€โ”€โ”€
                               โŽบโŽบ        max   RTT
                               n=1
                                       4
                           3   1  โŽ› K โŽž            K
                 โ‰ˆ -C * RTT  * โ”€ *โŽœโ”€โ”€โ”€โŽŸ  + W    * โ”€โ”€โ”€
                               4  โŽRTTโŽ      max   RTT
                              4
                        1    K            K
                 = -C * โ”€ * โ”€โ”€โ”€ + W    * โ”€โ”€โ”€
                        4   RTT    max   RTT

Figure 11 ๐Ÿ™ˆ

okay now the big payoff ๐Ÿ‘‘ after solving the equations in Figures 10 and 11 for _K_ and _W_max_, we get:

                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                          โ”‚ 4 * โŽ›1-ฮฒ     โŽž
                       4  โ”‚     โŽ   cubicโŽ     RTT
                   K = โ•ฒ  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ * โ”€โ”€โ”€
                        โ•ฒ โ”‚C * โŽ›3 + ฮฒ     โŽž    p
                         โ•ฒโ”‚    โŽ     cubicโŽ 

Figure 12 ๐ŸŒˆ

the average CUBIC window size _AVG_W_cubic_ can be obtained by substituting _K_ from Figure 12 into Figure 9. โญ

                         1       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”€       โ”‚C * โŽ›3 + ฮฒ     โŽž      3
                         p    4  โ”‚    โŽ     cubicโŽ    RTT
           AVG_W      = โ”€โ”€โ”€ = โ•ฒ  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ * โ”€โ”€โ”€โ”€
                cubic    K     โ•ฒ โ”‚ 4 * โŽ›1-ฮฒ     โŽž      3
                        โ”€โ”€โ”€     โ•ฒโ”‚     โŽ   cubicโŽ      p
                        RTT

Acknowledgments ๐Ÿซถ

Richard Scheffenegger and Alexander Zimmermann originally coauthored [RFC8312].

these individuals suggested improvements to this document: ๐Ÿ’œ

  • Bob Briscoe
  • Christian Huitema
  • Gorry Fairhurst
  • Jonathan Morton
  • Juhamatti Kuusisaari
  • Junho Choi
  • Markku Kojo
  • Martin Duke
  • Martin Thomson
  • Matt Mathis
  • Matt Olson
  • Michael Welzl
  • Mirja Kรผhlewind
  • Mohit P. Tahiliani
  • Neal Cardwell
  • Praveen Balasubramanian
  • Randall Stewart
  • Richard Scheffenegger
  • Rod Grimes
  • Spencer Dawkins
  • Tom Henderson
  • Tom Petch
  • Wesley Rosenblum
  • Yoav Nir
  • Yoshifumi Nishida
  • Yuchung Cheng

Authors' Addresses ๐Ÿ“ฎ

Lisong Xu University of Nebraska-Lincoln Department of Computer Science and Engineering Lincoln, NE 68588-0115 United States of America Email: xu@unl.edu URI: https://cse.unl.edu/~xu/

Sangtae Ha University of Colorado at Boulder Department of Computer Science Boulder, CO 80309-0430 United States of America Email: sangtae.ha@colorado.edu URI: https://netstech.org/sangtaeha/

Injong Rhee Bowery Farming 151 W 26th Street, 12th Floor New York, NY 10001 United States of America Email: injongrhee@gmail.com

Vidhi Goel Apple Inc. One Apple Park Way Cupertino, CA 95014 United States of America Email: vidhi_goel@apple.com

Lars Eggert (editor) NetApp Stenbergintie 12 B FI-02700 Kauniainen Finland Email: lars@eggert.org URI: https://eggert.org/

๐Ÿ“ฆ where this page comes from