7 Commits
Author SHA1 Message Date
Nils Andreas Svee c89a8b2165 docs(reflectors): bundle protocol-aware inventory and configuration examples
Build binaries / Build (aarch64-musl) (push) Successful in 1m39s
Build binaries / Build (arm-musleabi) (push) Successful in 1m40s
Build binaries / Build (armv7-musleabi) (push) Successful in 1m54s
Build binaries / Build (arm-musleabihf) (push) Successful in 1m58s
Build binaries / Build (armv7-musleabihf) (push) Successful in 2m36s
Build binaries / Build (i686-musl) (push) Successful in 2m0s
Build binaries / Build (mips-musl) (push) Successful in 2m3s
Build binaries / Build (mips64-muslabi64) (push) Successful in 2m12s
Build binaries / Build (mips64el-muslabi64) (push) Successful in 2m18s
Build binaries / Build (mipsel-musl) (push) Successful in 2m11s
Build binaries / Build (riscv64gc-musl) (push) Successful in 1m53s
Build binaries / Build (x86_64-musl) (push) Successful in 1m46s
Replace the ICMP-only inventory with protocol-aware records, remove Mullvad DNS entries and omit misleading anycast countries. Document IRTT authentication and explicit TOML/UCI reflector configuration, including disabling file loading.
2026-10-14 12:13:14 +07:00
Nils Andreas Svee f0fc761fb3 feat(measurement): integrate IRTT and configurable reflector selection
Add protocol-aware reflector definitions, TOML/UCI lists, validation and environment overrides. Resolve and select endpoint-aware measurement streams, honor configured ICMP timing and socket routing, and retain partial-set reselection behavior from the standalone fixes.

Drive the managed IRTT task throughout its lifecycle, retry terminal targets without restarting healthy sessions, normalize blank HMAC keys and use effective RTT for latency fallback. Fold the reviewed configuration, resolution and measurement corrections into their implementation.
2026-10-14 12:13:14 +07:00
Nils Andreas Svee 9de7b9dabc feat(uci): support repeated sections and skipped fields
Allow structured lists to share the existing UCI configuration adapter while keeping collection fields out of scalar section mappings.
2026-10-14 12:13:14 +07:00
Nils Andreas Svee 2efa0d30c2 fix(uci): gate schema generation behind UCI feature
Rust CI / cargo fmt (push) Successful in 10s
Rust CI / cargo clippy (push) Failing after 28s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Failing after 26s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 6s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 6s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Failing after 22s
Supply chain / cargo-deny advisories (push) Failing after 2s
Supply chain / cargo-deny bans licenses sources (push) Failing after 3s
Supply chain / actionlint (push) Failing after 5s
Rust CI / cargo doc (push) Failing after 27s
Build binaries / Build (arm-musleabi) (push) Successful in 1m45s
Build binaries / Build (aarch64-musl) (push) Successful in 1m49s
Build binaries / Build (armv7-musleabi) (push) Successful in 1m54s
Build binaries / Build (arm-musleabihf) (push) Successful in 1m55s
Build binaries / Build (armv7-musleabihf) (push) Successful in 2m34s
Build binaries / Build (i686-musl) (push) Successful in 2m34s
Build binaries / Build (mips-musl) (push) Successful in 2m5s
Build binaries / Build (mips64-muslabi64) (push) Successful in 2m5s
Build binaries / Build (mipsel-musl) (push) Successful in 2m10s
Build binaries / Build (mips64el-muslabi64) (push) Successful in 2m12s
Build binaries / Build (riscv64gc-musl) (push) Successful in 2m8s
Build binaries / Build (x86_64-musl) (push) Successful in 2m1s
2026-10-14 12:13:13 +07:00
Nils Andreas Svee f1a50af7d3 fix(reflectors): retain current peers when no candidates respond
Rust CI / cargo fmt (push) Successful in 22s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Failing after 37s
Rust CI / cargo clippy (push) Failing after 37s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 12s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 13s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Failing after 31s
Supply chain / cargo-deny advisories (push) Failing after 3s
Supply chain / cargo-deny bans licenses sources (push) Failing after 2s
Supply chain / actionlint (push) Failing after 3s
Rust CI / cargo doc (push) Failing after 32s
Build binaries / Build (arm-musleabi) (push) Successful in 2m16s
Build binaries / Build (aarch64-musl) (push) Failing after 24m1s
Build binaries / Build (arm-musleabihf) (push) Failing after 51m7s
Build binaries / Build (armv7-musleabihf) (push) Failing after 11m33s
Build binaries / Build (armv7-musleabi) (push) Failing after 11m33s
Build binaries / Build (i686-musl) (push) Successful in 2m6s
Build binaries / Build (mips-musl) (push) Successful in 2m10s
Build binaries / Build (mips64-muslabi64) (push) Successful in 2m5s
Build binaries / Build (mips64el-muslabi64) (push) Successful in 2m12s
Build binaries / Build (mipsel-musl) (push) Successful in 2m10s
Build binaries / Build (riscv64gc-musl) (push) Successful in 2m9s
Build binaries / Build (x86_64-musl) (push) Successful in 1m42s
Restore the pre-probe selection when evaluation finds no usable candidates. Preserve master’s existing selection of smaller candidate sets.
2026-10-14 11:58:07 +07:00
Nils Andreas Svee 5624746914 fix(ratecontroller): account for configured and partial reflector sets
Cap the required delta count at the active peer count using advanced_settings.num_reflectors. Keep requesting reselection when the active set is empty so recovery remains possible.
2026-10-14 11:58:07 +07:00
Nils Andreas Svee 2e24da4bf8 chore: remove unused clock and mutex helpers 2026-10-14 11:58:07 +07:00
8 changed files with 13 additions and 50 deletions

No files matched your search

+2
View File
@@ -82,6 +82,7 @@ fn expand_uci_section(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStre
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
Ok(quote! {
#[cfg(all(feature = "uci", unix))]
#[automatically_derived]
impl #impl_generics
crate::settings::uci_schema::UciSectionSchema
@@ -155,6 +156,7 @@ fn expand_uci_config(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStrea
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
Ok(quote! {
#[cfg(all(feature = "uci", unix))]
#[automatically_derived]
impl #impl_generics
crate::settings::uci_schema::UciConfigSchema
+1 -3
View File
@@ -120,9 +120,7 @@ impl Controller {
icmp.push(IcmpBinding::new(stream, schedule))
}
#[cfg(feature = "irtt")]
MeasurementSource::Irtt => {
irtt.push(IrttBinding::new(stream, schedule, port, hmac))
}
MeasurementSource::Irtt => irtt.push(IrttBinding::new(stream, port, hmac)),
#[cfg(not(feature = "irtt"))]
MeasurementSource::Irtt => unreachable!("IRTT feature is checked before startup"),
_ => unreachable!("unsupported reflector measurement source"),
-1
View File
@@ -389,7 +389,6 @@ fn run(settings: &Settings) -> anyhow::Result<()> {
let (irtt_task, irtt_engine) = {
let _guard = rt.enter();
IrttEngine::new(
start_time,
Duration::from_secs_f64(settings.advanced_settings.tick_interval),
&settings.network,
measurement_tx,
+4 -22
View File
@@ -1,4 +1,4 @@
use std::{collections::HashMap, net::SocketAddr, time::Instant};
use std::{collections::HashMap, net::SocketAddr};
use flume::{Receiver, Sender};
use irtt_client::{
@@ -17,7 +17,7 @@ use tokio::sync::broadcast::error::RecvError;
use crate::SHUTDOWN;
use crate::measurement::model::{
MeasurementEvent, MeasurementLoss, MeasurementObservation, MeasurementStream,
MeasurementStreamId, OneWayClock, OneWayLatency, ProbeSchedule, SignedDuration,
MeasurementStreamId, OneWayClock, OneWayLatency, SignedDuration,
};
use crate::settings::NetworkSettings;
@@ -53,27 +53,13 @@ pub enum IrttError {
pub struct IrttBinding {
stream: MeasurementStream,
/// Retained for future hybrid-mode scheduling. IRTT currently uses the
/// global interval configured on its managed client.
#[allow(dead_code)]
schedule: ProbeSchedule,
port: u16,
hmac: Option<String>,
}
impl IrttBinding {
pub fn new(
stream: MeasurementStream,
schedule: ProbeSchedule,
port: u16,
hmac: Option<String>,
) -> Self {
Self {
stream,
schedule,
port,
hmac,
}
pub fn new(stream: MeasurementStream, port: u16, hmac: Option<String>) -> Self {
Self { stream, port, hmac }
}
}
@@ -83,15 +69,12 @@ pub struct IrttEngine {
bindings: HashMap<MeasurementStreamId, IrttBinding>,
targets: Vec<ManagedTargetConfig>,
origin: Instant,
binding_rx: Receiver<Vec<IrttBinding>>,
observation_tx: Sender<MeasurementEvent>,
}
impl IrttEngine {
pub fn new(
origin: Instant,
interval: std::time::Duration,
settings: &NetworkSettings,
observation_tx: Sender<MeasurementEvent>,
@@ -106,7 +89,6 @@ impl IrttEngine {
client: handle,
bindings: HashMap::new(),
targets: Vec::new(),
origin,
binding_rx,
observation_tx,
},
+4 -1
View File
@@ -492,7 +492,10 @@ impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
self.state_ul.deltas = up_deltas;
let minimum = usize::from(self.settings.reflectors.num_reflectors).min(reflectors.len());
if self.state_dl.deltas.len() < minimum || self.state_ul.deltas.len() < minimum {
if reflectors.is_empty()
|| self.state_dl.deltas.len() < minimum
|| self.state_ul.deltas.len() < minimum
{
// trigger reselection
warn!(
"Not enough delta values (D: {}, U: {}, need {}), triggering reselection",
+1 -3
View File
@@ -2,12 +2,10 @@
//
// SPDX-License-Identifier: MPL-2.0
use anyhow::{Context, bail};
use config::{Config, ConfigError, Environment};
use log::Level;
use serde::{Deserialize, Deserializer, de};
use std::fmt::{self, Display};
use std::net::IpAddr;
use std::str::FromStr;
use uci_derive::{UciConfig, UciSection};
@@ -17,6 +15,7 @@ use crate::settings::uci::UciSource;
#[cfg(all(feature = "uci", unix))]
pub mod uci;
#[cfg(all(feature = "uci", unix))]
pub(crate) mod uci_schema;
mod validation;
@@ -494,4 +493,3 @@ where
)),
}
}
-9
View File
@@ -14,16 +14,11 @@ pub trait Clock {
}
pub enum Realtime {}
pub enum Monotonic {}
impl Clock for Realtime {
const ID: ClockId = ClockId::Realtime;
}
impl Clock for Monotonic {
const ID: ClockId = ClockId::Monotonic;
}
pub struct ClockSample<C> {
time_s: u64,
time_ns: u64,
@@ -56,10 +51,6 @@ impl<C: Clock> ClockSample<C> {
pub fn as_secs_f64(&self) -> f64 {
self.time_s as f64 + self.time_ns as f64 / 1_000_000_000.0
}
pub fn to_milliseconds(&self) -> u64 {
(self.time_s * 1000) + (self.time_ns / 1000000)
}
}
impl ClockSample<Realtime> {
+1 -11
View File
@@ -3,20 +3,10 @@
// SPDX-License-Identifier: MPL-2.0
use anyhow::anyhow;
use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
pub type ArcRwLock<T> = Arc<RwLock<T>>;
pub trait MutexExt<T> {
fn lock_anyhow(&self) -> anyhow::Result<MutexGuard<'_, T>>;
}
impl<T> MutexExt<T> for Mutex<T> {
fn lock_anyhow(&self) -> anyhow::Result<MutexGuard<'_, T>> {
self.lock().map_err(|e| anyhow!("mutex poisoned: {e}"))
}
}
pub trait RwLockExt<T> {
fn read_anyhow(&self) -> anyhow::Result<RwLockReadGuard<'_, T>>;
fn write_anyhow(&self) -> anyhow::Result<RwLockWriteGuard<'_, T>>;