Skip to content

[wip/draft] fix(proto): immediately retransmit in-flight data when a path is abandoned#770

Draft
Frando wants to merge 1 commit into
mainfrom
Frando/abandon-retransmit
Draft

[wip/draft] fix(proto): immediately retransmit in-flight data when a path is abandoned#770
Frando wants to merge 1 commit into
mainfrom
Frando/abandon-retransmit

Conversation

@Frando

@Frando Frando commented Jul 24, 2026

Copy link
Copy Markdown
Member

Description

Experiment / draft

Change: When a path is abandoned, all in-flight packets on that path are now immediately declared as lost, causing their retransmittable frames to be queued for retransmission on another active path.

Previously, in-flight packets remained in the abandoned path's sent_packets until the PathDrained timer fired. That timer is only armed once we receive the peer's own PATH_ABANDON frame for this path, and then runs for 3*PTO. This means stream data is not retransmitted for at least 3*PTO when the previously-active path dies.

Breaking Changes

Notes & open questions

I had claude compare to picoquic and spec (not checked myself yet):

This matches picoquic's behavior: their picoquic_retransmit_demoted_path immediately walks a failing/demoted path's outstanding queue rather than waiting for a timer. It's also spec-permitted: draft-ietf-quic-multipath section 5.7 explicitly leaves post-abandonment retransmission timing and strategy to the implementation; the only normative requirement (section 3.4.3) is that packets are eventually considered lost by the time path state is deleted, which the old PathDrained-gated behavior already satisfied, just slowly.

Change checklist

  • Self-review.
  • Documentation updates following the style guide, if relevant.
  • Tests if relevant.
  • All breaking changes documented.
  • This PR was created by a human that thought critically about the
    proposed change and wrote an as clear and concise description as
    they could.
  • This PR isn't slop, and is carefully crafted to do have the
    intented effect.
  • cargo make passes locally.

…doned

When a path is abandoned, all in-flight packets on that path are now
immediately declared as lost, causing their retransmittable frames to be
queued for retransmission on another active path.

Previously, in-flight packets remained in the abandoned path's
sent_packets until the PathDrained timer fired. That timer only arms
once we receive the peer's own PATH_ABANDON frame for this path (not an
ACK of ours - the incoming PATH_ABANDON handler), 3*PTO after that; and
that in turn requires some live path to carry the frame at all. In the
meantime, loss detection kept cycling on the dead path via PTO probes
that could never be ACKed, and the actual stream data was never
retransmitted on the new active path.

This caused multi-second stalls (up to ~20s observed) after path
migration: the application's stream data was stuck on the abandoned path
while a perfectly good new path was available.

The LossDetection timer on the abandoned path is now also stopped, since
all packets are declared lost immediately and there is nothing left to
detect.
@github-actions

Copy link
Copy Markdown

Documentation for this PR has been generated and is available at: https://n0-computer.github.io/noq/pr/770/docs/noq/

Last updated: 2026-07-24T12:22:21Z

@github-actions

Copy link
Copy Markdown

Performance Comparison Report

630db780d89552f6a8dfbab1ab6f468d1158745d - artifacts

Raw Benchmarks (localhost)

Scenario noq upstream Delta CPU (avg/max)
large-single 5238.3 Mbps 7883.7 Mbps -33.6% 97.9% / 150.0%
medium-concurrent 5324.4 Mbps 7467.7 Mbps -28.7% 92.9% / 99.0%
medium-single 3352.3 Mbps 4688.9 Mbps -28.5% 92.3% / 100.0%
small-concurrent 3726.5 Mbps 5229.2 Mbps -28.7% 98.0% / 153.0%
small-single 3327.2 Mbps 4749.5 Mbps -29.9% 97.5% / 153.0%

Netsim Benchmarks (network simulation)

Condition noq upstream Delta
ideal 3072.9 Mbps 4134.7 Mbps -25.7%
lan 782.4 Mbps 810.3 Mbps -3.5%
lossy 69.9 Mbps 55.9 Mbps +25.0%
wan 83.8 Mbps 83.8 Mbps ~0%

Summary

noq is 28.8% slower on average

@flub

flub commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Declaring all in-flight packets as lost when the path is abandoned is bad I think. These in-flight packets may still arrive. So you're potentially wasting a lot of resources. This should follow normal retransmission and loss detection as closely as possible IMHO. The problem is of course that loss is only declared once a new packet is received, which won't happen on an abandoned path. I've long been thinking that when the PTO fires for an abandoned path is the right time to start re-transmitting in-flight data on a new path.

I also kind of wanted this to be more progressive, so that not all data is re-sent on a different path immediately, but rather more based on sent-time. That is of course not ideal either. Plus that's hard, the PTO timer only fires for the last packet sent. I almost want to set a per-packet PTO timer once path is abandoned, and each time it first send that packet's data on a different path. But that might just be too expensive.

I looked for an issue and couldn't find any right away, which surprises me because this has been an issue we've been aware off for a while too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🚑 Needs Triage

Development

Successfully merging this pull request may close these issues.

2 participants