feat: forward-port per-source RX demux (v0.7.3) onto 0.8.0#137
feat: forward-port per-source RX demux (v0.7.3) onto 0.8.0#137JustinKovacich wants to merge 2 commits into
Conversation
The SOME/IP unicast header carries no instance id, so on a shared subnet the sender's source address is the only way to attribute an event to a device. The source was already received (ReceivedMessage.source) but dropped before forwarding; carry it on ClientUpdate::Unicast instead.
385f44c to
a683029
Compare
fee01d1 to
2788e95
Compare
On a shared subnet, several devices send the same (service, method) under one fixed instance id; a single per-key receive counter collides their interleaved sequences into spurious WrongSequence. Split the registry into endpoint-agnostic profile config, per-(source,key) receive state, and per-key transmit state. check() now takes the source address; protect() is unchanged. Reset a source's receive state on its reboot.
2788e95 to
4b1d095
Compare
There was a problem hiding this comment.
Pull request overview
Forward-ports the per-source RX demux work onto the 0.8.0 codebase by preserving sender identity on unicast updates and keying E2E receive state per source, while also expanding the crate’s no_std/bare-metal tooling, transport surface, and examples to support/verify these paths across targets.
Changes:
- Preserve unicast sender identity by adding
source: SocketAddrtoClientUpdate::Unicastand forwarding it from the client run loop. - Key E2E RX counter state per
(source, key)with bounded receive-state storage and areset_sourcehook for sender reboots. - Broaden bare-metal/no_std support & verification (buffer pools, callback transport/mailbox runtime pieces, embassy-net adapter crate, probes, docs/tests).
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tools/size_probe/Cargo.toml | Adds standalone no_std staticlib probe manifest for size/type-layout measurement. |
| tools/size_probe/Cargo.lock | Locks probe dependencies for repeatable measurement builds. |
| tools/capture_type_sizes.sh | Script to capture -Zprint-type-sizes for host/thumb and summarize results. |
| tests/no_alloc_server_witness.rs | Adds no-alloc witness for server-side static subscription handle hot paths. |
| tests/data/vsomeip-offerer/subscriber.json | Adds vsomeip subscriber config for TX-direction SD conformance testing. |
| tests/data/vsomeip-offerer/subscriber.cpp | Adds vsomeip subscriber binary used by SD compatibility tests. |
| tests/data/vsomeip-offerer/README.md | Documents building/running the vsomeip conformance Docker image and tests. |
| tests/data/vsomeip-offerer/offerer.json | Updates vsomeip offerer config (multicast group alignment commentary). |
| tests/data/vsomeip-offerer/offerer.cpp | Updates/minimizes offerer implementation and logs for test scraping. |
| tests/data/vsomeip-offerer/entrypoint.sh | Adds entrypoint templating logic for vsomeip role configs. |
| tests/data/vsomeip-offerer/Dockerfile | Builds pinned vsomeip + offerer/subscriber binaries for conformance testing. |
| tests/data/vsomeip-offerer/CMakeLists.txt | Builds both vsomeip helper binaries against installed vsomeip3. |
| tests/buffer_pool.rs | Adds tests for the new fixed-capacity BufferPool claim/release behavior. |
| tests/bare_metal_example_builds.rs | Canary test documenting that bare-metal example crates must compile. |
| tests/bare_metal_client.rs | Witness test for constructing/running client without client-tokio using static channels. |
| tests/bare_metal_client_local.rs | Witness test for local-spawner client construction (new_with_deps_local). |
| src/traits.rs | Makes SD helpers more no_std-friendly (visitor APIs, core net types, default no-op hook). |
| src/server/service_info.rs | Gates std-only service/event-group info types; uses core::net where possible. |
| src/server/README.md | Updates server docs for the new announcement loop spawning API and subscription APIs. |
| src/server/error.rs | Expands server error taxonomy (Transport/Capacity/InvalidUsage) with cfg(std) IO. |
| src/raw_payload.rs | Switches SD endpoint/service extraction to visitor pattern for no_std compatibility. |
| src/protocol/sd/test_support.rs | Aligns test payload SD header construction with core types and new trait surface. |
| src/protocol/sd/options.rs | Minor doc fix to avoid broken intra-doc link formatting. |
| src/protocol/sd/header.rs | Minor numeric literal formatting cleanup in tests. |
| src/protocol/message_type.rs | Fixes wire encoding for message type field (Response/Error bytes) + regression test. |
| src/protocol/message_id.rs | Moves/adds Debug impl for MessageId (formatting consistency noted in review). |
| src/protocol/header.rs | Adds upper_header_bytes() accessor and restores WireFormat impl placement. |
| src/protocol/byte_order.rs | Adds clippy allow for float cmp in byte-level roundtrip tests. |
| src/log.rs | Introduces internal logging shim to avoid tracing/alloc requirements on some no_std targets. |
| src/heapless_payload.rs | Adds alloc-free PayloadWireFormat implementation for bare-metal payload handling. |
| src/e2e/mod.rs | Makes registry/state available beyond std and re-exports registry constants/types. |
| src/e2e/e2e_protector.rs | Formatting-only test constant literal updates. |
| src/e2e/e2e_checker.rs | Routes warnings through logging shim; formatting-only test updates. |
| src/e2e/crc.rs | Routes traces through logging shim; formatting-only test updates. |
| src/client/session.rs | Replaces HashMap with bounded FnvIndexMap for session tracking; saturation behavior docs/tests. |
| src/client/service_registry.rs | Makes service registry heap-free via FnvIndexMap, adds capacity error path + tests. |
| src/client/error.rs | Refines client error taxonomy (Capacity/Transport/Shutdown) and adds display regression tests. |
| src/client/bind_dispatch.rs | Adds spawner-agnostic bind+spawn abstraction shared by Send and !Send client constructions. |
| src/buffer_pool.rs | Adds fixed-capacity buffer pool with RAII leases for no-alloc socket loops. |
| src/bare_metal_runtime/transport.rs | Adds callback-driven transport/timer implementations for bare-metal runtime integration. |
| src/bare_metal_runtime/mod.rs | Adds bare-metal runtime module surface exports and feature-gated runtime glue. |
| src/bare_metal_runtime/mailbox.rs | Adds shared RX mailbox for callback transport (bounded slots/capacity) + tests. |
| simple-someip-embassy-net/src/socket.rs | Adds embassy-net TransportSocket adapter with named futures for zero-alloc send/recv. |
| simple-someip-embassy-net/src/lib.rs | New no_std adapter crate surface and MTU guidance. |
| simple-someip-embassy-net/README.md | Documents adapter usage and status. |
| simple-someip-embassy-net/Cargo.toml | Adds new adapter crate manifest with pinned embassy-net deps and host test deps. |
| README.md | Updates crate README for 0.8 feature split, transport traits, and run-loop spawning requirements. |
| examples/embassy_net_client/Cargo.toml | Adds host example wiring simple-someip through the embassy-net adapter. |
| examples/discovery_client/src/main.rs | Updates example to spawn the client run-loop future returned by Client::new. |
| examples/discovery_client/Cargo.toml | Updates example to depend on client-tokio (constructor availability). |
| examples/client_server/src/main.rs | Updates hybrid example to new SD announcement loop API and server config shape. |
| examples/client_server/Cargo.toml | Updates example to client-tokio/server-tokio features. |
| examples/bare_metal_server/src/main.rs | Adds host-side example for no-tokio bare-metal server construction/run. |
| examples/bare_metal_server/Cargo.toml | Adds bare-metal server example manifest with appropriate feature pins. |
| examples/bare_metal_client/Cargo.toml | Adds bare-metal client example manifest with appropriate feature pins. |
| docs/simple_someip/plans/2026-06-17-pr126-polled-port-handoff.md | Adds planning/handoff notes for future polled bare-metal port work. |
| docs/simple_someip/plans/2026-06-10-pr1-124-followups-design.md | Adds design doc covering callback shape, docs, tests, and error-handling decisions. |
| Cargo.toml | Expands workspace members, adds feature split (*-tokio), adds bare-metal runtime deps, excludes probe. |
| .gitignore | Updates ignore list for probe targets and generated Claude artifacts. |
| .config/nextest.toml | Adds nextest serialization groups to prevent static pool exhaustion in parallel runs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Folded into #138. The 0.8.0 forward-port stack was consolidated via a linear rebase of the whole stack onto |
…solidated branch
CI gates that never ran on the spine (gated behind the failing Format &
Lint job) surfaced once the branch was rebased onto main:
- protocol/message_id: `{:#02X}` → `{:#06X}`. Under the `0x` alternate
flag the width-2 spec has no effect (latest-nightly
clippy::unused_format_specs); u16 IDs want 4 hex digits.
- buffer_pool: add `;` to the multi-line `const { assert!(..) }`
(clippy::semicolon_if_nothing_returned, exposed once rustfmt reflowed
the one-liner).
- e2e: export `E2E_RX_STATE_CAP` alongside its sibling `E2E_REGISTRY_CAP`
(a #137 forward-port oversight — `E2ERegistry`'s public docs link it).
- docs: demote intra-doc links whose targets are private or
feature-gated to code spans — `SUBSCRIBERS_PER_GROUP` (pub(crate)),
`API_SCRATCH_CAP` (private), and `publish_raw_event_to` (`_alloc`-only,
unresolved in no-alloc doc builds).
- rustfmt over the branch under rustfmt 1.9.
Verified green: fmt --check; all 5 clippy lanes (incl. nightly
bare-metal-runtime); all 5 doc lanes (-D warnings); 556 all-features lib
tests; client_server 11/11 (single-threaded); no_alloc_witness;
bare_metal_e2e 9/9; thumbv7em + build-std=core bare_metal builds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…solidated branch
CI gates that never ran on the spine (gated behind the failing Format &
Lint job) surfaced once the branch was rebased onto main:
- protocol/message_id: `{:#02X}` → `{:#06X}`. Under the `0x` alternate
flag the width-2 spec has no effect (latest-nightly
clippy::unused_format_specs); u16 IDs want 4 hex digits.
- buffer_pool: add `;` to the multi-line `const { assert!(..) }`
(clippy::semicolon_if_nothing_returned, exposed once rustfmt reflowed
the one-liner).
- e2e: export `E2E_RX_STATE_CAP` alongside its sibling `E2E_REGISTRY_CAP`
(a #137 forward-port oversight — `E2ERegistry`'s public docs link it).
- docs: demote intra-doc links whose targets are private or
feature-gated to code spans — `SUBSCRIBERS_PER_GROUP` (pub(crate)),
`API_SCRATCH_CAP` (private), and `publish_raw_event_to` (`_alloc`-only,
unresolved in no-alloc doc builds).
- rustfmt over the branch under rustfmt 1.9.
Verified green: fmt --check; all 5 clippy lanes (incl. nightly
bare-metal-runtime); all 5 doc lanes (-D warnings); 556 all-features lib
tests; client_server 11/11 (single-threaded); no_alloc_witness;
bare_metal_e2e 9/9; thumbv7em + build-std=core bare_metal builds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Forward-ports the two v0.7.3 feature commits (
cb6e3bd,662662b) onto the 0.8.0 spine, so the 0.8.0 release doesn't regress per-source RX demux. The 0.7.3 release itself lives only on therelease/0.7.2line (PR #136); this is its 0.8.0 equivalent, the sibling of #135 (which forward-ported 0.7.2).What
ClientUpdate::Unicastnow carriessource: SocketAddr. The source was already received onReceivedMessage.sourcebut dropped via..before forwarding. On a shared subnet the SOME/IP header has no instance id, so the source address is the only demux key. (Clean cherry-pick modulo thesend→send_nowrename from Reduce async state and static pool memory in simple_someip to prevent Embassy arena exhaustion #125.)RX E2E counter state is keyed per
(source, key).E2ERegistrysplits into endpoint-agnostic profile config + per-(source, key)receive state + per-keytransmit state.check()now takes the source IP;protect()is unchanged (fan-out keeps one TX counter; per-recipient TX lives a layer up). A rebooted source's receive state is reset.Forward-port adaptation (differs materially from the 0.7.3 diff)
The 0.7.3 commit assumed
std::HashMapand a freeprocess_discovery(&Arc<Mutex<E2ERegistry>>, …)function. Neither exists on the 0.8.0 spine, so the port was re-authored against the post-#18/#125 surface:heapless::FnvIndexMap, notHashMap. All three maps are fixed-capacity andconst-constructible (no_std, heap-free). Profile/TX bounded byE2E_REGISTRY_CAP; RX bounded by a newE2E_RX_STATE_CAP(64).E2ERegistryHandlegainedsourceoncheck+ a newreset_source, propagated through all three impls (Arc<Mutex>,StaticE2EHandle,NullE2ERegistry).if rebootedsite (inner.rs), via theR: E2ERegistryHandlehandle — there is noprocess_discoveryto thread a registry through on this spine.discovery_unicast_socket/TransportKind::Unicast); that infrastructure isn't on the 0.8.0 spine and is outside the per-source-E2E feature. Not ported here.Design decision worth a look — RX saturation policy
rx_statesis bounded (E2E_RX_STATE_CAP = 64), unlike the original unboundedHashMap. When full, a brand-new(source, key)can't claim a slot, socheck()falls back to a transient per-call counter: CRC is still validated, only sequence continuity is untracked for that source until a slot frees (reset_source/unregister). A one-shotwarn!fires the first time (mirrors thesession.rssaturation latch). Sizing and this policy are the two things to sanity-check for the target subnet.Verification
cargo clippy --workspace --all-features -- -D warnings -D clippy::pedantic✅cargo clippy --no-default-features --features client,bare_metal(andserver,bare_metal,client,server,bare_metal) pedantic ✅cargo build --target thumbv7em-none-eabihf --no-default-features --features client,bare_metal✅no_alloc_witness(StaticE2EHandle check/protect) — still zero heap alloc on the per-source path ✅distinct_sources_have_independent_e2e_state,reset_source_clears_only_that_source) ✅client_server+bare_metal_e2e+ doctests ✅ (client_serverpasses single-threaded; the parallel run hits the known pre-existing fixture-collision flake)🤖 Generated with Claude Code