Fixed packet_threshold spuriously fast-retransmits under rate-scaled reordering displacement — consider RACK-style adaptation
## Summary
Loss detection's packet-count threshold (`TransportConfig::packet_threshold`, default 3 per RFC 9002) compares packet-number displacement, but reordering displacement is a *time* phenomenon: at a fixed reordering delay, displacement in packet numbers scales linearly with send rate (~130 PN per ms at 1.6 Gbit/s). So for any fixed threshold there is a rate above which benign reordering is declared loss, triggering spurious fast-retransmit storms and congestion response. Linux TCP handles this with adaptive reordering detection (RACK-TLP, `tcp_reordering` adapts 3→300); RFC 9002 §6.1.1 explicitly permits adapting the threshold.
## Measured dose-response
Same setup as https://github.com/quinn-rs/quinn/issues/2710 (197 ms real path, BBR, 512 MiB transfers, netem `delay 5ms reorder 25% 50%` — with the dedup-window issue from that report patched out so this effect is isolated):
| packet_threshold | goodput | stats().path.lost_packets |
|---|---|---|
| 3 (default) | 125 Mbit/s | ~65% of sent |
| 300 | 306 Mbit/s | ~64% |
| 1000 | 563 Mbit/s | ~52% |
| effectively ∞ | **632–710 Mbit/s** | **~14%** |
| (clean path reference) | 828 Mbit/s | ~1% |
With the threshold effectively disabled, recovery is purely time-based (~1.125×RTT) and remained healthy under genuine loss in our testing (1% and 10% netem loss rows unaffected) — for bulk transfer the packet-count path adds little except reorder-fragility.
## Secondary effect worth knowing
With defaults, the spurious-retransmit storm can escalate to a connection-fatal abort: the stream reassembler's anti-DoS cap (`assembler.rs`, >1024 buffered chunks after defragment) returns `TransportError::INTERNAL_ERROR("too many gaps in stream buffer")` and kills the connection. We observed this repeatedly under ±10 ms jitter; it disappears once the spurious losses do.
## Suggestion
An adaptive reordering threshold — e.g. grow `packet_threshold` when a packet declared lost by packet-count is subsequently ACKed (spurious retransmit detected), RACK-style — would fix this class without configuration. Short of that, documenting "set a large `packet_threshold` on reordering-prone / high-rate paths; time-based detection carries recovery" would help others hitting quinn-vs-TCP gaps like #2262.
Full write-up: https://github.com/length967/haul/blob/main/haul/wan-test/results-realworld-2026-07-05.md — happy to discuss/PR.
关闭于 2026-07-05 1 条评论