Skip to main content

Observer

Struct Observer 

Source
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: u32

Effective 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

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn poll_pending(&mut self) -> Option<Event>

Return the next queued Event::Stall, if any.

Source

pub fn has_pending_stalls(&self) -> bool

Whether the stall queue has unconsumed Event::Stall entries.

Source

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.

Source

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.

Source

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.

Source

pub fn clock_source(&self) -> ClockSource

Inspect the kernel clock backing this observer’s stall accounting.

Source

pub fn drain_evictions(&mut self) -> u64

Drain and reset the eviction counter.

Source

pub fn drain_evicted_pid(&mut self) -> Option<u32>

Drain the pid of the most recently evicted slot, if any.

Source

pub fn drain_capacity_exceeded(&mut self) -> u64

Drain and reset the capacity-exceeded counter.

Source

pub fn drain_nonce_wraps(&mut self) -> u64

Drain and reset the nonce-wrap counter.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn drain_per_pid_rate_limited(&mut self) -> u64

Drain and reset the per-pid rate-limited counter.

Source

pub fn drain_global_rate_limited(&mut self) -> u64

Drain and reset the global rate-limited counter.

Source

pub fn uds_rcvbuf_bytes(&self) -> u32

Effective SO_RCVBUF size granted by the kernel for the observer UDS.

Source

pub fn drain_decrypt_failures(&mut self) -> u64

Drain and reset the AEAD decryption failure counter across all listeners.

Source

pub fn drain_truncated(&mut self) -> u64

Drain and reset the truncated-datagram counter across all listeners.

Source

pub fn drain_sender_state_full(&mut self) -> u64

Drain and reset the sender-state-full counter across all listeners.

Source

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.

Source

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.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.