Skip to main content
The Scala RoCE NIC slows each queue pair down when switches mark its packets with ECN, and raises the rate again as the marks stop, in a DCQCN-style loop. This page follows a congestion signal from the switch that marks a packet to the sender’s rate. The transport that carries the packets is on Transport, PFC is on Buffers and PFC, and every ECNHandler attribute’s type and default is on Configuration.

Overview

Congestion control involves three parties, as in DCQCN:
  1. The sender’s NIC sends its data packets as ECN-capable.
  2. A switch with a congested egress queue marks those packets Congestion Experienced (CE). The NIC itself never marks a packet; marking is the switch’s job (ECN marking explains how the Scala Switch decides).
  3. The receiver’s NIC, on a CE-marked packet, sends a congestion notification packet (CNP) to the sending queue pair. The sender’s NIC reacts to CNPs by lowering that queue pair’s rate, and raises it again in steps once CNPs stop.
Each queue pair has its own rate and its own loop. A queue pair starts at line rate, the NIC’s DataRate, and stays there until its first CNP.

Key concepts

ECN on the wire

EnableECN decides whether the NIC takes part as a sender: ACKs and NAKs are always sent Not-ECT, and run at line rate.

Congestion notification

When a packet arrives with its IP ECN field set to CE, the receiving NIC sends a CNP to the queue pair that sent it, whatever the receiving NIC’s own EnableECN. The CNP is 122 bytes on the wire (Packets on the wire). It carries the queue pair’s control class in its DSCP, but it is sent through the NIC’s dedicated queue for PFC and congestion notification frames: ahead of all traffic classes, never paused by PFC, and not charged to an egress pool (Transmit scheduling). The sender counts the CNPs each queue pair receives, and the data packets each queue pair sends, for the rate control loop.

The rate control loop

The loop runs per queue pair while that queue pair is congested. It has these stages:
  1. CNP reception starts an episode. When a CNP arrives for a queue pair that is not congested, the loop runs at once, starting with a reduction. The queue pair is congested from then on, and its target rate is set to the rate it had when the episode began.
  2. The control interval. The loop then runs every half ControlIntervalDurationNs, alternating a reduction half and an increase half, so each control interval of 45 µs by default holds one of each. The CNP and packet counts are cleared after each reduction half, so each interval counts afresh.
  3. The congestion estimate. Every run of the loop updates the queue pair’s congestion estimate, a moving average of how strongly the queue pair’s traffic is being marked, taken from the CNPs it received and the packets it sent in the current interval. CongestionProbabilityWeight is the weight each new interval carries in the average: a higher weight makes the estimate rise faster and forget earlier congestion sooner.
  4. Reduction. In a reduction half that saw at least one CNP, the queue pair makes a reduction. On the reduction that begins an episode, and during fast recovery, the current rate is cut by a fraction set by the congestion estimate, at most half, and the recovery count goes back to 0. Once the queue pair has moved on to additive increase, a reduction instead first lowers the target rate by one additive step, then moves the current rate halfway toward the new target rate, and takes one off the recovery count. When the count falls below FastRecoveryAttempt, the queue pair is back in fast recovery: its next increase leaves the target rate alone, and a reduction that comes before increases bring the count back to FastRecoveryAttempt is a fast recovery reduction. A reduction half with no CNP leaves the rate alone.
  5. Increase. An increase half that has seen no CNP since the last reduction half makes an increase. An increase half that did see CNPs makes one only on every (NumOfControlLoopsPerIncrease + 1)-th such half, every sixth at the default 5.
  6. Fast recovery. While the recovery count is below FastRecoveryAttempt, each increase moves the current rate halfway toward the target rate, without changing the target, and adds one to the count. Each halves the gap between them.
  7. Additive increase. Once the recovery count reaches FastRecoveryAttempt, each further increase first raises the target rate by the additive step, up to line rate, and then moves the current rate halfway toward it. The step is fixed when the episode begins:
  8. The floor. While a queue pair is congested, its rate never goes below MinimumRatePercentage × DataRate, whatever the reductions would give.
  9. The return to line rate. When an increase brings the current rate within 0.1 Gbps of line rate, the episode ends: the queue pair runs at line rate again, the loop stops, and the next CNP starts a new episode.
There is no hyper-increase stage and no byte counter: every increase is driven by the timer of the control interval.

How the rate is applied

The allowed rate applies to the queue pair’s data packets: the network port sends each of them at the queue pair’s current rate, or at the floor if that is higher, rather than at DataRate. Its ACKs and NAKs, CNPs, and PFC frames are sent at line rate. Each queue pair’s rate is independent of the others’, so two queue pairs on the same NIC can be slowed by different amounts.

How each attribute shapes the loop

All of these sit in the ECNHandler component and apply to every queue pair on the NIC.

Worked example: the loop’s timing and steps at the defaults

A queue pair on a NIC with DataRate 400 Gbps and every ECNHandler attribute at its default, whose episode begins while it runs at line rate:
After the reduction that begins the episode, the first three increases are fast recovery. Each halves the gap between the current rate and the 400 Gbps target, so after three of them the queue pair has recovered seven eighths of what the reduction took. From the fourth increase on, additive increase adds the 4 Gbps step to the target. Here the target is already line rate, 400 Gbps, so it stays there, and each increase keeps halving the gap toward it. With no further CNPs, an increase comes every 45 µs, and the episode ends once the gap has fallen below 0.1 Gbps.

What congestion control records

No record holds a queue pair’s allowed rate. Records the transport writes describes the rest of roce-transport-stats.