Skip to content

Add BBRv3 as a selectable congestion control option#22

Open
endel wants to merge 1 commit into
mainfrom
bbr-v3
Open

Add BBRv3 as a selectable congestion control option#22
endel wants to merge 1 commit into
mainfrom
bbr-v3

Conversation

@endel
Copy link
Copy Markdown
Owner

@endel endel commented Apr 19, 2026

Summary

Implements a faithful BBRv3 (draft-cardwell-iccrg-bbr-congestion-control-03) alongside the existing NewReno and Cubic, selectable via ConnectionConfig.congestion_control = .bbr. Default remains Cubic — BBR is opt-in, with zero per-packet overhead when not selected.

Architecture follows picoquic's bbr.c structure: three-stage onAckBatch pipeline, seven-state machine with four event-driven ProbeBW sub-states, full lower-bound dynamics, BBRLossThresh-gated inflight_hi, ECN EWMA, ACK aggregation, recovery state.

What's in here

Core:

  • src/quic/bbr.zig (~1080 lines): Bbr struct, state machine, model estimators, pacing/cwnd computation.
  • src/quic/delivery_rate.zig (~210 lines): RateSampler per RFC 9002 §B / draft-cheng-iccrg-delivery-rate-estimation.
  • src/quic/congestion.zig: Algorithm enum + CongestionControl tagged union over NewReno/Cubic/Bbr with inline else dispatch; AckContext extended with prior_bytes_in_flight, newly_acked_bytes, newly_lost_bytes, largest_acked_pn; Pacer.setPacingRate(bps).
  • src/quic/ack_handler.zig: per-packet snapshot fields on SentPacket; PacketHandler.rate_sampler + rate_sampling_enabled flag.
  • src/quic/connection.zig: union dispatch; cc_algorithm field preserved across migration; rate-sampling enabled only when .bbr.

Docs:

  • SPEC/9002_BBR.md: architecture, state machine, caveats.
  • SPEC/STATUS.md: row added to RFC 9002 table.

State machine

Startup ──bw plateau / loss > BBRLossThresh / RTT excess─▶ Drain
Drain   ──inflight ≤ BDP─▶ ProbeBW_Down

ProbeBW_Down   ──inflight ≤ (1-headroom)·BDP─▶ ProbeBW_Cruise
ProbeBW_Cruise ──≥1 round elapsed─▶ ProbeBW_Refill
ProbeBW_Refill ──one round (resets bw_lo, inflight_lo)─▶ ProbeBW_Up
ProbeBW_Up     ──inflight ≥ inflight_hi / >2 rounds─▶ ProbeBW_Down

(any non-Startup state) ──min_rtt stale (5s)─▶ ProbeRTT
ProbeRTT       ──200ms drained─▶ ProbeBW_Down (or Startup if !filled_pipe)

Performance

rps median (loopback HTTP/3) Δ vs main
Pre-BBR main (bb61b7e) 21,010 baseline
This branch (default Cubic) 20,995 −0.07%

Within run-to-run loopback variance (5–10%). bench-codec identical within sub-ns noise. Per-packet rate-sampler overhead is gated behind rate_sampling_enabled so non-BBR connections pay nothing.

Caveats (documented in SPEC/9002_BBR.md)

  • BBRRaiseInflightHiSlope uses a per-round approximation rather than the draft's per-ack slope.
  • CRUISE uses simple "≥1 round elapsed" rather than picoquic's randomized timer + Reno coexistence quota. Acceptable on links not sharing bottleneck with Reno; revisit if fairness matters.
  • No qlog instrumentation yet for BBR-specific state.
  • Interop binaries don't yet have --cc bbr CLI flag (default Cubic).

Test plan

  • zig build test — 551/551 pass (including 19 new BBR tests + 6 union-dispatch parity tests + 4 sampler tests + 3 connection-level algorithm-selection tests).
  • zig build — all 20+ executables build clean.
  • bench-codec (pure CPU) — identical to main within sub-ns noise.
  • bench (loopback HTTP/3) — median rps within 0.07% of main.
  • Cross-impl interop with .bbr selected (deferred — needs --cc bbr flag on interop binaries first).
  • qlog capture from a long transfer to verify state transitions Startup → Drain → ProbeBW (deferred — needs qlog instrumentation).

Implements draft-cardwell-iccrg-bbr-congestion-control-03 alongside the
existing NewReno and Cubic, selectable via
ConnectionConfig.congestion_control. Architecture follows picoquic's
bbr.c structure: three-stage onAckBatch pipeline (model → state →
control), seven-state machine with four event-driven ProbeBW sub-states
(Down → Cruise → Refill → Up), max-BW + min-RTT filters with separate
ProbeRTT stamp, lower bounds (bw_lo, inflight_lo) reset at REFILL,
BBRLossThresh-gated inflight_hi reduction, ECN EWMA alpha, ACK
aggregation extra_acked, recovery state with packet conservation.

Supporting changes:

- congestion.CongestionControl tagged union over NewReno/Cubic/Bbr with
  inline-else dispatch; AckContext extended with prior_bytes_in_flight,
  newly_acked_bytes, newly_lost_bytes, largest_acked_pn so BBR has the
  inputs it needs without per-packet tracking.

- delivery_rate.RateSampler (RFC 9002 §B / draft-cheng) with per-packet
  snapshot fields on SentPacket, gated by
  PacketHandler.rate_sampling_enabled so non-BBR connections pay zero
  per-send/per-ack overhead.

- Pacer.setPacingRate(bps) for BBR's model-driven pacing alongside the
  existing setBandwidth(cwnd, rtt) used by NewReno/Cubic; cc.updatePacer
  dispatches the right path.

- Migration resets preserve cc_algorithm so the user-chosen CC survives
  address rebinding.

Test coverage: 551/551 pass. New tests cover BBRLossThresh both
directions, ProbeRTT actually firing (separate min-stamp fix), all 4
ProbeBW sub-state transitions, inflight_hi growth in Up, ECN EWMA
threshold crossing, persistent congestion preserves model, PTO recovery
exit lifts inflight_hi, send_quantum scaling, CRUISE headroom, bdp uses
bounded bw, path-change reset.

Performance: bench-codec identical to main (within sub-ns noise);
loopback HTTP/3 bench median 20,995 rps vs main 21,010 rps (-0.07%,
within 5-10% run-to-run loopback variance).

Default remains Cubic. See SPEC/9002_BBR.md for architecture details
and outstanding caveats (qlog instrumentation, interop --cc CLI flag).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant