fix(shaper): distinguish interface loss and reset counters on recovery
This commit is contained in:
5 files changed
+42
-16
No files matched your search
@@ -105,6 +105,10 @@ impl InterfaceStatsProvider for FreeBsdInterfaceStats {
|
|||||||
tx_bytes: ifmd.ifmd_data.ifi_obytes,
|
tx_bytes: ifmd.ifmd_data.ifi_obytes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_interface_missing(error: &Self::Error) -> bool {
|
||||||
|
matches!(error, FreeBsdInterfaceStatsError::InterfaceNotFound { .. })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type PlatformInterfaceStats = FreeBsdInterfaceStats;
|
pub(crate) type PlatformInterfaceStats = FreeBsdInterfaceStats;
|
||||||
|
|||||||
@@ -18,9 +18,6 @@ use std::sync::atomic::Ordering;
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub(crate) enum NetlinkError {
|
pub(crate) enum NetlinkError {
|
||||||
#[error("Couldn't find interface `{0}`")]
|
|
||||||
InterfaceNotFound(String),
|
|
||||||
|
|
||||||
#[error("Netlink error: {0}")]
|
#[error("Netlink error: {0}")]
|
||||||
Netlink(#[from] io::Error),
|
Netlink(#[from] io::Error),
|
||||||
|
|
||||||
@@ -48,9 +45,8 @@ pub(crate) struct Qdisc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NetlinkError {
|
impl NetlinkError {
|
||||||
fn is_qdisc_loss(&self) -> bool {
|
fn is_interface_missing(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::InterfaceNotFound(_) | Self::NoQdiscFound(_) => true,
|
|
||||||
Self::Netlink(error) => {
|
Self::Netlink(error) => {
|
||||||
matches!(error.raw_os_error(), Some(libc::ENODEV | libc::ENOENT))
|
matches!(error.raw_os_error(), Some(libc::ENODEV | libc::ENOENT))
|
||||||
}
|
}
|
||||||
@@ -61,6 +57,10 @@ impl NetlinkError {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_qdisc_loss(&self) -> bool {
|
||||||
|
self.is_interface_missing() || matches!(self, Self::NoQdiscFound(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@@ -74,9 +74,7 @@ impl Netlink {
|
|||||||
request.encode().push_ifname_bytes(ifname.as_bytes());
|
request.encode().push_ifname_bytes(ifname.as_bytes());
|
||||||
|
|
||||||
let mut iter = socket.request(&request)?;
|
let mut iter = socket.request(&request)?;
|
||||||
let (header, _) = iter
|
let (header, _) = iter.recv_one()?;
|
||||||
.recv_one()
|
|
||||||
.map_err(|_| NetlinkError::InterfaceNotFound(ifname.to_string()))?;
|
|
||||||
Ok(header.ifi_index)
|
Ok(header.ifi_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +171,10 @@ impl InterfaceStatsProvider for Netlink {
|
|||||||
let (rx_bytes, tx_bytes) = Self::get_interface_stats(interface)?;
|
let (rx_bytes, tx_bytes) = Self::get_interface_stats(interface)?;
|
||||||
Ok(InterfaceStats { rx_bytes, tx_bytes })
|
Ok(InterfaceStats { rx_bytes, tx_bytes })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_interface_missing(error: &Self::Error) -> bool {
|
||||||
|
error.is_interface_missing()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrafficControlBackend for Netlink {
|
impl TrafficControlBackend for Netlink {
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ impl InterfaceStatsProvider for MacOsInterfaceStats {
|
|||||||
let response = route_interface_list(interface_index)?;
|
let response = route_interface_list(interface_index)?;
|
||||||
parse_route_messages(&response, interface_index)
|
parse_route_messages(&response, interface_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_interface_missing(error: &Self::Error) -> bool {
|
||||||
|
matches!(error, MacOsInterfaceStatsError::InterfaceNotFound { .. })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn route_interface_list(
|
fn route_interface_list(
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ pub(crate) trait InterfaceStatsProvider: Send {
|
|||||||
type Error: Error + Send + Sync + 'static;
|
type Error: Error + Send + Sync + 'static;
|
||||||
|
|
||||||
fn read_stats(&mut self, interface: &str) -> Result<InterfaceStats, Self::Error>;
|
fn read_stats(&mut self, interface: &str) -> Result<InterfaceStats, Self::Error>;
|
||||||
|
|
||||||
|
fn is_interface_missing(_error: &Self::Error) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait TrafficControlBackend: Send {
|
pub(crate) trait TrafficControlBackend: Send {
|
||||||
|
|||||||
+20
-8
@@ -367,14 +367,8 @@ impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
|
|||||||
&mut self.stats_provider,
|
&mut self.stats_provider,
|
||||||
&self.settings.network.upload_interface,
|
&self.settings.network.upload_interface,
|
||||||
) {
|
) {
|
||||||
Ok(stats) => {
|
Ok(stats) => stats,
|
||||||
if stats_missing {
|
Err(error) if S::is_interface_missing(&error) => {
|
||||||
info!("Interface statistics available again");
|
|
||||||
stats_missing = false;
|
|
||||||
}
|
|
||||||
stats
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
if !stats_missing {
|
if !stats_missing {
|
||||||
warn!(
|
warn!(
|
||||||
"Interface statistics unavailable: {error}; waiting for interface recovery"
|
"Interface statistics unavailable: {error}; waiting for interface recovery"
|
||||||
@@ -383,6 +377,7 @@ impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Err(error) => return Err(error.into()),
|
||||||
};
|
};
|
||||||
if SHUTDOWN.load(Ordering::Relaxed) {
|
if SHUTDOWN.load(Ordering::Relaxed) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -404,6 +399,23 @@ impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
|
|||||||
)?;
|
)?;
|
||||||
last_reassert_t = now_t;
|
last_reassert_t = now_t;
|
||||||
}
|
}
|
||||||
|
if stats_missing
|
||||||
|
|| self.state_dl.current_bytes < self.state_dl.previous_bytes
|
||||||
|
|| self.state_ul.current_bytes < self.state_ul.previous_bytes
|
||||||
|
{
|
||||||
|
if stats_missing {
|
||||||
|
info!("Interface statistics available again");
|
||||||
|
stats_missing = false;
|
||||||
|
} else {
|
||||||
|
warn!("Interface byte counters reset");
|
||||||
|
}
|
||||||
|
self.state_dl.previous_bytes = self.state_dl.current_bytes;
|
||||||
|
self.state_ul.previous_bytes = self.state_ul.current_bytes;
|
||||||
|
self.state_dl.prev_t = now_t;
|
||||||
|
self.state_ul.prev_t = now_t;
|
||||||
|
lastchg_t = now_t;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
self.update_deltas()?;
|
self.update_deltas()?;
|
||||||
|
|
||||||
if self.state_dl.deltas.is_empty() || self.state_ul.deltas.is_empty() {
|
if self.state_dl.deltas.is_empty() || self.state_ul.deltas.is_empty() {
|
||||||
|
|||||||
Reference in new issue
Block a user