From 82d8a049cc3f6ce2c246ca4a6b15b0608e1971fc Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Wed, 8 Jul 2026 18:35:22 +0300 Subject: [PATCH] stats: add rx_errors, tx_errors, rx_dropped, tx_dropped counters Stats struct gains 4 new u64 fields per RFC 1213 (MIB-II): - rx_errors: incoming packets with errors - tx_errors: outgoing packets with errors - rx_dropped: incoming packets dropped (buffer full, etc.) - tx_dropped: outgoing packets dropped (qdisc dropped, buffer full) EthernetLink tx path now increments tx_dropped when qdisc returns None (qdisc decided to drop the packet, e.g., TokenBucket rate exceeded). netcfg stats output now exposes all 8 counters: rx_bytes=N rx_packets=N tx_bytes=N tx_packets=N rx_errors=N tx_errors=N rx_dropped=N tx_dropped=N mtu=N link=up Aggregate fields work for bridge/bond via existing sum logic. --- netstack/src/link/ethernet.rs | 1 + netstack/src/link/mod.rs | 4 ++++ netstack/src/scheme/netcfg/mod.rs | 6 ++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/netstack/src/link/ethernet.rs b/netstack/src/link/ethernet.rs index 877afb7387..3c4efd8d9a 100644 --- a/netstack/src/link/ethernet.rs +++ b/netstack/src/link/ethernet.rs @@ -711,6 +711,7 @@ impl LinkDevice for EthernetLink { let owned = self.qdisc_config.enqueue_and_dequeue(packet.to_vec(), now); let Some(packet) = owned else { + self.stats.tx_dropped += 1; return; }; self.stats.tx_packets += 1; diff --git a/netstack/src/link/mod.rs b/netstack/src/link/mod.rs index dbd5896362..a2fde820d2 100644 --- a/netstack/src/link/mod.rs +++ b/netstack/src/link/mod.rs @@ -84,6 +84,10 @@ pub struct Stats { pub rx_packets: u64, pub tx_bytes: u64, pub tx_packets: u64, + pub rx_errors: u64, + pub tx_errors: u64, + pub rx_dropped: u64, + pub tx_dropped: u64, } #[derive(Default)] diff --git a/netstack/src/scheme/netcfg/mod.rs b/netstack/src/scheme/netcfg/mod.rs index c03adc8e59..0b00a33d6b 100644 --- a/netstack/src/scheme/netcfg/mod.rs +++ b/netstack/src/scheme/netcfg/mod.rs @@ -478,8 +478,9 @@ fn mk_root_node( match devices.borrow().get("eth0") { Some(dev) => { let s = dev.statistics(); - format!("rx_bytes={} rx_packets={} tx_bytes={} tx_packets={} mtu={} link={}\n", + format!("rx_bytes={} rx_packets={} tx_bytes={} tx_packets={} rx_errors={} tx_errors={} rx_dropped={} tx_dropped={} mtu={} link={}\n", s.rx_bytes, s.rx_packets, s.tx_bytes, s.tx_packets, + s.rx_errors, s.tx_errors, s.rx_dropped, s.tx_dropped, dev.mtu(), dev.link_state()) } None => "Device not found\n".into(), @@ -591,8 +592,9 @@ fn mk_root_node( match devices.borrow().get("loopback") { Some(dev) => { let s = dev.statistics(); - format!("rx_bytes={} rx_packets={} tx_bytes={} tx_packets={} mtu={} link={}\n", + format!("rx_bytes={} rx_packets={} tx_bytes={} tx_packets={} rx_errors={} tx_errors={} rx_dropped={} tx_dropped={} mtu={} link={}\n", s.rx_bytes, s.rx_packets, s.tx_bytes, s.tx_packets, + s.rx_errors, s.tx_errors, s.rx_dropped, s.tx_dropped, dev.mtu(), dev.link_state()) } None => "Device not found\n".into(),