rfc-9937

Proportional Rate Reduction (PRR)

M. Mathis, N. Cardwell, Y. Cheng, N. Dukkipati
date2025-12 streamIETF areawit wgtcpm statusPROPOSED STANDARD pages20 canonicalhttps://www.rfc-editor.org/rfc/rfc9937 doi10.17487/RFC9937
This document specifies a Standards Track version of the Proportional Rate Reduction (PRR) algorithm that obsoletes the Experimental version described in RFC 6937. PRR regulates the amount of data sent by TCP or other transport protocols during fast recovery. PRR accurately regulates the actual flight size through recovery such that at the end of recovery it will be as close as possible to the slow start threshold (ssthresh), as determined by the congestion control algorithm.

obsoletes

Extracted elements (24)

design-rationale §11.3

PRR bases transmission decisions on the volume of delivered data rather than the volume of lost data, unlike RFC 6675 where a single SACK-carrying ACK implying large missing data can cause a step discontinuity in the pipe estimator and trigger a large unclocked burst. This is the core motivation for PRR's self-clocking approach.

tcp, congestion

design-rationale §7

PRR-CRB satisfies the Strong Packet Conservation Bound: it never transmits more data than has been delivered to the receiver, ensuring a bottleneck queue maintains exactly constant length during recovery. However, this bound alone is less aggressive than RFC 6675 in burst-loss scenarios, motivating PRR-SSRB as a compromise that allows one extra segment per ACK when recovery is progressing well.

tcp, congestion

design-rationale §7

PRR is less sensitive to errors in the inflight estimator than RFC 6675. When inflight is misestimated (e.g., underestimated due to premature loss marking of reordered data), PRR's response differs by at most 1 segment per ACK between its two sub-algorithms, whereas RFC 6675 can send large bursts that cannot be retracted once the estimator corrects.

tcp, congestion

design-rationale §4

RecoverFS was changed to properly account for sequence ranges SACKed before entering fast recovery, correcting a defect in RFC 6937 where PRR would send too slowly after entering recovery following a large amount of pre-recovery SACKing (e.g., when the sender had previously detected high reordering).

tcp, congestion

design-rationale §4

Setting cwnd = ssthresh at the end of recovery (not the start, as in RFC 6675) is critical for robust performance: without it, application-limited senders and certain loss patterns could end fast recovery well below ssthresh, causing worse performance than RFC 6675.

tcp, congestion

design-rationale §4

The SafeACK heuristic was introduced after traffic policing research showed that both PRR-CRB and PRR-SSRB performed poorly under high-loss policer conditions. PRR-CRB was too timid and PRR-SSRB too aggressive, both causing prolonged recovery. SafeACK dynamically switches: use PRR-CRB by default, switch to PRR-SSRB only when ACKs show SND.UNA advancing without new losses.

tcp, congestion

interoperability-note §4

PRR can be adapted for non-loss-based congestion control (e.g., ECN per RFC 3168) by using parts of the RFC 6675 loss recovery state machine to invoke PRR ACK processing for exactly one round trip. However, interactions with AQM and ECN approaches should be assessed per RFC 9743 guidance.

tcp, congestion, ecn

interoperability-note §11.1

PRR is incrementally deployable and requires changes only at the data sender; no changes are required at receivers, routers, switches, or other network devices. PRR senders are fully compatible with existing receivers and networks.

tcp, congestion

interoperability-note §5

PRR MAY be used with loss detection algorithms from Reno (RFC 5681), NewReno (RFC 6582), SACK (RFC 6675), FACK, and RACK-TLP (RFC 8985). PRR requires only that the loss detection algorithm communicate how many packets were marked lost and delivered per ACK, with no dependency on the loss detection details.

tcp, congestion

normative-requirement §6.1 MUST

At the beginning of a congestion control response episode, a data sender using PRR MUST initialize PRR state variables: ssthresh (via CongCtrlAlg()), prr_delivered = 0, prr_out = 0, and RecoverFS computed from SND.NXT - SND.UNA adjusted for SACKed bytes.

tcp, congestion

normative-requirement §5 RECOMMENDED

Because of RACK-TLP's resilience to tail loss, reordering, and lost retransmissions, it is RECOMMENDED that PRR be implemented together with RACK-TLP loss recovery [RFC8985].

tcp, congestion

normative-requirement §6.2 MUST

For non-SACK connections, senders MUST subtract min(RecoverFS, 1 SMSS per preceding duplicate ACK) from the inflight estimate, rather than subtracting SACKed bytes. The min() with RecoverFS protects against misbehaving receivers.

tcp, congestion

normative-requirement §6.2 MUST

If prr_out is 0 and SndCnt is 0 upon entering recovery, SndCnt MUST be forced to SMSS to ensure a fast retransmit is sent, maintaining the ACK clock and avoiding potential RTO events.

tcp, congestion

normative-requirement §6.4 RECOMMENDED

It is RECOMMENDED that implementations use pacing to reduce the burstiness of data traffic, especially when cwnd is set to ssthresh at the end of recovery, which can permit a burst of back-to-back segments.

tcp, congestion

normative-requirement §6.4 MUST

On completion of a PRR episode (end of fast recovery or start of a new congestion control response), cwnd MUST be set to ssthresh. This prevents cwnd from ending recovery well below ssthresh due to application-limited behavior.

tcp, congestion

normative-requirement §5 MAY

PRR MAY be used with any congestion control algorithm that intends to make a multiplicative decrease in sending rate over approximately one RTT, where in-flight data is limited by cwnd and the target volume during reduction is a fixed ssthresh value. PRR is explicitly applicable to Reno and CUBIC.

tcp, congestion

normative-requirement §6.2 MUST

SACK-enabled connections using RACK-TLP or other non-pipe loss detection MUST calculate inflight as SND.NXT - SND.UNA, minus SACKed bytes, minus bytes marked lost, plus bytes retransmitted since last marked lost.

tcp, congestion

normative-requirement §6.2 MUST NOT

Without SACK, PRR disallows incrementing DeliveredData when the total bytes delivered in a PRR episode would exceed RecoverFS, as a mitigation against misbehaving receivers that return extraneous duplicate ACKs to artificially inflate DeliveredData.

tcp, congestion, security

protocol-element §6.2

cwnd is updated after each ACK as cwnd = inflight + SndCnt. On every data transmission or retransmission, prr_out is incremented by the number of bytes sent.

tcp, congestion

protocol-element §6.2

DeliveredData is the sender's best estimate of bytes delivered since the previous ACK. With SACK it equals the change in SND.UNA plus the signed change in SACKed bytes. Without SACK, it is estimated as 1 SMSS per duplicate ACK, or the change in SND.UNA minus 1 SMSS per preceding duplicate ACK on a full/partial ACK.

tcp, congestion

protocol-element §6.1

Recovery Flight Size (RecoverFS) is the sender's estimate of bytes possibly delivered during a PRR episode. It is initialized as SND.NXT - SND.UNA, minus bytes already SACKed in scoreboard, plus newly SACKed bytes, plus newly cumulatively acknowledged bytes. It remains constant during a recovery episode.

tcp, congestion

protocol-element §6.2

SafeACK is a local boolean that is true only when the current ACK has cumulatively acknowledged new data and does not indicate further losses (e.g., does not trigger an RFC 6675 'rescue' retransmission). It controls whether PRR-SSRB or PRR-CRB is used when inflight is below ssthresh.

tcp, congestion

security-consideration §13

PRR does not change the risk profile for transport protocols. However, implementations that count segments instead of bytes must be cautious about ACK splitting attacks (Savage99), where a misbehaving receiver acknowledges partial segments to confuse the sender's congestion accounting.

tcp, security, congestion

state-machine §6.2

When inflight > ssthresh, PRR uses Proportional Rate Reduction: SndCnt = DIV_ROUND_UP(prr_delivered * ssthresh, RecoverFS) - prr_out. When inflight <= ssthresh, PRR defaults to PRR-CRB: SndCnt = MAX(prr_delivered - prr_out, DeliveredData), then adds SMSS if SafeACK is true (PRR-SSRB), capped at MIN(ssthresh - inflight, SndCnt).

tcp, congestion