Skip to content

fix(flow-entry): add an insertion that will not displace a live flow - #1736

Draft
daniel-noland wants to merge 1 commit into
pr/daniel-noland/fuzz-routingfrom
pr/daniel-noland/fuzz-flow-entry
Draft

fix(flow-entry): add an insertion that will not displace a live flow#1736
daniel-noland wants to merge 1 commit into
pr/daniel-noland/fuzz-routingfrom
pr/daniel-noland/fuzz-flow-entry

Conversation

@daniel-noland

Copy link
Copy Markdown
Collaborator

Fourth of five, stacked on #1735. One commit.

Adds an insertion that will not displace a live flow, and the test for it.
Displacing a flow takes the other half of its pair with it; the two halves have
different keys, so nothing displaces the partner in its own right, and it is
left live mapping a translation whose allocation has returned to the pool.

Small, but it is the commit that most needed adapting to a main that has moved
on, and it is worth knowing how it failed. It cherry-picked with no conflict,
then failed to compile because FlowInfo::related_pair became fallible, then
compiled and failed with InvalidPair("One of the flows must be the initiator") — an invariant main gained after this was written, which the test
was violating by flagging neither half. The forward half is now marked
INITIATOR, matching the sibling test in concurrent_fuzz.rs.

Three distinct failure modes behind one clean cherry-pick. With CI unavailable
this only surfaced because everything was run locally, which is the argument for
not trusting a clean apply on any of these branches.

Verified locally: dataplane-flow-entry 14/14, fmt --check clean.

🤖 Generated with Claude Code

@daniel-noland daniel-noland added the dont-merge Do not merge this Pull Request label Aug 17, 2026
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 28b10beb-cbb9-45a1-bfb0-2d85c70c022c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.53571% with 5 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
flow-entry/src/flow_table/table.rs 95.53% 3 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/fuzz-flow-entry branch from c806fa7 to 731db9d Compare August 18, 2026 03:07
@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/fuzz-flow-entry branch from 731db9d to 420ecb8 Compare August 18, 2026 20:23
@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/fuzz-flow-entry branch from 420ecb8 to dfdf917 Compare August 18, 2026 20:31
@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/fuzz-flow-entry branch from dfdf917 to 0c36ba2 Compare August 18, 2026 20:38
@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/fuzz-flow-entry branch from 0c36ba2 to 5d59ca1 Compare August 18, 2026 23:17
Two packets of one new flow can reach a NAT stage at the same time.
Packets of a 5-tuple usually land on one core, but nothing guarantees
that, and each packet builds a pair of its own before inserting it.

With a plain insert, whoever gets there second displaces the other's
forward flow -- and only that half. The two reverse keys carry the
allocations that made them, no two allocations agree, so the reverses
never collide and the loser's is never displaced along with its partner.
It stays in the table, live, mapping a translation whose allocation goes
back to the pool as soon as the displaced forward half is collected.
Return traffic for that public pair, once it has been handed out again,
is then translated for whoever held it before.

Two changes, either of which leaves a hole on its own.

insert_if_absent stands aside when a live flow already holds the key,
and reports that flow so the caller can go on with it. Arbitrating on
one key is enough, because racing packets of a single flow share their
forward key by construction: only whoever wins it inserts a reverse. A
flow that is present but no longer live is displaced as before, since it
is a corpse its timer has not swept yet and standing aside for one would
drop a packet that could have replaced it.

Displacing a flow now also invalidates the other half of its pair,
wherever it happens. The race is not the only way to reach the orphan:
the flow timer expires the two halves separately, so an expired forward
half could be replaced by an ordinary insert while its partner was still
live. That path needs no concurrency at all.

Three tests, each of which fails against the code without its guard: a
live flow keeps its key, a dead one does not, and displacing a flow
takes its partner with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Daniel Noland <daniel@githedgehog.com>

Rebased onto a `related_pair` that is fallible and requires exactly one
half of the pair to carry `INITIATOR`; both are invariants main gained
after this was written. The test now marks the forward half and unwraps,
matching the sibling test in `concurrent_fuzz.rs`.
@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/fuzz-flow-entry branch from 5d59ca1 to 809fc6d Compare August 19, 2026 06:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dont-merge Do not merge this Pull Request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant