Repository navigation
Conversation
…scoped one A dual-stack listen socket receives a responder's IPv4 copy of a message, from a v4-mapped sender with scope 0, and its byte-identical IPv6 copy, from a link-local sender with the interface's scope. Suppressing on the payload alone dropped the IPv6 copy, the only one whose link-local AAAA records get a scope, so they were never cached scoped. RFC 6762 section 20 treats a dual-stack host as on two logical segments, so the copies are separate arrivals. Key suppression on the scope the records would get as well: unscoped senders suppress each other as before, and a scoped sender's copy is keyed on its payload and scope.
|
Thanks for contributing! A quick note: this project is in the process of moving from LGPL-2.1 to Apache 2.0, and may keep LGPL-2.1-or-later as an OR option so GPL-2.0-only projects can keep using the library, see #1835. By continuing with this pull request you agree that this new contribution is offered under both Apache 2.0 and LGPL-2.1-or-later, so it is covered under either outcome. This notice does not affect your previous contributions. If you would like to consent to relicensing those as well, please post the consent statement on #1835; silence is never treated as consent for past work. If offering this contribution under these licenses does not work for you, no hard feelings; reply with the exact phrase |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1926 +/- ##
=======================================
Coverage 99.87% 99.87%
=======================================
Files 33 33
Lines 3913 3917 +4
Branches 568 568
=======================================
+ Hits 3908 3912 +4
Misses 3 3
Partials 2 2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Summary
On a dual-stack host, the
::listen socket receives a responder's IPv4 copy of a message, from a v4-mapped sender with scope 0, and its IPv6 copy, from a link-local sender with the interface's scope. The two are byte-identical and usually arrive a few milliseconds apart, IPv4 first. Duplicate suppression compares the payload only, so the IPv6 copy is dropped, although it's the only copy whose link-local AAAA records get a scope. The cache never holds a scoped record, andparsed_scoped_addresses()returnsfe80::…with no%<idx>(#1567, the case #1764 left open). The measurements behind this are in #1927.This PR makes duplicate suppression take into account the scope the packet's records would get. Copies from senders without a scope (IPv4, v4-mapped, global IPv6) still suppress each other as before. A copy from a scoped sender is keyed on its payload and scope together, so it is neither suppressed by an unscoped copy nor suppresses one, and its repeats are still suppressed.
Details
addrs[3]for IPv6 senders, 0 otherwise), not the address family. Copies that would scope their records the same way produce identical records, so suppressing them loses nothing, and it avoids a string test for v4-mapped senders on every packet. Scoped copies use a(payload, scope)key in the existing_recent_packetsdict, so the bound and the eviction are unchanged.Test plan
New
test_guard_against_duplicate_packets_per_sender_scopeintests/test_listener.py. A response carrying a link-local AAAA record is fed from a v4-mapped sender, then from a link-local IPv6 sender: the cache must hold both a scope-0 and a scope-2 record. Repeats of each copy are then still suppressed. It fails on master ({0} == {0, 2}) and passes here.Full suite on Linux (Docker, Python 3.14): 525 passed, in both the pure-Python build (
SKIP_CYTHON=1) and the Cython build (REQUIRE_CYTHON=1, listener compiled).test_integration_with_listener_ipv6fails in some runs in this container on master as well, as "Network is unreachable" for IPv6 multicast.pre-commit runon the changed files: all hooks pass.Microbenchmark of
_process_datagram_at_time, Cython build, master against this branch, three interleaved rounds (median ns/packet):Real network: a Linux 6.12 host on a link with embedded responders that answer over both IPv4 and IPv6, with an
AsyncServiceBrowserfor their service type. On master, a 300 s browse logged 43 copies from the responders'fe80::addresses dropped as duplicates, and no link-local address was ever scoped. On this branch, every responder whose answer arrived over IPv6 multicast hadfe80::…%2inparsed_scoped_addresses()within 10 s. Those whose only answers were IPv4 unicast stayed unscoped (see below).Not in this PR
A responder that only ever answers by IPv4 unicast (the first, QU, query) still leaves its link-local AAAA records unscoped, since an IPv4 packet has no scope. Scoping those from the receiving interface needs per-interface sockets (#1568) or
IP_PKTINFO.🤖 Generated with Claude Code