nvpsf_transport.h
nvpsf_transport.h
The message-oriented AF_UNIX SOCK_SEQPACKET transport that every Safety Core link uses: endpoint configuration, socket paths under /run/nvpsf, the peer group check and the socket-buffer sizing.
Part of the Transport. Generated from the header published in safety-core/, release 1.3-26.07.5. The development packages install it in /opt/nvidia/psf/include.
Message-oriented inter-process transport for PSF links.
One API over two transports: AF_UNIX SOCK_SEQPACKET and UDP. The API is message-oriented rather than stream-oriented, because both preserve message boundaries. Two consequences the caller can rely on:
- Recv returns exactly one whole message or an error. A partial message is not a reachable outcome, so no caller needs a recvAll loop.
- Send transmits one whole message or reports WOULD_BLOCK. A partial send is not a reachable outcome, so no caller needs a sendAll loop.
A blanket “never call this API under your own lock” rule would be unsafe, not merely conservative: obeying it literally means dropping your lock before Send, which opens a window for a concurrent Close to free the handle mid-send. Consult the table instead.
Par: Send is always non-blocking at the syscall level. Waiting happens only in NvPSFTransportPoll, which takes an explicit timeout. There is no call in this API through which a caller can block indefinitely.
Par: The transport’s internal descriptor mutex is a leaf lock: this library never invokes a caller callback while holding it, so it can never acquire a caller’s lock. The obligation is therefore per entry point, not blanket.
Call Under a caller lock? NvPSFTransportSend Permitted. Non-blocking at the syscall level (MSG_DONTWAIT, and every socket is SOCK_NONBLOCK), acquires only the transport’s own leaf mutex, and makes no callback. Holding a caller lock across it is in fact the simplest way to keep the handle alive against a concurrent Close. NvPSFTransportRecv Permitted, for the same reasons. recvmsg uses MSG_DONTWAIT. NvPSFTransportPoll Not permitted while holding a lock any send path also takes. Poll is the ONLY call in this API that blocks, for up to its timeout, and it would stall every concurrent Send for that whole period. NvPSFTransportDropPeer Not permitted. It tears down peer state, and reclaim logic naturally sits inside a locked region which is what makes this the easy one to get wrong. Snapshot the peer set under your lock, release it, then call DropPeer. NvPSFTransportClose Not permitted. It frees the handle. No other thread may be inside any call on it, which is a stronger requirement than a lock can express.
The distinction that matters: Send and Recv are bounded and side-effect-free with respect to the caller’s state; Poll blocks; DropPeer and Close destroy state other callers may be using. Treat the last three as the rule and the first two as safe.
Par: Descriptors stay private to the transport object. No function returns or accepts a raw descriptor, so a caller cannot outlive-use one.
Par: Linux only. Depends on SO_PEERCRED, struct ucred, AF_UNIX SOCK_SEQPACKET, MSG_NOSIGNAL, and SOCK_CLOEXEC.
Functions
NvPSFTransportKindName
Operator-facing name of kind, for logs and diagnostics.
Returns: A static string; “INVALID” when kind is out of range. Never NULL, so callers may log the result without a null check.
NvPSFTransportLinkSupportsKind
Whether link can carry kind.
The single definition of the availability matrix. A selection outside it is a fatal startup error everywhere, never a silent downgrade, because a downgrade would move safety traffic onto a different path than the operator configured with no indication.
Deliberately a header-only inline so configuration parsers and test tooling can validate a selection without linking libnvpsf_transport. Duplicating the matrix in those callers instead would let the copies drift apart, which is the failure this placement prevents.
Returns: 1 when supported, 0 when not or when either argument is out of range.
NvPSFTransportLinkName
Operator-facing name of link, for diagnostics.
Returns: A static string; “INVALID” when out of range. Never NULL.
NvPSFGatewaySdmMinQueueDepth
Provisioned depth for the gateway -> SDM link, honouring a deployment override.
Returns NVPSF_GATEWAY_SDM_MIN_QUEUE_DEPTH unless NVPSF_MIN_QUEUE_DEPTH is set in the environment, in which case that value is used and a warning naming the risk is printed.
WHY AN OVERRIDE EXISTS AT ALL, since a lower value re-opens exactly the spurious-lockout path this floor closes:
The floor is a statement about what the HOST has been provisioned for, not a safety dial. A host whose net.core.rmem_max cannot reach 1096500 every stock distribution default is far below it cannot start the gateway or either SDM at all once this lands, and that includes every build and test machine. Without an explicit, loud override the only way to run any integration test would be root access to change a kernel parameter, which turns an unprovisioned CI box into a hard stop rather than a warning.
It is deliberately an environment variable and not a config key or CLI flag: it must be conspicuous, it must not look like normal operator tuning, and it must not be reachable from nvpss.conf. Startup-only and read once, so it is therefore immutable once Open returns.
Production must NOT set it. Release documentation states the sysctl instead.
NvPSFTransportOpen
Create an endpoint.
Fails rather than degrades. An unsupported kind for cfg->link, a path too long for sun_path, or a buffer the kernel will not grant all return an error with a diagnostic on stderr; the caller is expected to treat any failure here as fatal at startup.
NvPSFTransportClose
Destroy an endpoint, closing every descriptor and unlinking a bound AF_UNIX path.
Call only after every thread that uses t has been joined. NULL is a no-op.
NvPSFTransportPoll
Wait up to timeoutMs for peer or message activity.
Accepts pending connections, validating credentials, and reports the results as events. Returns NVPSF_TRANSPORT_TIMEOUT with *outCount == 0 when nothing happened.
Par: When the shared datagram socket is in an error state most often ICMP port-unreachable from a peer that is not listening Poll consumes the pending error, names it on stderr and returns NVPSF_TRANSPORT_FAIL. It does not report TIMEOUT: poll() does not block while an error is pending, so a caller told “nothing happened” would spin.
Par: A peer that sends and then closes delivers both in one wakeup. Poll reports the readable data and holds the slot; PEER_GONE follows on a later Poll, or as Recv’s return code, once the queue is empty. Draining the peer is therefore what surfaces the disconnect: a caller that acts on events but never calls Recv never observes PEER_GONE.
NvPSFTransportRecv
Receive exactly one whole message.
With several peers ready, selection is round-robin from the slot after the one last serviced, and one call yields at most one message. Lowest-slot-first would let a chatty peer inside the allowed group starve the others; on the gateway link that would mean registrations and heartbeat acknowledgements from healthy SDMs go unserviced and those SDMs get reclaimed as dead.
NvPSFTransportSend
Send one whole message. Never blocks.
NvPSFTransportSolePeer
Identity of the single peer held by a non-server endpoint.
Required for a client to send first, which every PSF client does: an SDM registers with the gateway, the PSS daemon initiates to PSD, and an RPC client issues a request. A peer id embeds a generation counter that is assigned internally, so it cannot be constructed by the caller, and without this accessor a client could only learn its own peer after receiving a message making the send-first direction unreachable.
Valid for a client of any kind. A server has many peers and learns each from NVPSF_EVENT_PEER_CONNECTED or from Recv, so the question does not apply and the call is refused rather than answered arbitrarily.
NvPSFTransportPeerCred
Read the credential captured when peer was admitted.
Authorization must use this, never a field from a client-controlled message payload.
NvPSFTransportDropPeer
Disconnect peer and free its slot.
Must be called outside any caller lock. A stale identity whose generation no longer matches returns NVPSF_TRANSPORT_PEER_GONE without touching the slot’s current occupant.
NvPSFTransportPeerDropCount
Messages dropped for peer because the buffer was full.
Exists so a caller can log backpressure as fault evidence with a count attached, rather than reporting each WOULD_BLOCK in isolation.
NvPSFTransportErrName
Human-readable name for err. Never NULL.
Types
NvPSFPeerCred_t
Validated peer credential, captured once at accept/connect time.
NvPSFTransportEvent_t
NvPSFTransportCfg_t
Endpoint configuration. Startup-only; nothing here is mutable after NvPSFTransportOpen returns.
Only the fields belonging to kind are read. String fields are copied during Open, so the caller may free them afterwards.
NvPSFTransportKind_t
Transport used to carry PSF messages over one link.
Values are explicit and stable. Not every kind is valid on every link; each link declares the kinds it supports and rejects the rest at startup.
These enumerators must not be placed on the wire. Convert to and from a fixed-width integer at any serialization boundary and range-check against NVPSF_TRANSPORT_KIND_COUNT before casting back.
NvPSFTransportLink_t
Which PSF link an endpoint serves.
Lives here beside the kind enum rather than in nvpsf_transport.h because the two are one vocabulary: a transport selection is only meaningful paired with the link it applies to, and configuration parsers need both before any endpoint exists.