pub struct Observer {
pub uds_rcvbuf_bytes: u32,
/* private fields */
}Expand description
Observer bound to one or more transport listeners.
The observer owns all listeners; cleanup (e.g. socket file unlink) happens
when the Observer is dropped.
Fields§
§uds_rcvbuf_bytes: u32Effective SO_RCVBUF size granted by the kernel for the observer UDS,
in bytes. 0 if --uds-rcvbuf-bytes 0 was used or tuning failed.
Set by Observer::bind from the UdsListener::rcvbuf_bytes accessor.
Implementations§
Source§impl Observer
impl Observer
Sourcepub fn new(
threshold: Duration,
tracker_capacity: usize,
eviction_policy: EvictionPolicy,
eviction_scan_window: usize,
max_beat_rate: Option<u32>,
global_beat_rate: u32,
global_beat_burst: u32,
clock_source: ClockSource,
) -> Result<Self>
pub fn new( threshold: Duration, tracker_capacity: usize, eviction_policy: EvictionPolicy, eviction_scan_window: usize, max_beat_rate: Option<u32>, global_beat_rate: u32, global_beat_burst: u32, clock_source: ClockSource, ) -> Result<Self>
Create an empty observer with no listeners. Use
Observer::add_listener to attach transports, or call
Observer::bind for the common single-UDS case.
tracker_capacity sets the maximum number of distinct agent pids
tracked concurrently. Beats for new pids beyond this limit are
dropped with Update::CapacityExceeded (the counter is surfaced
via varta_tracker_capacity_exceeded_total).
eviction_policy controls which slot to reclaim when the tracker
is full and a new pid arrives (EvictionPolicy::Strict only
evicts confirmed-stalled agents; EvictionPolicy::Balanced also
evicts the oldest active slot to prevent capacity exhaustion).
max_beat_rate is an optional per-pid rate limit in beats per
second. When set, beats arriving faster than this rate from the
same pid are dropped and counted via [Observer::drain_rate_limited].
None (the default) disables rate limiting.
Sourcepub fn with_allow_cross_namespace(self, allow: bool) -> Self
pub fn with_allow_cross_namespace(self, allow: bool) -> Self
Allow beats from agents whose kernel-attested PID namespace differs
from the observer’s own namespace. Default false. Wired from the
--allow-cross-namespace-agents CLI flag.
Sourcepub fn from_listener<L: BeatListener + 'static>(
listener: L,
threshold: Duration,
tracker_capacity: usize,
eviction_policy: EvictionPolicy,
eviction_scan_window: usize,
max_beat_rate: Option<u32>,
global_beat_rate: u32,
global_beat_burst: u32,
clock_source: ClockSource,
) -> Result<Self>
pub fn from_listener<L: BeatListener + 'static>( listener: L, threshold: Duration, tracker_capacity: usize, eviction_policy: EvictionPolicy, eviction_scan_window: usize, max_beat_rate: Option<u32>, global_beat_rate: u32, global_beat_burst: u32, clock_source: ClockSource, ) -> Result<Self>
Create an observer from a single already-configured listener.
Sourcepub fn bind(
path: impl AsRef<Path>,
threshold: Duration,
socket_mode: u32,
read_timeout: Duration,
uds_rcvbuf_bytes: u32,
tracker_capacity: usize,
eviction_policy: EvictionPolicy,
eviction_scan_window: usize,
max_beat_rate: Option<u32>,
global_beat_rate: u32,
global_beat_burst: u32,
clock_source: ClockSource,
pre_thread: &PreThreadAttestation,
) -> Result<Self>
pub fn bind( path: impl AsRef<Path>, threshold: Duration, socket_mode: u32, read_timeout: Duration, uds_rcvbuf_bytes: u32, tracker_capacity: usize, eviction_policy: EvictionPolicy, eviction_scan_window: usize, max_beat_rate: Option<u32>, global_beat_rate: u32, global_beat_burst: u32, clock_source: ClockSource, pre_thread: &PreThreadAttestation, ) -> Result<Self>
Bind a Unix datagram socket at path and return an Observer
with that single UDS listener.
This is the backward-compatible convenience constructor for the common
single-UDS case. For multi-transport setups, use Observer::new
followed by Observer::add_listener.
Sourcepub fn add_listener(&mut self, listener: Box<dyn BeatListener>)
pub fn add_listener(&mut self, listener: Box<dyn BeatListener>)
Add a listener to the observer. The listener is polled in round-robin order alongside any existing listeners.
Sourcepub fn poll(&mut self) -> Option<Event>
pub fn poll(&mut self) -> Option<Event>
Poll every listener once round-robin and return the first
non-WouldBlock Event found. Each listener is tried exactly
once per call — a busy listener cannot starve others because the
round-robin cursor (next_listener_start) advances past each
non-WouldBlock listener on every call.
Latency bound: worst-case per-call work is
N_listeners × per-listener-recv-cost + eviction_scan_window.
Under the canonical stress profile (3 listeners, 4096 tracker
capacity, 256-slot eviction window) the p99 iteration time is
≤ 5 ms — see book/src/architecture/observer-liveness.md and the
tick-distribution bench (cargo run -p varta-bench --release -- tick-distribution) which asserts this bound under sustained load.
This method never returns Event::Stall — queued stall events must
be retrieved via Observer::poll_pending.
Sourcepub fn poll_pending(&mut self) -> Option<Event>
pub fn poll_pending(&mut self) -> Option<Event>
Return the next queued Event::Stall, if any.
Sourcepub fn has_pending_stalls(&self) -> bool
pub fn has_pending_stalls(&self) -> bool
Whether the stall queue has unconsumed Event::Stall entries.
Sourcepub fn now_ns(&mut self) -> u64
pub fn now_ns(&mut self) -> u64
Observer-local nanosecond timestamp (ns since Observer start).
Clamped to never decrease — on some platforms (VMs with TSC drift, live-migration pause-and-resume), the underlying clock can produce values that appear to go backwards. Without clamping, a forward clock jump after a backward excursion can cause false stall detections.
The kernel clock backing this reading is selected via
crate::clock::ClockSource (--clock-source CLI flag); see
book/src/architecture/safety-profiles.md for the SRE vs. medical
deployment matrix.
Sourcepub fn drain_clock_regressions(&mut self) -> u64
pub fn drain_clock_regressions(&mut self) -> u64
Drain and reset the clock-regression counter — number of times the
kernel monotonic clock returned a value strictly less than the
previously observed one and the forward clamp absorbed the
regression. Non-zero values surface TSC drift, VM live migration,
or other anomalous clock behavior that would otherwise be invisible.
Surfaced as varta_observer_clock_regression_total.
Sourcepub fn drain_clock_jumps_forward(&mut self) -> u64
pub fn drain_clock_jumps_forward(&mut self) -> u64
Drain and reset the forward-jump counter — number of times the kernel
monotonic clock advanced by more than [CLOCK_JUMP_FORWARD_THRESHOLD_NS]
between adjacent poll ticks. Non-zero values indicate sleep/wake on
monotonic-raw/boottime, VM live migration, or a hypervisor pause.
Surfaced as varta_observer_clock_jump_forward_total.
Sourcepub fn clock_source(&self) -> ClockSource
pub fn clock_source(&self) -> ClockSource
Inspect the kernel clock backing this observer’s stall accounting.
Sourcepub fn drain_evictions(&mut self) -> u64
pub fn drain_evictions(&mut self) -> u64
Drain and reset the eviction counter.
Sourcepub fn drain_evicted_pid(&mut self) -> Option<u32>
pub fn drain_evicted_pid(&mut self) -> Option<u32>
Drain the pid of the most recently evicted slot, if any.
Sourcepub fn drain_capacity_exceeded(&mut self) -> u64
pub fn drain_capacity_exceeded(&mut self) -> u64
Drain and reset the capacity-exceeded counter.
Sourcepub fn drain_nonce_wraps(&mut self) -> u64
pub fn drain_nonce_wraps(&mut self) -> u64
Drain and reset the nonce-wrap counter.
Sourcepub fn drain_eviction_scan_truncated(&mut self) -> u64
pub fn drain_eviction_scan_truncated(&mut self) -> u64
Drain and reset the count of bounded eviction-scan calls that ran
the full [crate::tracker::EVICTION_SCAN_WINDOW] without finding a
victim. Non-zero values prove the per-frame work cap engaged — i.e.
the tracker was full and an attacker would otherwise have forced
O(n) work per arriving frame.
Sourcepub fn drain_origin_conflicts(&mut self) -> u64
pub fn drain_origin_conflicts(&mut self) -> u64
Drain and reset the per-tracker origin-conflict counter — number of
beats dropped because their transport origin disagreed with the
slot’s pinned origin (first-origin-wins). Surfaced as
varta_origin_conflict_total in the Prometheus exporter.
Sourcepub fn drain_cross_namespace_drops(&mut self) -> u64
pub fn drain_cross_namespace_drops(&mut self) -> u64
Drain and reset the count of beats dropped at ingress because the
peer’s PID-namespace inode differs from the observer’s. Surfaced as
varta_frame_namespace_mismatch_total in the Prometheus exporter.
Sourcepub fn drain_pid_above_max_drops(&mut self) -> u64
pub fn drain_pid_above_max_drops(&mut self) -> u64
Drain and reset the count of beats dropped at ingress because
frame.pid exceeded the kernel’s configured pid_max. Surfaced as
varta_frame_rejected_pid_above_max_total in the Prometheus
exporter. Linux-only signal; 0 on platforms where the gate defaults
to u32::MAX.
Sourcepub fn pid_max(&self) -> u32
pub fn pid_max(&self) -> u32
Observer’s cached pid_max. Linux-only meaningful value; otherwise
u32::MAX. Exposed for tests and for the Prometheus exporter’s
gauge.
Sourcepub fn maybe_refresh_pid_max(&mut self) -> bool
pub fn maybe_refresh_pid_max(&mut self) -> bool
Re-read /proc/sys/kernel/pid_max if at least
[PID_MAX_REFRESH_INTERVAL_NS] has elapsed since the last refresh.
Cheap no-op otherwise (single u64 compare).
Intended to be called from the daemon’s maintenance phase — not
from poll() — so the I/O hot path stays untouched. Picks up
runtime sysctl -w kernel.pid_max=... changes within one interval.
On non-Linux targets, crate::pid_max::read_pid_max returns
u32::MAX so the gate stays effectively disabled and this method
is a steady no-op.
Returns true when a refresh actually ran this call (regardless of
whether the read value changed), false when gated by the interval.
Sourcepub fn drain_namespace_conflicts(&mut self) -> u64
pub fn drain_namespace_conflicts(&mut self) -> u64
Drain and reset the per-tracker namespace-conflict counter — beats
dropped because the beat’s namespace inode disagreed with the slot’s
pinned namespace inode (first-namespace-wins). Surfaced as
varta_tracker_namespace_conflict_total.
Sourcepub fn observer_pid_namespace_inode(&self) -> Option<u64>
pub fn observer_pid_namespace_inode(&self) -> Option<u64>
Observer’s own PID-namespace inode (Linux only; cached). Used by
main.rs to construct recovery StallSource values that include
the observer’s namespace for the audit record.
Sourcepub fn drain_invariant_violations(&mut self) -> u64
pub fn drain_invariant_violations(&mut self) -> u64
Drain and reset the tracker invariant-violation counter. Non-zero
values surface that a defensive fall-through in the hot path
triggered (e.g. a stale PidIndex entry pointed at an out-of-range
slot). Exposed as varta_tracker_invariant_violations_total.
Sourcepub fn drain_pid_index_probe_exhausted(&mut self) -> u64
pub fn drain_pid_index_probe_exhausted(&mut self) -> u64
Drain and reset the PidIndex probe-exhaustion counter — number of
times a pid lookup ran the full MAX_PROBE budget without finding
a match. Surfaced as varta_tracker_pid_index_probe_exhausted_total.
Sourcepub fn drain_per_pid_rate_limited(&mut self) -> u64
pub fn drain_per_pid_rate_limited(&mut self) -> u64
Drain and reset the per-pid rate-limited counter.
Sourcepub fn drain_global_rate_limited(&mut self) -> u64
pub fn drain_global_rate_limited(&mut self) -> u64
Drain and reset the global rate-limited counter.
Sourcepub fn uds_rcvbuf_bytes(&self) -> u32
pub fn uds_rcvbuf_bytes(&self) -> u32
Effective SO_RCVBUF size granted by the kernel for the observer UDS.
Sourcepub fn drain_decrypt_failures(&mut self) -> u64
pub fn drain_decrypt_failures(&mut self) -> u64
Drain and reset the AEAD decryption failure counter across all listeners.
Sourcepub fn drain_truncated(&mut self) -> u64
pub fn drain_truncated(&mut self) -> u64
Drain and reset the truncated-datagram counter across all listeners.
Sourcepub fn drain_sender_state_full(&mut self) -> u64
pub fn drain_sender_state_full(&mut self) -> u64
Drain and reset the sender-state-full counter across all listeners.
Sourcepub fn drain_aead_attempts(&mut self) -> u64
pub fn drain_aead_attempts(&mut self) -> u64
Drain and reset the AEAD-decryption-attempt counter across all
listeners. In steady state this equals
frames_received * (keys.len() + master_key_configured as u64) for
the secure-UDP listener — every loaded key is tried per frame to
remove the key-rotation timing side-channel.
Sourcepub fn drain_bind_dir_fsync_failures() -> u64
pub fn drain_bind_dir_fsync_failures() -> u64
Drain and reset the parent-directory fsync failure counter for UDS
bind. Non-zero only when the OS returned an error from fsync(2) on
the socket’s parent directory during startup. Surfaced as
varta_socket_bind_dir_fsync_failed_total.