Skip to main content

Module layer

Module layer 

Source
Expand description

NetworkLayer for local BACnet packet assembly and dispatch.

The network layer wraps a transport and provides APDU-level send/receive by handling NPDU encoding/decoding. This is a non-router implementation: it does not forward messages between networks, but it can address remote devices through local routers via NPDU destination fields (DNET/DADR).

§Receive-queue admission

NetworkLayer and BACnetRouter use the same drop-arriving policy for application delivery. Each receive queue holds 256 items. Admission never waits for a consumer and never evicts an older queued item. A tracked NetworkLayer APDU queue and an opted-in control queue have independent capacities, so saturation of either does not stall admission to the other. All router ports share one local APDU queue; its saturation does not stop forwarding or inline network-message handling.

The raw NetworkLayer receiver is different: ApduReceiver has no queue of its own (#1713). It decodes the transport’s NPDUs in the task that polls it, so network controls flow only while it is polled: while the consumer is busy in an inline await they wait in the transport’s queue, which adds latency, not a deadlock. That queue is the only buffer. It holds 256 NPDUs on B/IP, B/IPv6, BACnet/SC, Ethernet and loopback, and 64 on MS/TP, whose deliveries were buffered 64 + 256 deep before. Under overload it bounds memory and the transport counts what it drops: B/IP and B/IPv6 as npdu_channel_full in receive_counters(), MS/TP as delivery_drops in its diagnostics’ MAC counters, BACnet/SC in npdu_drop_counts(), and loopback in receive_drops(). Ethernet has no drop counter, only throttled warnings.

§Raw and tracked receivers

Receiver kindEntry pointsCapacityPer-source quotaAccounting
Raw APDU, NetworkLayerNetworkLayer::start (ApduReceiver)The transport’s queueNoneDrops counted by the transport; no admission snapshot
Raw APDU, routerBACnetRouter::start with RouterOptions::new256NoneFull/Closed counted internally; no admission snapshot or depth/high-water tracking
Tracked APDUNetworkLayer::start_with_admission, RouterOptions::track_admission25616 queued APDUs per key, defined belowExact depth/high-water and Full/fairness/Closed totals via AdmissionReceiver::counters
Raw controlNetworkLayer::enable_network_control_receiver, RouterOptions::network_control_receiver256, separate from APDUsNoneFull/Closed counted internally; no admission snapshot or depth/high-water tracking
Tracked controlNetworkLayer::enable_network_control_receiver_with_admission, RouterOptions::network_control_receiver_with_admission256, separate from APDUsNoneExact depth/high-water and Full/Closed totals; fairness always zero

The router’s raw receivers and the raw control receiver are tokio::sync::mpsc::Receivers; NetworkLayer’s raw APDU receiver is an ApduReceiver; tracked receivers are the AdmissionReceiver alternatives. APDU and control opt-ins are independent. Routers process network messages inline; their control receiver gets only the Reject-Message-To-Network messages addressed to the router itself, and every closed admission attempt counts as Closed without disabling the stream. priority_channel is not used by these ingress paths.

§Source keys and drop precedence

Tracked APDU queues cap each key at 16 queued, unconsumed APDUs:

Each successful recv or try_recv releases a queue slot and, for tracked APDUs, that key’s quota slot before returning the item. Retaining or processing the returned item does not occupy either slot. Sixteen keys at their quota fill the 256-item queue; a key below quota can still encounter global Full. This is a queued-item cap, not a byte/rate limit or a delivery guarantee. Raw receivers and control queues have no per-source quota.

Drop attribution is Closed > fairness > Full: closed admission wins; otherwise a tracked APDU whose key already holds 16 items is a fairness drop, even if the queue also holds 256 items; otherwise global saturation is Full. Only the winning reason is counted. Every admission drop releases the arriving item’s owned payload, metadata and any reply sender without sending reply bytes or generating a wire rejection. This does not suppress ordinary router forwarding/reject behavior or change transport no-reply handling.

§Close, drop, stop, and observation

Closing either receiver kind prevents further admission but retains queued items for draining. Dropping a receiver discards them and releases their payloads, metadata and reply senders without sending reply bytes. For tracked receivers, close preserves depth until dequeued; drop sets depth to zero. Neither operation resets high-water/drop totals, and discarding queued items is not an admission drop.

A tracked NetworkLayer ends its dispatcher on the first APDU admission attempt after that receiver closes/drops, also ending control delivery. Closing an ApduReceiver stops the transport handing up NPDUs while those it queued stay drainable; dropping it discards them. A closed/dropped control receiver instead disables only that stream on the first subsequent control admission attempt. Later discarded controls (like controls received without either opt-in) are not admission attempts. Router forwarding and inline control handling continue after local delivery closes/drops; each subsequent local admission attempt is counted as Closed.

NetworkLayer::stop after start and BACnetRouter::stop end dispatch without waiting for application queues to drain; queued items remain drainable, for an ApduReceiver the NPDUs the transport queued. Stopping is not an admission drop. An independently owned QueueAdmissionCounters handle remains readable after the receiver, layer, or router is dropped; it keeps accounting alive, not the channel or tasks. snapshot is consistent for one queue, not atomic across queues, and exposes counts only, not payloads, per-source identities or per-source totals. Its three drop totals saturate at u64::MAX.

Structs§

AdmissionReceiver
Opt-in, one-consumer receiver with exact queue-depth accounting.
ApduReceiver
The APDUs a NetworkLayer receives, from NetworkLayer::start.
Counters
What a NetworkLayer has dropped on receipt since it was created, by reason. Each total saturates at u64::MAX. A dropped NPDU reaches neither the APDU nor the control receiver, so it never shows up in their admission counters. The totals never change a decision, and name no peer.
IssuedApdu
One APDU handed to a local-issuance send.
NetworkLayer
Non-router BACnet network layer.
QueueAdmissionCounters
Cloneable snapshot handle obtained from an AdmissionReceiver.
QueueAdmissionSnapshot
A consistent, count-only snapshot of one network-layer receive queue.
ReceivedApdu
A received APDU with source addressing information.
ReceivedNetworkControl
A decoded network-layer control message received from a transport peer.
ReceivedNetworkReport
A NetworkReport and where it came from.
RoutedTarget
A remote device reached through a local router.

Enums§

NetworkReport
A network message that tells a non-routing node something about the internetwork, read from a ReceivedNetworkControl.

Constants§

SENDABLE_NETWORK_MESSAGES
The network messages NetworkLayer::send_network_message sends: the two questions a non-routing node asks. The rest change routing tables, flow control or connections, or announce routes this node doesn’t have, so each joins the list only deliberately, with its own review.