Skip to content

Add streaming IAm API with BVLL transport metadata - #3

Open
acedrew wants to merge 4 commits into
mainfrom
feature/streaming-iam-api
Open

Add streaming IAm API with BVLL transport metadata#3
acedrew wants to merge 4 commits into
mainfrom
feature/streaming-iam-api

Conversation

@acedrew

@acedrew acedrew commented Mar 21, 2026

Copy link
Copy Markdown

Summary

  • Adds a TransportMeta struct to carry BVLL framing context (function code, forwarded-from IP/port) through the transport → network → client pipeline
  • Adds an IAmEvent broadcast channel so every IAm is streamed to consumers with full metadata, including BBMD relay duplicates
  • Exposes who_is_stream() (subscribe-then-WhoIs) and iam_events() (passive listener) in the Python bindings

This fixes the downstream edge driver's inability to:

  1. Distinguish original vs BBMD-forwarded IAms (BBMD relay IPs were overwriting correct addresses)
  2. See duplicate IAms (critical diagnostic signal for BBMD misconfiguration)
  3. Access BVLL context needed for cross-subnet routed device address selection

Changes by layer

Layer Files What
Transport port.rs, bip.rs, bip6.rs, mstp.rs, ethernet.rs, sc.rs TransportMeta struct + populate at all ReceivedNpdu sites
Network layer.rs, router.rs Thread transport_meta through ReceivedApdu
Server server.rs Add transport_meta: None to fallback constructions
Client discovery.rs, client.rs IAmEvent struct, iam_tx broadcast channel, iam_events() accessor
Python types.rs, client.rs, rusty_bacnet.pyi PyIAmEvent, PyIAmEventIterator, who_is_stream(), iam_events(), type stubs

Test plan

  • cargo check — full workspace compiles
  • cargo test — all 1703 existing tests pass (backward compatible)
  • Integration test: two localhost clients, A sends WhoIs, B's IAm appears on A's iam_events() with bvlc_function: Some(0x0b)
  • Python test: async for event in await client.who_is_stream(): ... yields IAmEvent with expected fields
  • Container test (campus network): verify Forwarded-NPDU events carry forwarded_from fields

🤖 Generated with Claude Code

acedrew and others added 4 commits March 20, 2026 19:30
Introduces RequestTarget enum (Direct/Routed/ImplicitRouted) so all
client service methods accept routed addresses via `impl Into<RequestTarget>`.
Adds ClientRouterTable auto-populated from I-Am-Router-To-Network, with
resolve_router() for automatic router discovery. Python bindings gain
parse_target() supporting "network:mac" address format and a `router`
keyword-only param on all 32 address-taking methods. Includes unit tests
for parse_target and ClientRouterTable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two issues caused routed confirmed requests to time out:

1. The NPDU destination filter in layer.rs (line 143) discarded all
   non-broadcast messages with a DNET, including legitimate application-
   layer responses to our routed requests. Since network-layer messages
   are already handled earlier in the dispatch loop, the remaining
   messages are all APDUs — which should be accepted regardless of
   DNET, as a non-router can be the destination of a routed reply.

2. The non-BBMD FORWARDED_NPDU handler in bip.rs used the UDP sender
   address as source_mac instead of the originating IP from the BVLL
   header. When a response came through a BBMD relay, the source_mac
   wouldn't match the router_mac registered in the TSM, causing a
   correlation failure. Now uses originating_ip consistently with the
   BBMD code path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add routed_test.rs: 8-test integration binary for campus simulator
  (router discovery, direct reads, routed reads to multiple networks,
  error round-trip, and implicit routing via auto-discovery)
- Auto-resolve ImplicitRouted targets in confirmed_request() and
  unconfirmed_request() instead of requiring callers to pre-resolve

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a broadcast channel for raw IAm events so downstream consumers can
see every IAm as it arrives (including BBMD relay duplicates) with full
BVLL context. This fixes the edge driver's inability to distinguish
original vs forwarded IAms and its reliance on the last-write-wins
device table.

Transport layer:
- Add TransportMeta struct (bvlc_function, forwarded_from_ip/port)
- Populate in BIP transport at all 5 BVLL message handlers
- Thread through ReceivedNpdu → ReceivedApdu → dispatch

Client layer:
- Add IAmEvent struct with IAm fields + BVLL metadata + timestamp
- Add iam_tx broadcast channel (follows cov_tx pattern)
- Send IAmEvent on every IAm, alongside existing device_table.upsert()
- Add iam_events() public accessor

Python bindings:
- Add PyIAmEvent (frozen pyclass) and PyIAmEventIterator (async iter)
- Add who_is_stream() — subscribe first, send WhoIs, return iterator
- Add iam_events() — passive listener, no WhoIs sent
- Add type stubs for all new types and methods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant