feat(measurement): add configurable IRTT reflector measurements

Support optional IRTT measurements alongside ICMP with CSV and inline reflector definitions, repeated UCI registration, authentication, and endpoint-specific stream tracking.

Keep the managed driver running during target acknowledgements and stop and join it on event-loop exits. Carry stream identity through baselines, selection, and rate control so endpoints sharing an IP remain distinct.
This commit is contained in:
Nils Andreas Svee committed 2026-10-13 21:24:05 +07:00
1 parent 76a7e14835
commit de77e5a281
12 files changed
+1022 -194

No files matched your search

+25 -13
View File
@@ -7,6 +7,7 @@
use crate::SHUTDOWN;
use crate::baseliner::ControlSnapshot;
use crate::measurement::model::MeasurementStream;
use crate::metrics::{Metric, MetricsSender};
use crate::platform::{
InterfaceStatsProvider, PlatformInterfaceStats, PlatformTrafficControl, TrafficControlBackend,
@@ -19,7 +20,6 @@ use flume::{Receiver, Sender};
use log::{debug, info, warn};
use std::fs::File;
use std::io::Write;
use std::net::IpAddr;
use std::sync::atomic::Ordering;
use std::thread::sleep;
use std::time::{Duration, Instant};
@@ -100,7 +100,7 @@ fn drain_latest_snapshot(
fn deltas_from_snapshot(
snapshot: Option<&ControlSnapshot>,
reflectors: &[IpAddr],
reflectors: &[MeasurementStream],
now: Instant,
tick_interval: f64,
) -> (Vec<f64>, Vec<f64>) {
@@ -123,8 +123,8 @@ fn deltas_from_snapshot(
up.push(up_delta);
debug!(
"Reflector: {} down_delay: {} up_delay: {}",
reflector, down_delta, up_delta
"Reflector: {} ({:?}) down_delay: {} up_delay: {}",
reflector.peer, reflector.source, down_delta, up_delta
);
}
}
@@ -139,7 +139,7 @@ pub struct Ratecontroller<S: InterfaceStatsProvider, T: TrafficControlBackend> {
settings: Settings,
control_snapshot: Option<ControlSnapshot>,
control_snapshot_rx: Receiver<ControlSnapshot>,
reflectors_lock: ArcRwLock<Vec<IpAddr>>,
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
reselect_trigger: Sender<bool>,
state_dl: State<T::Handle>,
state_ul: State<T::Handle>,
@@ -153,7 +153,7 @@ impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
fn new_with_backends(
settings: Settings,
control_snapshot_rx: Receiver<ControlSnapshot>,
reflectors_lock: ArcRwLock<Vec<IpAddr>>,
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
reselect_trigger: Sender<bool>,
metrics: MetricsSender,
mut stats_provider: S,
@@ -509,7 +509,7 @@ impl Ratecontroller<PlatformInterfaceStats, PlatformTrafficControl> {
pub fn new(
settings: Settings,
control_snapshot_rx: Receiver<ControlSnapshot>,
reflectors_lock: ArcRwLock<Vec<IpAddr>>,
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
reselect_trigger: Sender<bool>,
metrics: MetricsSender,
) -> anyhow::Result<Self> {
@@ -530,7 +530,17 @@ impl Ratecontroller<PlatformInterfaceStats, PlatformTrafficControl> {
mod tests {
use super::*;
use crate::baseliner::{EwmaStats, ReflectorState};
use crate::measurement::model::{MeasurementSource, MeasurementStreamId};
use std::collections::HashMap;
use std::net::IpAddr;
fn stream(id: u64, peer: IpAddr) -> MeasurementStream {
MeasurementStream {
id: MeasurementStreamId(id),
peer,
source: MeasurementSource::IcmpTimestamp,
}
}
#[test]
fn fixed_seed_reproduces_initial_safe_rates() {
@@ -564,7 +574,7 @@ mod tests {
}
fn snapshot(generated_at: Instant, marker: f64) -> ControlSnapshot {
let reflector = "192.0.2.1".parse().unwrap();
let reflector = stream(0, "192.0.2.1".parse().unwrap());
ControlSnapshot {
generated_at,
reflectors: HashMap::from([(
@@ -590,7 +600,9 @@ mod tests {
assert!(rx.is_empty());
assert_eq!(latest.generated_at, newest_at);
assert_eq!(
latest.reflectors[&"192.0.2.1".parse().unwrap()].recent.down,
latest.reflectors[&stream(0, "192.0.2.1".parse().unwrap())]
.recent
.down,
2.0
);
}
@@ -598,10 +610,10 @@ mod tests {
#[test]
fn calculates_sorted_deltas_from_active_fresh_snapshot_state() {
let now = Instant::now();
let first: IpAddr = "192.0.2.1".parse().unwrap();
let second: IpAddr = "192.0.2.2".parse().unwrap();
let stale: IpAddr = "192.0.2.3".parse().unwrap();
let inactive: IpAddr = "192.0.2.4".parse().unwrap();
let first = stream(0, "192.0.2.1".parse().unwrap());
let second = stream(1, "192.0.2.2".parse().unwrap());
let stale = stream(2, "192.0.2.3".parse().unwrap());
let inactive = stream(3, "192.0.2.4".parse().unwrap());
let snapshot = ControlSnapshot {
generated_at: now,
reflectors: HashMap::from([