<?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-03" 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="05"/>

    <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[
if (c4_state == initial):
    margin = 0
else:
    margin = min(nominal_max_rtt/4, 15_milliseconds)

pacing_rate = alpha_current * nominal_rate
cwnd = max ((pacing_rate+margin) * nominal_max_rtt, 2*MTU)
]]></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 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>
<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 804?>

<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-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:
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
ahh8fYwtrFAtOHw5KOKcfv4fMzs727h5AAA=

-->

</rfc>

