feat(irtt): make IRTT measurement optional and refine engine behavior
Build binaries / Build (arm-musleabi) (push) Successful in 1m42s
Build binaries / Build (aarch64-musl) (push) Successful in 1m44s
Build binaries / Build (arm-musleabihf) (push) Successful in 1m45s
Build binaries / Build (armv7-musleabi) (push) Successful in 1m44s
Build binaries / Build (i686-musl) (push) Successful in 1m36s
Build binaries / Build (armv7-musleabihf) (push) Successful in 1m39s
Build binaries / Build (mips-musl) (push) Successful in 2m6s
Build binaries / Build (mips64-muslabi64) (push) Successful in 2m7s
Build binaries / Build (mipsel-musl) (push) Successful in 2m18s
Build binaries / Build (mips64el-muslabi64) (push) Successful in 2m18s
Build binaries / Build (x86_64-musl) (push) Successful in 1m53s
Build binaries / Build (riscv64gc-musl) (push) Successful in 1m54s
Build binaries / Build (arm-musleabi) (push) Successful in 1m42s
Build binaries / Build (aarch64-musl) (push) Successful in 1m44s
Build binaries / Build (arm-musleabihf) (push) Successful in 1m45s
Build binaries / Build (armv7-musleabi) (push) Successful in 1m44s
Build binaries / Build (i686-musl) (push) Successful in 1m36s
Build binaries / Build (armv7-musleabihf) (push) Successful in 1m39s
Build binaries / Build (mips-musl) (push) Successful in 2m6s
Build binaries / Build (mips64-muslabi64) (push) Successful in 2m7s
Build binaries / Build (mipsel-musl) (push) Successful in 2m18s
Build binaries / Build (mips64el-muslabi64) (push) Successful in 2m18s
Build binaries / Build (x86_64-musl) (push) Successful in 1m53s
Build binaries / Build (riscv64gc-musl) (push) Successful in 1m54s
Conditionally compile IRTT functionality behind the `irtt` feature flag to allow building smaller binaries without IRTT dependencies. Enhance IRTT engine shutdown, configuration, and clarify ICMP protocol names.
This commit is contained in:
5 files changed
+112
-42
No files matched your search
+19
-8
@@ -8,10 +8,11 @@ use std::{
|
|||||||
use flume::{Receiver, SendError, Sender};
|
use flume::{Receiver, SendError, Sender};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
|
use crate::measurement::irtt::IrttBinding;
|
||||||
use crate::{
|
use crate::{
|
||||||
measurement::{
|
measurement::{
|
||||||
icmp::IcmpBinding,
|
icmp::IcmpBinding,
|
||||||
irtt::IrttBinding,
|
|
||||||
model::{MeasurementSource, MeasurementStream, MeasurementStreamId, ProbeSchedule},
|
model::{MeasurementSource, MeasurementStream, MeasurementStreamId, ProbeSchedule},
|
||||||
},
|
},
|
||||||
settings::ReflectorDefinition,
|
settings::ReflectorDefinition,
|
||||||
@@ -21,6 +22,7 @@ use crate::{
|
|||||||
pub enum ControllerError {
|
pub enum ControllerError {
|
||||||
#[error("ICMP channel error")]
|
#[error("ICMP channel error")]
|
||||||
IcmpChannelError(#[from] SendError<Vec<IcmpBinding>>),
|
IcmpChannelError(#[from] SendError<Vec<IcmpBinding>>),
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
#[error("IRTT channel error")]
|
#[error("IRTT channel error")]
|
||||||
IrttChannelError(#[from] SendError<Vec<IrttBinding>>),
|
IrttChannelError(#[from] SendError<Vec<IrttBinding>>),
|
||||||
}
|
}
|
||||||
@@ -28,6 +30,7 @@ pub enum ControllerError {
|
|||||||
pub struct Controller {
|
pub struct Controller {
|
||||||
reflector_rx: Receiver<Vec<SocketAddr>>,
|
reflector_rx: Receiver<Vec<SocketAddr>>,
|
||||||
icmp_binding_tx: Sender<Vec<IcmpBinding>>,
|
icmp_binding_tx: Sender<Vec<IcmpBinding>>,
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
irtt_binding_tx: Sender<Vec<IrttBinding>>,
|
irtt_binding_tx: Sender<Vec<IrttBinding>>,
|
||||||
reflectors: HashMap<SocketAddr, ReflectorDefinition>,
|
reflectors: HashMap<SocketAddr, ReflectorDefinition>,
|
||||||
active_streams: Arc<RwLock<Vec<MeasurementStream>>>,
|
active_streams: Arc<RwLock<Vec<MeasurementStream>>>,
|
||||||
@@ -42,7 +45,7 @@ impl Controller {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
reflector_rx: Receiver<Vec<SocketAddr>>,
|
reflector_rx: Receiver<Vec<SocketAddr>>,
|
||||||
icmp_binding_tx: Sender<Vec<IcmpBinding>>,
|
icmp_binding_tx: Sender<Vec<IcmpBinding>>,
|
||||||
irtt_binding_tx: Sender<Vec<IrttBinding>>,
|
#[cfg(feature = "irtt")] irtt_binding_tx: Sender<Vec<IrttBinding>>,
|
||||||
reflectors: HashMap<SocketAddr, ReflectorDefinition>,
|
reflectors: HashMap<SocketAddr, ReflectorDefinition>,
|
||||||
active_streams: Arc<RwLock<Vec<MeasurementStream>>>,
|
active_streams: Arc<RwLock<Vec<MeasurementStream>>>,
|
||||||
endpoint_streams: Arc<RwLock<HashMap<SocketAddr, MeasurementStream>>>,
|
endpoint_streams: Arc<RwLock<HashMap<SocketAddr, MeasurementStream>>>,
|
||||||
@@ -51,6 +54,7 @@ impl Controller {
|
|||||||
Self {
|
Self {
|
||||||
reflector_rx,
|
reflector_rx,
|
||||||
icmp_binding_tx,
|
icmp_binding_tx,
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
irtt_binding_tx,
|
irtt_binding_tx,
|
||||||
reflectors,
|
reflectors,
|
||||||
active_streams,
|
active_streams,
|
||||||
@@ -90,18 +94,21 @@ impl Controller {
|
|||||||
) -> Result<(), ControllerError> {
|
) -> Result<(), ControllerError> {
|
||||||
let count = endpoints.len();
|
let count = endpoints.len();
|
||||||
let mut icmp = Vec::new();
|
let mut icmp = Vec::new();
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
let mut irtt = Vec::new();
|
let mut irtt = Vec::new();
|
||||||
let mut streams = Vec::with_capacity(count);
|
let mut streams = Vec::with_capacity(count);
|
||||||
let mut endpoint_streams = HashMap::new();
|
let mut endpoint_streams = HashMap::new();
|
||||||
for (index, endpoint) in endpoints.into_iter().enumerate() {
|
for (index, endpoint) in endpoints.into_iter().enumerate() {
|
||||||
let Some((port, hmac)) = self.reflectors.get(&endpoint).map(|definition| {
|
let Some(_definition) = self.reflectors.get(&endpoint) else {
|
||||||
(
|
|
||||||
definition.irtt_port.unwrap_or(2112),
|
|
||||||
definition.irtt_hmac.clone(),
|
|
||||||
)
|
|
||||||
}) else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
|
let (port, hmac) = {
|
||||||
|
(
|
||||||
|
_definition.irtt_port.unwrap_or(2112),
|
||||||
|
_definition.irtt_hmac.clone(),
|
||||||
|
)
|
||||||
|
};
|
||||||
let stream = self.stream_for(endpoint);
|
let stream = self.stream_for(endpoint);
|
||||||
let schedule = ProbeSchedule {
|
let schedule = ProbeSchedule {
|
||||||
period: self.period,
|
period: self.period,
|
||||||
@@ -111,9 +118,12 @@ impl Controller {
|
|||||||
MeasurementSource::IcmpEcho | MeasurementSource::IcmpTimestamp => {
|
MeasurementSource::IcmpEcho | MeasurementSource::IcmpTimestamp => {
|
||||||
icmp.push(IcmpBinding::new(stream, schedule))
|
icmp.push(IcmpBinding::new(stream, schedule))
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
MeasurementSource::Irtt => {
|
MeasurementSource::Irtt => {
|
||||||
irtt.push(IrttBinding::new(stream, schedule, port, hmac))
|
irtt.push(IrttBinding::new(stream, schedule, port, hmac))
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "irtt"))]
|
||||||
|
MeasurementSource::Irtt => unreachable!("IRTT feature is checked before startup"),
|
||||||
_ => unreachable!("unsupported reflector measurement source"),
|
_ => unreachable!("unsupported reflector measurement source"),
|
||||||
}
|
}
|
||||||
streams.push(stream);
|
streams.push(stream);
|
||||||
@@ -128,6 +138,7 @@ impl Controller {
|
|||||||
.write()
|
.write()
|
||||||
.expect("endpoint stream lock poisoned") = endpoint_streams;
|
.expect("endpoint stream lock poisoned") = endpoint_streams;
|
||||||
self.icmp_binding_tx.send_async(icmp).await?;
|
self.icmp_binding_tx.send_async(icmp).await?;
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
self.irtt_binding_tx.send_async(irtt).await?;
|
self.irtt_binding_tx.send_async(irtt).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-3
@@ -22,6 +22,7 @@ mod util;
|
|||||||
use crate::baseliner::Baseliner;
|
use crate::baseliner::Baseliner;
|
||||||
use crate::controller::Controller;
|
use crate::controller::Controller;
|
||||||
use crate::measurement::icmp::IcmpEngine;
|
use crate::measurement::icmp::IcmpEngine;
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
use crate::measurement::irtt::IrttEngine;
|
use crate::measurement::irtt::IrttEngine;
|
||||||
use crate::measurement::model::{MeasurementSource, MeasurementStream};
|
use crate::measurement::model::{MeasurementSource, MeasurementStream};
|
||||||
use crate::metrics::{Metric, Metrics, MetricsSender};
|
use crate::metrics::{Metric, Metrics, MetricsSender};
|
||||||
@@ -279,6 +280,12 @@ fn wait_for_exit(error_rx: &flume::Receiver<anyhow::Error>) -> anyhow::Result<()
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(settings: &Settings) -> anyhow::Result<()> {
|
fn run(settings: &Settings) -> anyhow::Result<()> {
|
||||||
|
#[cfg(not(feature = "irtt"))]
|
||||||
|
if settings.advanced_settings.measurement_type == ReflectorProtocol::Irtt {
|
||||||
|
anyhow::bail!(
|
||||||
|
"IRTT measurement selected, but this binary was built without the `irtt` feature"
|
||||||
|
);
|
||||||
|
}
|
||||||
let rt = tokio::runtime::Runtime::new()?;
|
let rt = tokio::runtime::Runtime::new()?;
|
||||||
|
|
||||||
if settings.advanced_settings.dry_run {
|
if settings.advanced_settings.dry_run {
|
||||||
@@ -299,6 +306,7 @@ fn run(settings: &Settings) -> anyhow::Result<()> {
|
|||||||
let (control_snapshot_tx, control_snapshot_rx) = flume::unbounded();
|
let (control_snapshot_tx, control_snapshot_rx) = flume::unbounded();
|
||||||
let (error_tx, error_rx) = flume::unbounded::<anyhow::Error>();
|
let (error_tx, error_rx) = flume::unbounded::<anyhow::Error>();
|
||||||
let (icmp_binding_tx, icmp_binding_rx) = flume::unbounded();
|
let (icmp_binding_tx, icmp_binding_rx) = flume::unbounded();
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
let (irtt_binding_tx, irtt_binding_rx) = flume::unbounded();
|
let (irtt_binding_tx, irtt_binding_rx) = flume::unbounded();
|
||||||
let (measurement_tx, measurement_rx) = flume::unbounded();
|
let (measurement_tx, measurement_rx) = flume::unbounded();
|
||||||
let (reflector_tx, reflector_rx) = flume::unbounded();
|
let (reflector_tx, reflector_rx) = flume::unbounded();
|
||||||
@@ -318,6 +326,7 @@ fn run(settings: &Settings) -> anyhow::Result<()> {
|
|||||||
let controller = Controller::new(
|
let controller = Controller::new(
|
||||||
reflector_rx,
|
reflector_rx,
|
||||||
icmp_binding_tx,
|
icmp_binding_tx,
|
||||||
|
#[cfg(feature = "irtt")]
|
||||||
irtt_binding_tx,
|
irtt_binding_tx,
|
||||||
reflectors,
|
reflectors,
|
||||||
Arc::clone(&active_streams),
|
Arc::clone(&active_streams),
|
||||||
@@ -333,13 +342,20 @@ fn run(settings: &Settings) -> anyhow::Result<()> {
|
|||||||
icmp_binding_rx,
|
icmp_binding_rx,
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
let (_irtt_task, irtt_engine) = {
|
#[cfg(feature = "irtt")]
|
||||||
|
let (irtt_task, irtt_engine) = {
|
||||||
let _guard = rt.enter();
|
let _guard = rt.enter();
|
||||||
IrttEngine::new(start_time, measurement_tx, irtt_binding_rx)?
|
IrttEngine::new(
|
||||||
|
start_time,
|
||||||
|
Duration::from_secs_f64(settings.advanced_settings.tick_interval),
|
||||||
|
measurement_tx,
|
||||||
|
irtt_binding_rx,
|
||||||
|
)?
|
||||||
};
|
};
|
||||||
|
|
||||||
spawn_task(&rt, &error_tx, icmp_engine.run());
|
spawn_task(&rt, &error_tx, icmp_engine.run());
|
||||||
spawn_task(&rt, &error_tx, irtt_engine.run());
|
#[cfg(feature = "irtt")]
|
||||||
|
spawn_task(&rt, &error_tx, irtt_engine.run(irtt_task));
|
||||||
|
|
||||||
let dropped = Arc::new(AtomicU32::new(0));
|
let dropped = Arc::new(AtomicU32::new(0));
|
||||||
|
|
||||||
|
|||||||
+56
-13
@@ -2,7 +2,7 @@ use std::{collections::HashMap, net::SocketAddr, time::Instant};
|
|||||||
|
|
||||||
use flume::{Receiver, Sender};
|
use flume::{Receiver, Sender};
|
||||||
use irtt_client::{
|
use irtt_client::{
|
||||||
ClientConfig, ClientEvent,
|
ClientConfig, ClientEvent, NegotiationPolicy, OpenPolicy,
|
||||||
managed::{
|
managed::{
|
||||||
ManagedClient, ManagedClientConfig, ManagedClientHandle, ManagedClientTask,
|
ManagedClient, ManagedClientConfig, ManagedClientHandle, ManagedClientTask,
|
||||||
ManagedCommandAcknowledgement, ManagedCommandApplyError, ManagedCommandError,
|
ManagedCommandAcknowledgement, ManagedCommandApplyError, ManagedCommandError,
|
||||||
@@ -15,6 +15,7 @@ use log::{debug, trace, warn};
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::broadcast::error::RecvError;
|
use tokio::sync::broadcast::error::RecvError;
|
||||||
|
|
||||||
|
use crate::SHUTDOWN;
|
||||||
use crate::measurement::model::{
|
use crate::measurement::model::{
|
||||||
MeasurementEvent, MeasurementLoss, MeasurementObservation, MeasurementStream,
|
MeasurementEvent, MeasurementLoss, MeasurementObservation, MeasurementStream,
|
||||||
MeasurementStreamId, OneWayClock, OneWayLatency, ProbeSchedule, SignedDuration,
|
MeasurementStreamId, OneWayClock, OneWayLatency, ProbeSchedule, SignedDuration,
|
||||||
@@ -52,6 +53,9 @@ pub enum IrttError {
|
|||||||
|
|
||||||
pub struct IrttBinding {
|
pub struct IrttBinding {
|
||||||
stream: MeasurementStream,
|
stream: MeasurementStream,
|
||||||
|
/// Retained for future hybrid-mode scheduling. IRTT currently uses the
|
||||||
|
/// global interval configured on its managed client.
|
||||||
|
#[allow(dead_code)]
|
||||||
schedule: ProbeSchedule,
|
schedule: ProbeSchedule,
|
||||||
port: u16,
|
port: u16,
|
||||||
hmac: Option<String>,
|
hmac: Option<String>,
|
||||||
@@ -87,20 +91,11 @@ pub struct IrttEngine {
|
|||||||
impl IrttEngine {
|
impl IrttEngine {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
origin: Instant,
|
origin: Instant,
|
||||||
|
interval: std::time::Duration,
|
||||||
observation_tx: Sender<MeasurementEvent>,
|
observation_tx: Sender<MeasurementEvent>,
|
||||||
binding_rx: Receiver<Vec<IrttBinding>>,
|
binding_rx: Receiver<Vec<IrttBinding>>,
|
||||||
) -> Result<(ManagedClientTask, Self), IrttError> {
|
) -> Result<(ManagedClientTask, Self), IrttError> {
|
||||||
let config = ManagedClientConfig {
|
let config = managed_client_config(interval);
|
||||||
client: ClientConfig {
|
|
||||||
request: irtt_client::SessionRequest {
|
|
||||||
duration: None,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
completion: ManagedCompletionPolicy::ExplicitStop,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let (task, handle) = ManagedClient::task(config, Vec::new())?;
|
let (task, handle) = ManagedClient::task(config, Vec::new())?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
@@ -142,11 +137,19 @@ impl IrttEngine {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(mut self) -> Result<(), IrttError> {
|
pub async fn run(mut self, task: ManagedClientTask) -> Result<(), IrttError> {
|
||||||
|
let mut task = Box::pin(task);
|
||||||
let mut events = self.client.subscribe()?;
|
let mut events = self.client.subscribe()?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
outcome = task.as_mut() => {
|
||||||
|
return match outcome.end_reason {
|
||||||
|
ManagedEndReason::StopRequested => Ok(()),
|
||||||
|
end_reason => Err(IrttError::ManagedFailure(end_reason)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
bindings = self.binding_rx.recv_async() => {
|
bindings = self.binding_rx.recv_async() => {
|
||||||
let bindings = bindings
|
let bindings = bindings
|
||||||
.map_err(|_| IrttError::BindingChannelClosed)?;
|
.map_err(|_| IrttError::BindingChannelClosed)?;
|
||||||
@@ -338,11 +341,51 @@ impl IrttEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = tokio::time::sleep(std::time::Duration::from_millis(100)) => {
|
||||||
|
if SHUTDOWN.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
|
let stop = self.client.stop();
|
||||||
|
tokio::pin!(stop);
|
||||||
|
tokio::select! {
|
||||||
|
_ = &mut stop => {},
|
||||||
|
outcome = task.as_mut() => {
|
||||||
|
return match outcome.end_reason {
|
||||||
|
ManagedEndReason::StopRequested => Ok(()),
|
||||||
|
end_reason => Err(IrttError::ManagedFailure(end_reason)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let outcome = task.await;
|
||||||
|
return match outcome.end_reason {
|
||||||
|
ManagedEndReason::StopRequested => Ok(()),
|
||||||
|
end_reason => Err(IrttError::ManagedFailure(end_reason)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn managed_client_config(interval: std::time::Duration) -> ManagedClientConfig {
|
||||||
|
ManagedClientConfig {
|
||||||
|
client: ClientConfig {
|
||||||
|
request: irtt_client::SessionRequest {
|
||||||
|
duration: None,
|
||||||
|
interval,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
open: OpenPolicy {
|
||||||
|
negotiation: NegotiationPolicy::Strict,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
completion: ManagedCompletionPolicy::ExplicitStop,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn map_one_way(sample: irtt_client::OneWayDelaySample) -> Option<OneWayLatency> {
|
fn map_one_way(sample: irtt_client::OneWayDelaySample) -> Option<OneWayLatency> {
|
||||||
let uplink = i64::try_from(sample.client_to_server?.as_nanos()).ok()?;
|
let uplink = i64::try_from(sample.client_to_server?.as_nanos()).ok()?;
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub enum MeasurementSource {
|
|||||||
impl Display for MeasurementSource {
|
impl Display for MeasurementSource {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
MeasurementSource::IcmpEcho => write!(f, "icmp"),
|
MeasurementSource::IcmpEcho => write!(f, "icmp-echo"),
|
||||||
MeasurementSource::IcmpTimestamp => write!(f, "icmp-timestamps"),
|
MeasurementSource::IcmpTimestamp => write!(f, "icmp-timestamps"),
|
||||||
MeasurementSource::Irtt => write!(f, "irtt"),
|
MeasurementSource::Irtt => write!(f, "irtt"),
|
||||||
MeasurementSource::TcpSeqAck => write!(f, "tcp-seqack"),
|
MeasurementSource::TcpSeqAck => write!(f, "tcp-seqack"),
|
||||||
|
|||||||
+17
-17
@@ -89,7 +89,7 @@ pub enum ReflectorProtocol {
|
|||||||
impl Display for ReflectorProtocol {
|
impl Display for ReflectorProtocol {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ReflectorProtocol::IcmpEcho => write!(f, "icmp"),
|
ReflectorProtocol::IcmpEcho => write!(f, "icmp-echo"),
|
||||||
ReflectorProtocol::IcmpTimestamps => write!(f, "icmp-timestamps"),
|
ReflectorProtocol::IcmpTimestamps => write!(f, "icmp-timestamps"),
|
||||||
ReflectorProtocol::Irtt => write!(f, "irtt"),
|
ReflectorProtocol::Irtt => write!(f, "irtt"),
|
||||||
}
|
}
|
||||||
@@ -101,8 +101,8 @@ impl FromStr for ReflectorProtocol {
|
|||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s.to_lowercase().as_str() {
|
match s.to_lowercase().as_str() {
|
||||||
"icmp" => Ok(ReflectorProtocol::IcmpEcho),
|
"icmp-echo" => Ok(ReflectorProtocol::IcmpEcho),
|
||||||
"icmp-timestamps" | "icmp_timestamps" => Ok(ReflectorProtocol::IcmpTimestamps),
|
"icmp-timestamps" => Ok(ReflectorProtocol::IcmpTimestamps),
|
||||||
"irtt" => Ok(ReflectorProtocol::Irtt),
|
"irtt" => Ok(ReflectorProtocol::Irtt),
|
||||||
_ => Err(ConfigError::Message(format!(
|
_ => Err(ConfigError::Message(format!(
|
||||||
"invalid measurement type: {s}"
|
"invalid measurement type: {s}"
|
||||||
@@ -137,15 +137,15 @@ pub(crate) struct ReflectorDefinition {
|
|||||||
pub(crate) country: Option<String>,
|
pub(crate) country: Option<String>,
|
||||||
pub(crate) protocols: Vec<ReflectorProtocol>,
|
pub(crate) protocols: Vec<ReflectorProtocol>,
|
||||||
pub(crate) irtt_port: Option<u16>,
|
pub(crate) irtt_port: Option<u16>,
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) irtt_hmac: Option<String>,
|
pub(crate) irtt_hmac: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct ReflectorRow {
|
struct ReflectorRow {
|
||||||
#[serde(alias = "reflector_ip")]
|
|
||||||
host: String,
|
host: String,
|
||||||
country: Option<String>,
|
country: Option<String>,
|
||||||
protocols: Option<String>,
|
protocols: String,
|
||||||
irtt_port: Option<u16>,
|
irtt_port: Option<u16>,
|
||||||
irtt_hmac: Option<String>,
|
irtt_hmac: Option<String>,
|
||||||
}
|
}
|
||||||
@@ -246,18 +246,18 @@ impl ReflectorSettings {
|
|||||||
.map_err(|error| ConfigError::Message(error.to_string()))?;
|
.map_err(|error| ConfigError::Message(error.to_string()))?;
|
||||||
for row in reader.deserialize::<ReflectorRow>() {
|
for row in reader.deserialize::<ReflectorRow>() {
|
||||||
let row = row.map_err(|error| ConfigError::Message(error.to_string()))?;
|
let row = row.map_err(|error| ConfigError::Message(error.to_string()))?;
|
||||||
let protocols = match row.protocols {
|
let protocols = row
|
||||||
Some(protocols) => protocols
|
.protocols
|
||||||
.split(['|', ';'])
|
.split(['|', ';'])
|
||||||
.map(str::trim)
|
.map(str::trim)
|
||||||
.filter(|protocol| !protocol.is_empty())
|
.filter(|protocol| !protocol.is_empty())
|
||||||
.map(ReflectorProtocol::from_str)
|
.map(ReflectorProtocol::from_str)
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
None => vec![
|
if protocols.is_empty() {
|
||||||
ReflectorProtocol::IcmpEcho,
|
return Err(ConfigError::Message(format!(
|
||||||
ReflectorProtocol::IcmpTimestamps,
|
"reflector row in {path} has no protocols"
|
||||||
],
|
)));
|
||||||
};
|
}
|
||||||
self.entries.push(ReflectorDefinition {
|
self.entries.push(ReflectorDefinition {
|
||||||
host: row.host,
|
host: row.host,
|
||||||
country: row.country,
|
country: row.country,
|
||||||
|
|||||||
Reference in new issue
Block a user