Files
amethyst/quic
Vitor Pamplona 707fcee5b6 fix(quic): rotate DCID off failed CID on path validation timeout
Pre-fix, PathValidator.checkValidationTimeout queued a
RETIRE_CONNECTION_ID for the failed sequence number while leaving
QuicConnection.destinationConnectionId stamping that same CID. The
strict servers (quic-go / picoquic / msquic / mvfst) processed the
RETIRE, dropped their routing entry, then closed us with
PROTOCOL_VIOLATION the next time a packet arrived stamped with
the just-retired CID — visible in qlog as two RETIRE_CONNECTION_ID
frames within ~500 ms followed by "retired connection ID N, which
was used as the Destination Connection ID on this packet".

Reproducer: setting proactiveDcidRotationMillis=4_000L on
QuicConnection drove the trigger every 4 s; rebind-port vs quic-go
then failed at ~10 s with the close above. Reverted in this commit;
the experiment fields are gone.

The fix splits the timeout outcome into three cases:

  - NotTimedOut         — budget hasn't elapsed.
  - RecoveredOnSpare    — rotated active to the lowest spare CID;
                          queued RETIRE for the failed seq; the
                          QuicConnection wrapper synchronously
                          updates destinationConnectionId so the
                          next outbound stamps the new CID, atomic
                          under streamsLock with the validator
                          state change.
  - StuckOnFailedCid    — no spare available; KEEP the failed seq
                          active and DO NOT queue retire. The
                          writer keeps stamping the unvalidated
                          CID; if the path is genuinely dead the
                          connection idles out, and once a
                          NEW_CONNECTION_ID arrives the next
                          trigger rotates cleanly.

After the fix, rebind-port vs quic-go fails at the 60 s test
timeout with server-side trigger=idle_timeout (the Task 2 issue —
strict servers gate on fresh DCID at new src port, which we can't
synchronize with the sim's rebind cadence) instead of the
PROTOCOL_VIOLATION close.

Tests:
  - PathValidatorTest:
      validationTimeoutAfter3PtoTransitionsToFailedAndRetiresFailedCidWithSpare
      timeoutWithoutSpareKeepsFailedSeqActiveAndDoesNotRetire
      twoConsecutiveFailedValidationsRetireAllAbandonedSequencesWithSpare
  - ClientPathMigrationTest:
      backToBackSuccessfulMigrationsRetireExactlyOnePerRotationAndStampNewDcid
      validationTimeoutWithSpareRotatesDcidAndRetiresFailedSeq
      validationTimeoutWithoutSpareKeepsActiveCidAndDoesNotRetire

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:40:36 -04:00
..