<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.20 (Ruby 3.3.5) -->


<!DOCTYPE rfc  [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">

<!ENTITY RFC2119 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml">
<!ENTITY RFC8174 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml">
<!ENTITY RFC9000 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9000.xml">
<!ENTITY I-D.ietf-moq-transport SYSTEM "https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-moq-transport.xml">
<!ENTITY RFC9331 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9331.xml">
<!ENTITY RFC9959 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9959.xml">
]>


<rfc ipr="trust200902" docName="draft-huitema-ccwg-c4-spec-04" category="exp" consensus="true" submissionType="IETF">
  <front>
    <title abbrev="C4 Specification">Specification of Christian's Congestion Control Code (C4)</title>

    <author initials="C." surname="Huitema" fullname="Christian Huitema">
      <organization>Private Octopus Inc.</organization>
      <address>
        <email>huitema@huitema.net</email>
      </address>
    </author>
    <author initials="S." surname="Nandakumar" fullname="Suhas Nandakumar">
      <organization>Cisco</organization>
      <address>
        <email>snandaku@cisco.com</email>
      </address>
    </author>
    <author initials="C." surname="Jennings" fullname="Cullen Jennings">
      <organization>Cisco</organization>
      <address>
        <email>fluffy@iii.ca</email>
      </address>
    </author>

    <date year="2026" month="July" day="19"/>

    <area>Web and Internet Transport</area>
    
    <keyword>C4</keyword> <keyword>Congestion Control</keyword> <keyword>Realtime Communication</keyword> <keyword>Media over QUIC</keyword>

    <abstract>


<?line 45?>

<t>Christian's Congestion Control Code is a new congestion control
algorithm designed to support Real-Time applications such as
Media over QUIC. It is designed to drive towards low delays,
with good support for the "application limited" behavior
frequently found when using variable rate encoding, and
with fast reaction to congestion to avoid the "priority
inversion" happening when congestion control overestimates
the available capacity. The design emphasizes simplicity and
avoids making too many assumptions about the "model" of
the network.</t>



    </abstract>



  </front>

  <middle>


<?line 58?>

<section anchor="introduction"><name>Introduction</name>

<t>Christian's Congestion Control Code (C4) is a congestion control
algorithm designed to support Real-Time multimedia applications, specifically
multimedia applications using QUIC <xref target="RFC9000"/> and the Media
over QUIC transport <xref target="I-D.ietf-moq-transport"/>.</t>

<t>The two main variables describing the state of a flow are the
"nominal rate" (see <xref target="nominal-rate"/>) and the
"nominal max RTT" (see <xref target="nominal-max-rtt"/>).
C4 organizes the management of the flow through a series of
states: Initial, during which the first assessment of nominal-rate
and nominal max RTT are obtained, Resuming for the implementation
of careful resume <xref target="RFC9959"/>, Recovery in which a flow is
stabilized after the Initial, Probing or Pushing phase, Cruising during which
a flow uses the nominal rate, Probing during which the flow
tries to discover whether more resource mighht be available and Pushing during which the flow
tries to otain more resource  -- see <xref target="c4-states"/>.</t>

<t>C4 divides the duration of the connection in a set of "eras",
each corresponding to a packet round trip. Transitions between protocol
states typically happen at the end of an era, except if the
transition is forced by a congestion event.</t>

<t>C4 assumes that the transport stack is
capable of signaling events such
as acknowledgements, RTT measurements, ECN signals or the detection
of packet losses. It also assumes that the congestion algorithm
controls the transport stack by setting the congestion window
(CWND) and the pacing rate (see <xref target="congestion-response"/>).</t>

<t>C4 introduces the concept of "sensitivity" (see <xref target="sensitivity"/>)
to ensure that flows using a large amount of bandwidth are more
"sensitive" to congestion signals than flows using fewer bandwidth,
and thus that multiple flows sharing a common bottleneck are driven
to share the resource evenly.</t>

</section>
<section anchor="key-words"><name>Key Words</name>

<t>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 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>

</section>
<section anchor="c4-variables"><name>C4 variables</name>

<t>In addition to the nomnal rate and the nominal max RTT,
C4 maintains a set a variables per flow (see <xref target="global-variables"/>)
and per era (see <xref target="era-variables"/>).</t>

<section anchor="nominal-rate"><name>Nominal rate</name>

<t>The nominal rate is an estimate of the bandwidth available to the flow.
On initialization, the nominal rate is set to zero, and default values
are used when setting the pacing rate and CWND for the flow.</t>

<t>C4 evaluates the nominal rate after acknowledgements are received
using the number of bytes acknowledged since the packet was sent
(<spanx style="verb">bytes_acknowledged</spanx>) and the time delay it took to process these packets.</t>

<t>That delay is normally set to the difference between the time
at which the acknowledged packet was sent (<spanx style="verb">time_sent</spanx>),
and the current time (<spanx style="verb">current_time</spanx>). However, that difference
may sometimes be severely underestimated because of delay jitter
and ACK compression. We also compute a "send delay" as the difference
between the send time of the acknowledged packet and the send time
of the oldest "delivered" packet.</t>

<figure><artwork><![CDATA[
delay_estimate = max (current_time - time_sent, send_delay)
rate_estimate = bytes_acknowledged /delay_estimate
]]></artwork></figure>

<t>If we are not in a congestion situation, we update the
nominal rate:</t>

<figure><artwork><![CDATA[
if not congested and nominal_rate > rate_estimate:
    nominal_rate = rate_estimate
]]></artwork></figure>

<t>The data rate measurements can only cause increases in
the nominal rate. The nominal rate is reduced following
congestion events, as specified in <xref target="congestion-response"/>.</t>

<t>The "congested" condition is defined as being in the
recovery state and having either entered that state due
to a congestion event, or having received a congestion
event after entering recovery.</t>

<t>Updating the nominal rate
in these conditions would cause a congestion bounce: the
nominal rate is reduced because of a congestion event,
C4 enters recovery, but then packets sent at the previous
rate are received during recovery, generating a new estimate
and resetting the nominal rate to a value close to the one
that caused congestion.</t>

</section>
<section anchor="nominal-max-rtt"><name>Nominal max RTT</name>

<t>The nominal max RTT is an estimate of the maximum RTT
that can occur on the path in the absence of queues.
The RTT samples observed for the flow are the sum of four
components:</t>

<t><list style="symbols">
  <t>the latency of the path</t>
  <t>the jitter introduced by processes like link layer contention
or link layer retransmission</t>
  <t>queuing delays caused by competing applications</t>
  <t>queuing delays introduced by C4 itself.</t>
</list></t>

<t>C4's goal is to obtain a estimate of the combination of path latency
and maximum jitter. This is done by only taking measurements
when C4 is sending data at a rate not higher than the nominal transmission rate,
as happens for example in the recovery and cruising states. These measurements
will happen during the following era. C4 captures them
by recording the max RTT for packets sent in that era.
C4 will also progressively reduce the value of the
nominal max RTT over time, to account for changes in network
conditions.</t>

<figure><artwork><![CDATA[
# on end of era

if alpha_previous <= 1.0:
    if era_min_rtt < running_min_rtt:
        running_min_rtt = era_min_rtt
    else:
        running_min_rtt =
           (7*running_min_rtt + era_min_rtt)/8

    if era_max_rtt > running_min_rtt + MAX_JITTER:
        # cap RTT increases to MAX_JITTER, i.e., 250ms
        era_max_rtt = running_min_rtt + MAX_JITTER
    if era_max_rtt > nominal_max_rtt:
        nominal_max_rtt = era_max_rtt
    else:
        nominal_max_rtt =
          (7*nominal_max_rtt + era_max_rtt)/8
]]></artwork></figure>

<t>The decrease over time is tuned so that jitter
events will be remembered for several of the
cruising-pushing-recovery cycles, which is enough time for the
next jitter event to happen, at least on Wi-Fi networks.</t>

</section>
<section anchor="global-variables"><name>Global variables</name>

<t>In addition to the nominal rate and nominal MAX RTT,
C4 maintains a set of variables tracking the evolution of the flow:</t>

<t><list style="symbols">
  <t>current state of the algorithm, which can be Initial, Resuming, Recovery,
Cruising, Probing or Pushing.</t>
  <t>running min RTT, an approximation of the min RTT for the flow,</t>
  <t>number of eras without increase (see <xref target="c4-initial"/>),</t>
  <t>the number of successive congestion events and the recent maximum rate,
used to detect and manage persistent congestion (see <xref target="persistent-congestion"/>).</t>
</list></t>

</section>
<section anchor="era-variables"><name>Per era variables</name>

<t>C4 keeps variables per era:</t>

<figure><artwork><![CDATA[
era_sequence; /* sequence number of first packet sent in this era */
alpha_current; /* coefficient alpha used in the current state */
alpha_previous; /* coefficient alpha used in the previous era */
era_max_rtt; /* max RTT observed during this era */
era_min_rtt; /* min RTT observed during this era */
]]></artwork></figure>

<t>These variables are initialized at the beginning of the era.</t>

</section>
</section>
<section anchor="c4-states"><name>States and Transition</name>

<t>The state machine for C4 has the following states:</t>

<t><list style="symbols">
  <t>"startup": the initial state, during which the CWND is
set to twice the "nominal_CWND". The connection
exits startup if the "nominal_cwnd" does not
increase for 3 consecutive round trips. When the
connection exits startup, it enters "recovery".</t>
  <t>"resuming": management of careful resume, during which the CWND and pacing rate are
pegged to the seed values. The state lasts for 2 eras,
giving enough time for the rate measurement to stabilize.
The eras are expanded if the connection is app limited,
to avoid exiting too early. After two eras, or at any time
if congestion is detected, the state transitions to recovery.</t>
  <t>"recovery": the connection enters that state after
"startup", "pushing", or a congestion detection in
a "cruising" state. It remains in that state for
at least one roundtrip, until the first packet sent
in "recovery" is acknowledged. Once that happens,
the connection goes back
to "startup" if the last 3 pushing attemps have resulted
in increases of "nominal rate", or enters "cruising"
otherwise.</t>
  <t>"cruising": the connection is sending using the
"nominal_rate" and "nominal_max_rtt" value. If congestion is detected,
the connection exits cruising and enters
"recovery" after lowering the value of
"nominal_cwnd".
Otherwise, the connection will
remain in "cruising" state until at least 4 RTT and
the connection is not "app limited". At that
point, it enters "pushing".</t>
  <t>"probing": the connection is using a rate and CWND 6.25%
larger than "nominal_rate" and "nominal_CWND", or 3.125%
if the local gateway is ECN capable. After
1 RTT, it moves back to "recovery" in order to assess
the results. If the data rate appears to have increased,
the connection moves to the "pushing" state.</t>
  <t>"pushing": the connection is using a rate and CWND 25%
larger than "nominal_rate" and "nominal_CWND".
It remains in that state for at least one round trip,
and until the measured rate stops growing. If the
pushing lasts more than 3 RTT, C4 re-enters the
initial state.</t>
</list></t>

<t>These transitions are summarized in the following state
diagram.</t>

<figure><artwork><![CDATA[
                    Start
                      |
                      v
                      +<-----------------------+
                      |                        |
                      v                        |
                 +----------+                  |
                 | Startup  |                  |
                 +-|--|-----+                  |
         +---------+  |                        | 
         |            |                        |
         v            |                        |
   +----------+       |                        |
   | Resuming |       |                        |
   +-----|----+       |                        |
         +---------+  |                        |
                   |  |                        |
                   v  v                        |
                 +------------+                |
  +--+---------->|  Recovery  |                |
  ^  ^           +----|---|---+                |
  |  |                |   | Rate increase      |
  |  |                |   +---------+          |
  |  |                |             |          |
  |  |                v             |          |
  |  |           +----------+       |          |
  |  |           | Cruising |       |          |
  |  |           +-|--|-----+       v          |
  |  | Congestion  |  |        +---------+     |
  |  +-------------+  |        | Pushing |     |
  |                   |        +----|--|-+     |
  |                   v             |  |       |
  |              +----------+       |  +-------+
  |              | Probing  |       |   Rapid
  |              +----|-----+       |   increase
  |                   |             |
  +<------------------+             |
  ^                                 |
  |                                 |
  +---------------------------------+

]]></artwork></figure>

<section anchor="set_pace"><name>Setting pacing rate, congestion window and quantum</name>

<t>If the nominal rate or the nominal max RTT are not yet
assessed, C4 sets pacing rate, congestion window and
pacing quantum to initial values:</t>

<t><list style="symbols">
  <t>pacing rate: set to the data rate of the outgoing interface,</t>
  <t>congestion window: set to the equivalent of 10 packets,</t>
  <t>congestion quantum: set to zero.</t>
</list></t>

<t>If the nominal rate or the nominal max RTT are both
assessed, C4 sets pacing rate, and congestion window 
to values that depends on these variables
and on a coefficient <spanx style="verb">alpha_current</spanx>:</t>

<figure><artwork><![CDATA[
pacing_rate = alpha_current * nominal_rate

if (c4_state == initial):
    margin = 0
else:
    margin = min(nominal_max_rtt/4, 15_milliseconds)

cwnd = max ((pacing_rate+margin) * nominal_max_rtt, 2*MTU)
]]></artwork></figure>

<t>During the initial phase, the pacing rate is set to a minimum
of 1,048,576 bps (128 KB/s) to avoid starting at too low a rate.
In these conditions, the transmission is expected to be limited
by the value of CWND.</t>

<figure><artwork><![CDATA[
if (c4_state == initial and pacing_rate < 1,048,576 bps):
    pacing_rate = 1,048,576 bps
]]></artwork></figure>

<t>The "margin" coefficient accounts for errors on the
estimate of the nominal max rtt, which could cause C4
to be stuck operating at a too low data rate. It is only
applied outside of the initial phase.</t>

<t>The coefficient <spanx style="verb">alpha</spanx> for the different states is:</t>

<texttable>
      <ttcol align='left'>state</ttcol>
      <ttcol align='left'>alpha</ttcol>
      <ttcol align='left'>comments</ttcol>
      <c>Initial</c>
      <c>2</c>
      <c>&#160;</c>
      <c>Recovery</c>
      <c>15/16</c>
      <c>&#160;</c>
      <c>Cruising</c>
      <c>1</c>
      <c>&#160;</c>
      <c>Probing</c>
      <c>33/32 or 17/16</c>
      <c>see <xref target="c4-probing"/> for rules on choosing 33/32 or 17/16</c>
      <c>Pushing</c>
      <c>5/4</c>
      <c>&#160;</c>
</texttable>

<t>Setting the pacing quantum is a tradeoff between two requirements.
Using a large quantum enables applications to send large batches of
packets in a single transaction, which improves performance. But
sending large batches of packets creates "instant queues" and
causes some Active Queue Management mechanisms to mark packets as
ECN/CE, or drop them. As a compromise, we set the quantum to
4 milliseconds worth of transmission, while capping it to 64KB.</t>

<figure><artwork><![CDATA[
quantum = max ( min (pacing_rate*4_milliseconds, 64KB), 2*MTU)
]]></artwork></figure>

</section>
<section anchor="c4-initial"><name>Initial state</name>

<t>When the flow is first initialized, it enters the Initial state,
during which it does a first assessment of the
"nominal rate" and "nominal max RTT".
The coefficient <spanx style="verb">alpha_current</spanx> is set to 2. The
"nominal rate" and "nominal max RTT" are initialized to zero,
which will cause pacing rate to be set to a default
initial value. The nominal max RTT will be set to the
first assessed RTT value, but is not otherwise changed
before the end of the initial phase.
The CWND will be set to the default initial value,
corresponding to 10 packets.</t>

<t>During the initial state, the nominal rate is updated
after receiving acknowledgements, see <xref target="nominal-rate"/>.
The value of CWND is increased after each acknowledgement
by the number of bytes newly acknowledged by this
acknowledgement.</t>

<t>C4 will exit the Initial state and enter Recovery if the 
nominal rate does not increase for 3 consecutive eras,
omitting the eras for which the transmission was
"application limited".</t>

<t>C4 exit the Initial when receiving a congestion signal if the
following conditions are true:</t>

<t>1- If the signal is due to "delay" or "ECN", C4 will only exit the
   initial state if the <spanx style="verb">nominal_rate</spanx> did not increase
   in the last 2 eras.</t>

<t>2- If the signal is due to "loss", C4 will only exit the
   initial state if more than 20 packets have been received.</t>

<t>The restriction on delay signals and ECN is meant to prevent spurious exit
due to delay jitter or competing connections. The restriction on loss
signals is meant to ensure that enough packets have been received to properly
assess the loss rate.</t>

<t>On exiting the Initial state, C4 computes an estimate of the nominal
max RTT as the quotient of the half the last CWND divided by the last
nominal rate, and updates the "nominal max RTT" accordingly.</t>

<section anchor="reentering-the-initial-state"><name>Reentering the initial state</name>

<t>When reentering the initial state, C4 already has an estimate of the
current nominal rate and nominal max RTT. CWND is set to the product of
nominal rate and nominal max RTT. The initial state then operates as
specified in <xref target="c4-initial"/>.</t>

</section>
</section>
<section anchor="resuming-state"><name>Resuming state</name>

<t>The resuming state is entered if the application remembers the CWND and RTT
of a previous connection between the same endpoints. The resuming state lasts for 2 eras,
during which the CWND and pacing rate are pegged to the remembered values.
The first of these eras can be extended if the connection is "application limited",
to avoid exiting too early. After 2 eras, or if a congestion signal is received before
that, C4 enters recovery.</t>

</section>
<section anchor="c4-recovery"><name>Recovery state</name>

<t>The recovery state is entered from the Initial, Resuming, Probing or Pushing state,
or from the Cruising state in case of congestion. 
The coefficient <spanx style="verb">alpha_current</spanx> is set to 15/16. Because the multiplier
is lower than 1, the new value of CWND may well be lower
than the current number of bytes in transit. C4 will wait
until acknowledgements are received and the number of bytes
in transit is lower than CWND to send new packets.</t>

<t>The Recovery ends when the first packet sent during that state
is acknowledged. That means that acknowledgement and congestion
signals received during recovery are the consequence of packets
sent before. C4 assumes that whatever corrective action is required
by these events will be taken prior to entering recovery, and that
events arriving during recovery are duplicate of the prior events
and can be ignored.</t>

<t>Rate increases are detected if the previous state was Probing, 
and if acknowledgements received during recovery
reflect a successful "probe" during the Probing phase, that is if the
probing did not trigger any congestion event
and if the data rate did increase.</t>

<t>If a succesful probing was detected, C4 immediately enters the Pushing state.</t>

<t>C4 re-enters "Initial" at the end of the recovery period if 
high jitter requires restarting the Initial phase (see
<xref target="restart-high-jitter"/>. Otherwise, C4 enters cruising.</t>

<t>Reception of a congestion signal during the Initial phase does not
cause a change in the <spanx style="verb">nominal_rate</spanx> or <spanx style="verb">nominal_max_RTT</spanx>.</t>

<section anchor="restart-high-jitter"><name>Restarting Initial if High Jitter</name>

<t>The "nominal max RTT" is not updated during the Initial phase,
because doing so would prevent exiting Initial on high delay
detection. This can lead to underestimation of the "nominal
rate" if the flow is operating on a path with high jitter.</t>

<t>C4 will reenter the "initial" phase on the first time
high jitter is detected for the flow. The high jitter
is detected after updating the "nominal max RTT" at the
end of the recovery era, if:</t>

<figure><artwork><![CDATA[
running_min_rtt < nominal_max_rtt*2/5
]]></artwork></figure>

<t>This will be done at most once per flow.</t>

</section>
</section>
<section anchor="cruising-state-c4-cruising-"><name>Cruising state {#c4-cruising }</name>

<t>The Cruising state is entered from the Recovery state. 
The coefficient <spanx style="verb">alpha_current</spanx> is set to 1.</t>

<t>C4 will transition from Cruising state to Probing state
after 2 eras.</t>

<t>C4 will transition to Recovery before that if
a congestion signal is received before transition to Probing.</t>

</section>
<section anchor="c4-probing"><name>Probing state</name>

<t>The probing state is entered from the Cruising state.</t>

<t>The coefficient <spanx style="verb">alpha_current</spanx> is set to 17/16, unless ECN-CE
marks have been received on the path, in which case it is set to 33/32.
The presence of ECN/CE means that an
on path router is implementing either L4S (<xref target="RFC9331"/>) or another
ECN marking scheme.</t>

<t>C4 exits the probing state after one era, or if a congestion
signal is received before that.</t>

</section>
<section anchor="c4-pushing"><name>Pushing state</name>

<t>The pushing state is entered from the Recovery state if a previous
probing was successful, as stated in <xref target="c4-recovery"/>.</t>

<t>The coefficient <spanx style="verb">alpha-current</spanx> is set to 5/4.</t>

<t>The pushing phase lasts for at least two eras. During the first
era, measurements correspond to data sent during the recovery
phase, which are unlikely to result in detection of rate increases.
After that first phase, C4 assesses whether the new "nominal rate"
has increased sufficiently druing the previous RTT. If it has, C4
will continue in the pushing phase. If it has not, the flow will
transition to recovery.</t>

<t>We define "increased sufficiently" as reaching at least 19/16th of the
nominal rate at the beginning of the era.</t>

<t>C4 also exits the pushing state if a congestion
signal is received. In an exception to
standard congestion processing, the reduction in <spanx style="verb">nominal_rate</spanx> and
<spanx style="verb">nominal_max_RTT</spanx> are not applied if the congestion signal
is tied to a packet sent during the Pushing state.</t>

</section>
</section>
<section anchor="congestion-response"><name>Handling of congestion signals</name>

<t>C4 responds to congestion events by reducing the nominal rate, and
in some condition also reducing the nominal max RTT. C4 monitors
3 types of congestion events:</t>

<t><list style="numbers" type="1">
  <t>Excessive increase of measured RTT,</t>
  <t>Excessive rate of packet losses (but not mere Probe Time Out, see <xref target="no-pto"/>),</t>
  <t>Excessive rate of ECN/CE marks</t>
</list></t>

<t>C4 monitors successive RTT measurements and compare them to
a reference value, defined as the sum of the "nominal max rtt"
and a "delay threshold". C4 monitors the arrival of packet losses
computes a "smoothed error rate", and compares it to a
"loss threshold". When the path supports ECN, C4 monitors the
arrival of ECN marks and computes a "smoothed CE rate",
and compares it to a "CE threshold". These coefficients
depend on the sensitivity coefficient defined in <xref target="sensitivity"/>.</t>

<section anchor="sensitivity"><name>Variable Sensitivity</name>

<t>The three congestion detection thresholds are
function of the "sensitivity" coefficient,
which increases with the nominal rate of the flow. Flows
operating at a low data rate have a low sensitivity coefficient
and reacts slower to congestion signals than flows operating
at a higher rate. If multiple flows share the same bottleneck,
the flows with higher data rate will detect congestion signals
and back off faster than flow operating at lower rate. This will
drive these flows towards sharing the available resource evenly.</t>

<t>The sensitivity coefficient varies from 0 to 1, according to
a simple curve:</t>

<t><list style="symbols">
  <t>set sensitivity to 0 if data rate is lower than 50000 B/s</t>
  <t>linear interpolation between 0 and 0.92 for values
between 50,000 and 1,000,000 B/s.</t>
  <t>linear interpolation between 0.92 and 1 for values
between 1,000,000 and 10,000,000 B/s.</t>
  <t>set sensitivity to 1 if data rate is higher than
10,000,000 B/s</t>
</list></t>

<t>The sensitivity index is then used to set the value of delay and
loss and CE thresholds.</t>

</section>
<section anchor="detecting-excessive-delays"><name>Detecting Excessive Delays</name>

<t>The delay threshold is function of the nominal max RTT and the
sensitivity coefficient:</t>

<figure><artwork><![CDATA[
    delay_fraction = 1/16 + (1 - sensitivity)*3/16
    delay_threshold = min(25ms, delay_fraction*nominal_max_rtt)
]]></artwork></figure>

<t>A delay congestion signal is detected if:</t>

<figure><artwork><![CDATA[
    rtt_sample > nominal_max_rtt + delay_threshold
]]></artwork></figure>

</section>
<section anchor="detecting-excessive-losses"><name>Detecting Excessive Losses</name>

<t>C4 maintains an average loss rate, updated for every packet
as:</t>

<figure><artwork><![CDATA[
    if packet_is_lost:
        loss = 1
    else:
        loss = 0
    smoothed_loss_rate = (loss + 15*smoothed_loss_rate)/16
]]></artwork></figure>

<t>The loss threshold is computed as:</t>

<figure><artwork><![CDATA[
    loss_threshold = 0.02 + 0.50 * (1-sensitivity);
]]></artwork></figure>

<t>A loss is detected if the smoothed loss rate is larger than the threshold.
In that case, the coefficient <spanx style="verb">beta</spanx> is set to 1/4.</t>

<section anchor="no-pto"><name>Do not react to Probe Time Out</name>

<t>QUIC normally detect losses by observing gaps in the sequences of acknowledged
packet. That's a robust signal. QUIC will also inject "Probe time out"
packets if the PTO timeout elapses before the last sent packet has not been acknowledged.
This is not a robust congestion signal, because delay jitter may also cause
PTO timeouts. When testing in "high jitter" conditions, we realized that we should
not change the state of C4 for losses detected solely based on timer, and
only react to those losses that are detected by gaps in acknowledgements.</t>

</section>
</section>
<section anchor="process-ecn"><name>Detecting Excessive CE Marks</name>

<t>The way we handle ECN signals is designed to be compatible with L4S <xref target="RFC9331"/>.
When the path supports ECN marking, C4 monitors the arrival of ECN/CE and
ECN/ECT(1) marks by computing the ratio <spanx style="verb">ecn_alpha</spanx>. Congestion is detected
when that ratio exceeds <spanx style="verb">ecn_threshold</spanx>, which varies depending on the
sensitivity coefficient:</t>

<figure><artwork><![CDATA[
ecn_threshold = (2-sensitivity)*3/32
]]></artwork></figure>

<t>The ratio <spanx style="verb">ecn_alpha</spanx> is
updated each time an acknowledgement is received, as follow:</t>

<figure><artwork><![CDATA[
delta_ce = increase in the reported CE marks
delta_ect1 = increase in the reported ECT(1) marks
frac = delta_ce / (delta_ce + delta_ect1)

if frac >= 0.5:
    ecn_alpha = frac
else:
    ecn_alpha += (frac - ecn_alpha)/16

if ecn_alpha > ecn_threshold:
    report congestion
]]></artwork></figure>

<t>Congestion detection causes C4 to enter recovery. The
ration <spanx style="verb">ecn_alpha</spanx> is set to zero on exit of recovery.</t>

</section>
<section anchor="applying-congestion-signals"><name>Applying congestion signals</name>

<t>On congestion signal, if C4 was not in recovery state, it
will enter recovery.</t>

<t>As stated in <xref target="c4-initial"/> and <xref target="c4-pushing"/>, detecting
a congestion in the Initial or Pushing state does not cause
a change in the <spanx style="verb">nominal_rate</spanx> or <spanx style="verb">nominal_max_RTT</spanx>, because
the pacing rate in these states is larger than the
<spanx style="verb">nominal_rate</spanx>. Rate reduction only happens if recovery
was entered from the Cruising state</t>

<section anchor="rate-reduction"><name>Rate Reduction on Congestion</name>

<t>On entering recovery from the cruising state, C4 reduces the
<spanx style="verb">nominal_rate</spanx> by the factor "beta"
corresponding to the congestion signal:</t>

<figure><artwork><![CDATA[
    nominal_rate = (1-beta)*nominal_rate
]]></artwork></figure>

<t>The coefficient <spanx style="verb">beta</spanx> differs depending on the nature of the congestion
signal. For packet losses, it is set to <spanx style="verb">1/4</spanx>, similar to the
value used in Cubic.</t>

<t>For delay based losses, it is proportional to the
difference between the measured RTT and the target RTT divided by
the acceptable margin, capped to <spanx style="verb">1/4</spanx>:</t>

<figure><artwork><![CDATA[
    beta = min(1/4,
              (rtt_sample - (nominal_max_rtt + delay_threshold)/
               delay_threshold))
]]></artwork></figure>

<t>If the signal is an ECN/CE rate, the coefficient is proportional
to the difference between <spanx style="verb">ecn_alpha</spanx> and <spanx style="verb">ecn_threshold</spanx>, capped to <spanx style="verb">1/4</spanx>:</t>

<figure><artwork><![CDATA[
    beta = min(1/4, (ecn_alpha - ecn_threshold)/ ecn_threshold)
]]></artwork></figure>

</section>
<section anchor="persistent-congestion"><name>Reaction to persistent congestion</name>

<t>C4 makes a distinction between intermittent congestion, which is handled
by reducing the nominal rate as specified in <xref target="rate-reduction"/>, and
persistent congestion, which is detected if 2 congestion events
appear in rapid succession.</t>

<t>C4 handles two variables to manage the reaction to persistent congestion:
the number of successive congestion events and the "recent maximum rate":</t>

<t><list style="symbols">
  <t>The number of successive congestion events is managed upon exiting
a recovery era. It is reset to zero if no congestion signal was received
upon entering that era or during that era, and is incremented by 1 otherwise.</t>
  <t>The "recent maximum rate" is the maximum rate measurement observed since
the end of the previous recovery period, i.e., the recovery period that
preceded the current one.</t>
</list></t>

<t>If the number of successive congestion events is larger than 1, C4 will
check if at least one rate measurement has been received since the end
of the previous recovery period, i.e, if the "recent maximum rate" is larger
than 0. If so, C4 will reset
the "nominal rate" to the "recent maximum rate".</t>

</section>
</section>
</section>
<section anchor="implementation-considerations"><name>Implementation considerations</name>

<t>Implementing C4 ought to be straightforward, but developers need to pay
attention to measurement of data rates and to pacing issues when the
CPU load is high.</t>

<section anchor="rate-measurement-should-be-conservative"><name>Rate measurement should be conservative</name>

<t>The standard algorithm for rate measurement is to consider the amount
of data acknowledged in an interval of time, and divide that amount
by the duration of the interval. This algorithm can result in
over-estimates of the rate in presence of data jitter. These
excessive estimates could cause C4 to set a nominal rate higher
than the network path bandwidth, resulting in queue build-up and
excessive delays.</t>

<t>There are two known ways to reduce the effect of jitter: filter out
measurements in which the data rate measured through acknowledgements
is larger than the send rate; and, make sure that the measurement
interval are long enough so jitter only has a small influence. Cautious
implementations should use both strategies.</t>

</section>
<section anchor="pacing-and-cpu-load"><name>Pacing and CPU load</name>

<t>C4 relies on pacing during to avoid sending data too fast.
Pacing is often implemented
using a "leaky bucket" algorithm, which refills the bucket at the
pacing rate, allows transmission as long as there are enough tokens
in the bucket, and forces transmission to wait when all tokens are
consumed. The wait time is computed based on the pacing rate
and the number of desired tokens, and is implemented using
operating system commands such as <spanx style="verb">select()</spanx>, <spanx style="verb">poll()</spanx>,
<spanx style="verb">epoll()</spanx> or <spanx style="verb">sleep()</spanx>. In high CPU load conditions, we observe
that these commands often return after more than the specified
wait time, resulting in a lower sending rate than the desired
pacing rate.</t>

<t>This phenomenom is particularly visible in low-latency paths.
The generic solution would probably be to estimate how much slower
the actual pacing is compared to the desired rate, and increase the
programmed pacing rate by a value proportional to these measurements.
This generic solution is not yet specified. In between, implementations
had success with a simple fix: increase the pacing rate 3/64th in
"cruising" state when the RTT is less than 1ms. This definitely
improved performance in low-latency environment, in particular
loopback interfaces.</t>

</section>
<section anchor="nominal-max-rtt-on-low-latency-links"><name>Nominal max RTT on low latency links</name>

<t>When doing tests on low latency links, we observed on some systems
a lot of measurement jitter. The measured RTT is the sum of the
actual RTT and some system wakeup delay, which can vary between a
few microseconds and maybe 1 millisecond. The default algorithm
will adapt the nominal RTT after each roundtrip, which can lead
to excessively low values, causing a slowdown of the transmission.
A solution is to set a "floor" value to the nominal max RTT,
updating it to the maximum of the measured value and the floor.
Setting the floor value to 1ms did improve performance.</t>

</section>
</section>
<section anchor="security-considerations"><name>Security Considerations</name>

<t>We do not believe that C4 introduce new security issues. Or maybe there are,
such as what happen if applications can be fooled in going to fast and
overwhelming the network, or going too slow and underwhelming the application.
Discuss!</t>

</section>
<section anchor="iana-considerations"><name>IANA Considerations</name>

<t>This document has no IANA actions.</t>

</section>


  </middle>

  <back>


<references title='References' anchor="sec-combined-references">

    <references title='Normative References' anchor="sec-normative-references">

&RFC2119;
&RFC8174;


    </references>

    <references title='Informative References' anchor="sec-informative-references">

&RFC9000;
&I-D.ietf-moq-transport;
&RFC9331;
&RFC9959;


    </references>

</references>


<?line 816?>

<section numbered="false" anchor="acknowledgments"><name>Acknowledgments</name>

<t>TODO acknowledge.</t>

</section>
<section numbered="false" anchor="changes-since-previous-versions"><name>Changes since previous versions</name>

<t>This section should be deleted before publication as an RFC</t>

<section numbered="false" anchor="changes-since-draft-huitema-ccwg-c4-spec-03"><name>Changes since draft-huitema-ccwg-c4-spec-03</name>

<t>Specified a minimum pacing rate during the initial phase.</t>

</section>
<section numbered="false" anchor="changes-since-draft-huitema-ccwg-c4-spec-02"><name>Changes since draft-huitema-ccwg-c4-spec-02</name>

<t>Added a "resuming" state for implementing the "careful resume"
algorithm.</t>

<t>Separate "probing" state, which lasts just one RTT before
success is evaluated, and a more aggressive "pushing" state,
which lasts until rate measurements stop growing. This replaces
the use of "probe level" introduced in draft-02.</t>

<t>Added a faster "reaction to persistent congestion".</t>

</section>
<section numbered="false" anchor="changes-since-draft-huitema-ccwg-c4-spec-01"><name>Changes since draft-huitema-ccwg-c4-spec-01</name>

<t>Revised the description of the initial state do derive the CWIN
from a Reno like algorithm, avoiding the need to estimate max RTT
during the initial startup.</t>

<t>Introduces a "probe level" with progressively increasing rates of
probing as previous trials succeed.</t>

<t>Added implementation considerations.</t>

</section>
<section numbered="false" anchor="changes-since-draft-huitema-ccwg-c4-spec-00"><name>Changes since draft-huitema-ccwg-c4-spec-00</name>

<t>Rewrote the description of the Initial state in <xref target="c4-initial"/>
to remove dependency on nominal max RTT.</t>

<t>Added the specification of reaction to ECN in <xref target="process-ecn"/>
and in <xref target="rate-reduction"/>. Update section <xref target="c4-pushing"/> to
modulate pushing rate based on observed rate of ECN/CE marks.</t>

<t>Added the RTT margin consideration in <xref target="set_pace"/>, and 
changed the computation of the "quantum" from:</t>

<figure><artwork><![CDATA[
quantum = max ( min (cwnd / 4, 64KB), 2*MTU)
]]></artwork></figure>

<t>to:</t>

<figure><artwork><![CDATA[
quantum = max ( min (pacing_rate*4_milliseconds, 64KB), 2*MTU)
]]></artwork></figure>

<t>The old formula caused long bursts of packets that would
trigger packet drops or ECN/CE marking by active queue management
algorithms.</t>

</section>
</section>


  </back>

<!-- ##markdown-source:
H4sIAAAAAAAAA6U9aXfcxpHf+1f0jt6+kOLM8BDlxIzlF5mS10qsIxK93v0S
EgP0cBBigDEOjmhR+e1bV18ASEpZvTgaAX1UV1fX3YXZbKbavC3MiZ582Jg0
X+Zp0uZVqaulPl3VedPmSfmHRp9W5aVp6A38bOuqgL8zo3dOj3cnKlksanMN
Y5we62iYiYK/zWVV35xo83GjVFalZbKG6bI6WbazVZe3Zp3M0nR7OUuPZw10
nh0cq6ZbrPOmgRHamw20fvXy7EdVduuFqU9UBkOeqLQqG1M2XXOi27ozKt/U
9Ktpjw4Ovj04UkltEgDpV7PQSZnpV2Vr6tK0+qxOymZT1e1EXZmbbVVnJ0rP
9Okx/f9gnfj0vUmKNl8beLZed6UsDt+8Nlme6Ora1Prvv7w6VSrp2lVV44hK
a52XAN7pXP/E68RHvHyH2/BVVV+e6Hd1fg0L1G/Tttp0DcCdzvEltMmLEy0Y
+4v8PYcVhXN9mOs3sNrkqlsntZ/uQ7dKmt4bmC0p899pKQBQ3qRVME9TcuO/
pPhinlbr3pL+asoyLy+bYE1dUZgyenH/HMuiWy5v/pLn+TxNlCqreg0tr2Fz
oc37H0+PDg+/tb//dPjH4xOVl8t+o28PDg7o96vZi3lu2uVsXf02a+0mu2ZP
nhy6398+hXHVbDbTyaKBpmmr1JdQe97oRJdmq1PfIBUySQog87xdrXVmmvyy
NJluK910G4SCKGh2hiSUbDaFEFADr9OVThrVI6O5ftXiZOFIGdCFgR/bpM4a
XVRbeFskN81UbWFWfVlVmZsNkKTbldGTYDJd5GsgmWyiF2aVXOdVrZa1+a0z
ZVvcQI8Ozsh2BfvXNbB7+jqp82RRGF0jMZoyrTJ4PMWjxBMuk6bVcMRSGhwA
DHAC/0quqzxjIDZ1jpi5gd2DBeKhnugVQGaQTHjOIT4JGfgIdts0CgdKroFq
CKY02SQpjDjXZ/CcsQREtQEiz383gNZ8jeuGFgQvwdLodXKFE7ZVBT9LeNU0
3XrDG5Esqq5lcNew08UEGCBNCucLWMTVnMllnWdZYZR6hOykrrKOVv9lxIOs
kino/0E9644YEVJLSEhT3Vi2WxQ36o5WsrVIYfrTJzk7nz8Te8S1EhUqR4Xa
HSJoPX66Pn8GxOAeAJIAqXnp6IaIN63zBaEcWjQtEhKIlQTOPVAvsGd8riZl
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
WcQ5/fk/3OJ5yo5+AAA=

-->

</rfc>

