pub mod bfd; pub mod control; pub mod events; use std::{ fmt::{self, Display}, net::IpAddr, time::Instant, }; use log::debug; use nix::sys::socket::{getsockopt, setsockopt, sockopt}; use tokio::net::UdpSocket; use crate::bfd::*; #[derive(Debug)] pub struct BfdSessionStats { pub local_ip: IpAddr, pub remote_ip: IpAddr, pub local_discr: BfdDiscriminator, pub remote_discr: BfdDiscriminator, pub state: BfdState, pub last_diag: BfdDiagnostic, pub control_packets_rx: u64, pub control_packets_tx: u64, pub last_change: Instant, pub detect_time: BfdInterval, pub base_interval: BfdInterval, } impl BfdSessionStats { pub fn with_base_interval(mut self, base_interval: BfdInterval) -> Self { self.base_interval = base_interval; self } } impl Display for BfdSessionStats { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!( f, "{:<20} {:<9} {:>6} {:>6}", self.remote_ip, self.state, self.control_packets_rx, self.control_packets_tx )?; write!( f, " LocalDiscr:{} RemoteDiscr:{} DetectTime: {} TxTime: {} Diag:{} Last: {}s", self.local_discr, self.remote_discr, self.detect_time, self.base_interval, self.last_diag, Instant::now().duration_since(self.last_change).as_secs() ) } } pub fn set_ttl_or_hop_limit(sock: &UdpSocket, hop_limit: u8) -> Result<(), std::io::Error> { let addr = sock.local_addr()?; if addr.is_ipv4() { debug!("IPv4 socket, setting ttl {}", hop_limit as u32); sock.set_ttl(hop_limit as u32) } else if addr.is_ipv6() { debug!("IPv6 socket, setting hop limit {}", hop_limit as i32); let i32_hop_limit = hop_limit as i32; if let Err(e) = setsockopt(sock, sockopt::Ipv6Ttl, &i32_hop_limit) { Err(std::io::Error::from_raw_os_error(e as i32)) } else { let res = getsockopt(sock, sockopt::Ipv6Ttl)?; debug!("Got {} after setting {}", res, i32_hop_limit); Ok(()) } } else { panic!("UdpSocket with no address family ?!") } }