From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 24B7D1FF185 for ; Mon, 4 Aug 2025 18:23:55 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 1A63936A7E; Mon, 4 Aug 2025 18:25:26 +0200 (CEST) From: Stefan Hanreich To: pbs-devel@lists.proxmox.com Date: Mon, 4 Aug 2025 18:24:40 +0200 Message-ID: <20250804162448.607184-7-s.hanreich@proxmox.com> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250804162448.607184-1-s.hanreich@proxmox.com> References: <20250804162448.607184-1-s.hanreich@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.191 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Subject: [pbs-devel] [PATCH proxmox-backup v5 2/4] metric_collection: use ip link for determining the type of interfaces X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" Physical interfaces now can have arbitrary names with the introduction of proxmox-network-interface pinning. In order to correctly report the bandwidth metrics for PBS hosts, the method for determining whether an interface is physical or not needs to be adjusted as well. Use the adapted helper from proxmox-network-api to query the information about interfaces and use that to determine the type of interface at every site that uses the generated stats. To avoid spawning a new process with every update loop, cache the initial query and use that information. Signed-off-by: Stefan Hanreich Tested-by: Christian Ebner --- src/server/metric_collection/mod.rs | 87 +++++++++++++++++--- src/server/metric_collection/pull_metrics.rs | 5 +- src/server/metric_collection/rrd.rs | 5 +- 3 files changed, 79 insertions(+), 18 deletions(-) diff --git a/src/server/metric_collection/mod.rs b/src/server/metric_collection/mod.rs index daedfb72..9b62cbb4 100644 --- a/src/server/metric_collection/mod.rs +++ b/src/server/metric_collection/mod.rs @@ -1,7 +1,8 @@ use std::{ + collections::HashMap, path::Path, pin::pin, - sync::Arc, + sync::{Arc, OnceLock}, time::{Duration, Instant}, }; @@ -9,6 +10,7 @@ use anyhow::Error; use tokio::join; use pbs_api_types::{DataStoreConfig, Operation}; +use proxmox_network_api::{get_network_interfaces, IpLink}; use proxmox_sys::{ fs::FileSystemInformation, linux::procfs::{Loadavg, ProcFsMemInfo, ProcFsNetDev, ProcFsStat}, @@ -101,7 +103,7 @@ async fn run_stat_generator() { struct HostStats { proc: Option, meminfo: Option, - net: Option>, + net: Option>, load: Option, } @@ -111,11 +113,78 @@ struct DiskStat { dev: Option, } -fn collect_host_stats_sync() -> HostStats { - use proxmox_sys::linux::procfs::{ - read_loadavg, read_meminfo, read_proc_net_dev, read_proc_stat, +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] +enum NetdevType { + Physical, + Virtual, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] +struct NetdevStat { + pub device: String, + pub receive: u64, + pub send: u64, + pub ty: NetdevType, +} + +impl NetdevStat { + fn from_fs_net_dev(net_dev: ProcFsNetDev, ty: NetdevType) -> Self { + Self { + device: net_dev.device, + receive: net_dev.receive, + send: net_dev.send, + ty, + } + } +} + +static NETWORK_INTERFACE_CACHE: OnceLock> = OnceLock::new(); + +fn collect_netdev_stats() -> Option> { + use proxmox_sys::linux::procfs::read_proc_net_dev; + + let net_devs = match read_proc_net_dev() { + Ok(net_devs) => net_devs, + Err(err) => { + eprintln!("read_prox_net_dev failed - {err}"); + return None; + } }; + let ip_links = match NETWORK_INTERFACE_CACHE.get() { + Some(ip_links) => ip_links, + None => match get_network_interfaces() { + Ok(network_interfaces) => { + let _ = NETWORK_INTERFACE_CACHE.set(network_interfaces); + NETWORK_INTERFACE_CACHE.get().unwrap() + } + Err(err) => { + eprintln!("get_network_interfaces failed - {err}"); + return None; + } + }, + }; + + let mut stat_devs = Vec::with_capacity(net_devs.len()); + + for net_dev in net_devs { + if let Some(ip_link) = ip_links.get(&net_dev.device) { + let ty = if ip_link.is_physical() { + NetdevType::Physical + } else { + NetdevType::Virtual + }; + + stat_devs.push(NetdevStat::from_fs_net_dev(net_dev, ty)); + } + } + + Some(stat_devs) +} + +fn collect_host_stats_sync() -> HostStats { + use proxmox_sys::linux::procfs::{read_loadavg, read_meminfo, read_proc_stat}; + let proc = match read_proc_stat() { Ok(stat) => Some(stat), Err(err) => { @@ -132,13 +201,7 @@ fn collect_host_stats_sync() -> HostStats { } }; - let net = match read_proc_net_dev() { - Ok(netdev) => Some(netdev), - Err(err) => { - eprintln!("read_prox_net_dev failed - {err}"); - None - } - }; + let net = collect_netdev_stats(); let load = match read_loadavg() { Ok(loadavg) => Some(loadavg), diff --git a/src/server/metric_collection/pull_metrics.rs b/src/server/metric_collection/pull_metrics.rs index 3b105eaf..e99662fa 100644 --- a/src/server/metric_collection/pull_metrics.rs +++ b/src/server/metric_collection/pull_metrics.rs @@ -12,7 +12,7 @@ use proxmox_shared_cache::SharedCache; use proxmox_sys::fs::CreateOptions; use serde::{Deserialize, Serialize}; -use super::{DiskStat, HostStats, METRIC_COLLECTION_INTERVAL}; +use super::{DiskStat, HostStats, NetdevType, METRIC_COLLECTION_INTERVAL}; const METRIC_CACHE_TIME: Duration = Duration::from_secs(30 * 60); const STORED_METRIC_GENERATIONS: u64 = @@ -113,11 +113,10 @@ pub(super) fn update_metrics( } if let Some(netdev) = &host.net { - use pbs_config::network::is_physical_nic; let mut netin = 0; let mut netout = 0; for item in netdev { - if !is_physical_nic(&item.device) { + if item.ty != NetdevType::Physical { continue; } netin += item.receive; diff --git a/src/server/metric_collection/rrd.rs b/src/server/metric_collection/rrd.rs index ed39cc94..d129432e 100644 --- a/src/server/metric_collection/rrd.rs +++ b/src/server/metric_collection/rrd.rs @@ -16,7 +16,7 @@ use proxmox_sys::fs::CreateOptions; use pbs_buildcfg::PROXMOX_BACKUP_STATE_DIR_M; use proxmox_rrd_api_types::{RrdMode, RrdTimeframe}; -use super::{DiskStat, HostStats}; +use super::{DiskStat, HostStats, NetdevType}; const RRD_CACHE_BASEDIR: &str = concat!(PROXMOX_BACKUP_STATE_DIR_M!(), "/rrdb"); @@ -162,11 +162,10 @@ pub(super) fn update_metrics(host: &HostStats, hostdisk: &DiskStat, datastores: } if let Some(netdev) = &host.net { - use pbs_config::network::is_physical_nic; let mut netin = 0; let mut netout = 0; for item in netdev { - if !is_physical_nic(&item.device) { + if item.ty != NetdevType::Physical { continue; } netin += item.receive; -- 2.47.2 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel