Networking · Congestion Control
Model-Based Congestion Control: Delivery Rate, Minimum RTT, and Pacing
Estimating the bottleneck rate and the propagation delay separately lets a sender set its window from the product of the two instead of probing for loss. The estimators are the whole design.
Loss-based control treats a dropped packet as the definition of congestion and derives everything else from the loss rate. The derivation is a proxy: the sender wants to know how many bytes per second the bottleneck can carry, and it estimates that number from how often the bottleneck’s buffer overflows. The estimate is indirect, it is noisy, and its accuracy depends on the buffer’s depth, which the sender cannot see.
A model-based sender skips the proxy. It measures two quantities directly — the rate at which the bottleneck delivers data, and the round-trip time with no queue — and sets its window to their product. The window that results is the amount of data the path can hold in flight, which is the quantity that determines throughput. No loss is needed to find it, and no sawtooth is needed to maintain it.
The difficulty moves entirely into the estimators. Both quantities must be extracted from the same acknowledgement stream that loss-based control uses, and both are contaminated by the queue that the sender itself creates.
Two measurements, not one
The first quantity is the bottleneck bandwidth. It cannot be measured by timing a single packet, because a single packet’s arrival says nothing about the rate at the bottleneck; it can only be measured by observing how fast a delivery of data completes. The standard construction is to record, for each acknowledgement, the amount of data acknowledged and the time since the previous such record, and to take the ratio as an instantaneous delivery rate. The maximum of that ratio over a window is the estimate of the bottleneck rate, because a delivery that was compressed by a queue draining reveals the bottleneck’s true service rate, while deliveries spread out by a queue filling reveal something slower.
The second quantity is the round-trip propagation delay. Its estimate is the minimum RTT observed over a window, for the same reason the delay-based algorithms of queueing delay as a signal use a minimum: queueing delay is non-negative, so the smallest sample is the closest to the floor.
The two estimates answer different questions and are maintained on different timescales. The delivery-rate maximum is held over a window of a few round trips, long enough to include a delivery that was not slowed by a queue. The RTT minimum is held over a much longer window, on the order of tens of seconds, because the propagation delay changes only when the route changes and a short window would let a queue-inflated sample become the minimum.
The product of the two is the bandwidth-delay product, the number of bytes that must be in flight to keep the bottleneck busy. That is the target window, and it is derived rather than probed.
Why the maximum and the minimum, and what they get wrong
Both estimators are extremes, and extremes are chosen because they are insensitive to the specific contamination present. An average delivery rate is dragged down by every queue-induced gap, so it underestimates the bottleneck. An average RTT is inflated by every queue the sender creates, so it overestimates the propagation delay. The extremes discard the contaminated samples in the direction that matters: the maximum delivery rate is the one least affected by queueing, and the minimum RTT is the one taken when the queue was empty.
The price is that extremes are also the most sensitive to outliers in the other direction. A delivery rate sample computed over a very short interval, containing only one or two packets, can be arbitrarily large if the acknowledgements happen to arrive compressed. That sample becomes the maximum and stays there for the length of the window, so the sender believes the bottleneck is faster than it is and oversends until the estimate ages out. Implementations therefore require a minimum amount of data per sample before admitting it, which is a bias against high-rate paths where a legitimate sample interval is short.
The minimum RTT has the mirror problem. A single sample taken during a moment when the path was briefly shorter than usual — a route change, a transient in a virtualized forwarding path — sets a floor that no later sample can reach. The sender then computes a bandwidth-delay product that is too small and runs below capacity for the length of the window. The window’s length is the only defense, and it converts the error from permanent to temporary at the cost of slow recovery from a genuine improvement in propagation delay.
There is a third contamination that neither extreme removes. Both estimates are computed from acknowledgements, and acknowledgements are generated by the receiver, whose delay is not part of the path. A receiver that batches acknowledgements makes deliveries look compressed and then sparse, which inflates the delivery-rate maximum on the compressed samples. The estimates are of the sender-to-receiver-plus-receiver-to-sender system, not of the forward path alone, and no amount of filtering separates the receiver’s contribution.
The four phases
A model-based sender still has to discover the model, because at the start of a connection neither estimate exists. The structure that results is a cycle of phases rather than a single control law.
Startup doubles the sending rate each round trip, as slow start does, but it doubles the rate rather than the window, and it stops when the delivery-rate estimate stops growing. The stopping condition is the important difference. Slow start stops on loss, so it always overshoots; startup stops once several successive rounds fail to raise the maximum delivery rate by a meaningful margin, which happens when the bottleneck has been reached and the extra data is merely filling a queue. The overshoot is then bounded by the queue that accumulated during the last doubling rather than by whatever it takes to overflow the buffer.
Drain removes that queue. The sending rate is reduced to below the estimated bottleneck rate until the in-flight data falls back to the estimated bandwidth-delay product, which is the point at which the queue should be empty. The phase is short and exists only to undo startup’s overshoot.
Probe for bandwidth is the steady state. The sender holds its rate near the estimated bottleneck rate and periodically raises it by a small factor for one round trip, then lowers it by a corresponding factor, to test whether more capacity has become available. The rate cycle is a sawtooth in the rate domain rather than in the window domain, and its amplitude is small: a 25 percent increase followed by a 25 percent decrease, repeated on a schedule. A larger available rate shows up as a higher delivery-rate maximum during the probe, which updates the estimate.
Probe for RTT periodically empties the queue to re-measure the propagation delay. The sender reduces its window to a few packets for one round trip, which drains the queue and yields an uncontaminated RTT sample, then returns to the previous rate. This phase is what keeps the minimum RTT estimate from becoming permanently stale, and it costs a brief reduction in throughput on a schedule measured in tens of seconds.
def target_window(btlbw_bytes_per_s, min_rtt_s, gain=1.0, mss=1460):
"""Bytes in flight that fill the pipe without building a queue."""
bdp = btlbw_bytes_per_s * min_rtt_s
return max(bdp * gain, 4 * mss)
def pacing_interval(bytes_to_send, rate_bytes_per_s):
"""Time to wait between two transmissions at the given rate."""
return bytes_to_send / rate_bytes_per_s if rate_bytes_per_s > 0 else 0.0
The gain factor is where the design’s remaining tuning lives. A gain above one deliberately keeps a small standing queue, on the argument that a pipe held exactly full runs slightly below capacity because the bottleneck idles whenever a packet is late. A gain of one targets an empty queue and accepts the utilization loss.
Pacing as a separate mechanism
Window-based senders transmit when an acknowledgement arrives, so their transmissions are clustered at the moments the ACK stream delivers. Even with a correct average rate, the instantaneous rate is bursty, and the bursts land in the bottleneck’s queue where they add delay and force the buffer to be deeper than the average rate requires.
Pacing decouples the two. The sender computes the interval between packets from its target rate and transmits on that schedule, so the packet stream is smooth at the scale of the bottleneck’s service time. The window then becomes a safety bound rather than the primary control: it limits how much data may be outstanding, while the pacing rate determines when each packet goes out.
The mechanism is most valuable exactly where model-based control is most valuable. On a path with a large bandwidth-delay product, a window of several megabytes released on ACK arrival produces a burst that a shallow buffer cannot absorb; paced at the bottleneck rate, the same window produces a smooth stream that fills the pipe without a queue. The two techniques are usually described together for that reason, though either can be used without the other.
Pacing has its own failure mode. The pacing rate is derived from an estimate, and if the estimate is too high the sender transmits faster than the bottleneck can serve, which builds a queue at the same rate as an unpaced sender would, only more evenly. If the estimate is too low, the sender underutilizes the path and its own delivery-rate samples confirm the low estimate, which is a self-reinforcing error. The probe phases exist to break that loop, and their period determines how long a stale underestimate persists.
Fairness, and what the model does not see
Model-based control’s relationship to fairness is different from AIMD’s, and the difference is not in its favour.
AIMD converges to equal shares among flows with equal round trips because its increase is additive and its decrease multiplicative, as shown in the sawtooth analysis. A model-based sender has no such convergence property. It sets its rate from its own estimate of the bottleneck, and when several such flows share a bottleneck, each estimates the bottleneck as the rate it is achieving, which is its share rather than the link’s capacity. The estimates do not automatically equalize, and the flows’ relative shares depend on the order in which they arrived and on the timing of their probes.
The concrete pathology is that a flow which has been running longer has a higher delivery-rate estimate and therefore probes from a higher base. A later flow’s estimate grows only when its own delivery rate grows, which requires capacity to be free. If the earlier flow’s probe cycle keeps the queue non-empty, the later flow’s samples are contaminated and its estimate stays low. The result is a persistent advantage to the incumbent, which is the opposite of the convergence AIMD provides.
Loss-based flows and model-based flows also interact badly, in a direction that depends on the queue. A model-based flow keeps a small standing queue; a loss-based flow sharing the same bottleneck fills the buffer until it overflows. The model-based flow’s RTT minimum becomes stale because the queue never empties, so its bandwidth-delay product is computed from an inflated delay and its window grows larger than the path can hold, which pushes the loss-based flow’s losses higher. Later variants of the algorithm add an explicit response to loss and to ECN marks, which restores some of the properties the first version lacked while reintroducing a sawtooth that the model was meant to avoid.
Where the model is the right abstraction
The case for measuring rather than probing is strongest on paths where the two quantities are stable and separable: a data-center fabric with fixed topology and no cross traffic, a cellular link whose rate changes in steps that the sender can track, or a long-haul path where the propagation delay is large and the bandwidth-delay product dominates. On such paths the model is accurate, the sender avoids the losses that probing would cause, and the queue stays short.
The case is weakest where the bottleneck is a shared queue whose occupancy is determined by other flows, because then neither estimate is a property of the path. The delivery rate is a property of the sharing arrangement, and the minimum RTT is a property of everyone’s queue. A sender that treats those as constants of the path will be wrong in a way that no filter can correct, and the correctness of the whole design rests on an assumption that the network does not guarantee.
References
- BBR: Congestion-Based Congestion Control — Cardwell, Cheng, Gunn, Hassayoun, Jacobson; ACM Queue 14(5), 2016
- RFC 5681: TCP Congestion Control — IETF
- The Macroscopic Behavior of the TCP Congestion Avoidance Algorithm — Mathis, Semke, Mahdavi, Ott; ACM SIGCOMM Computer Communication Review 27(3), 1997