From 8c0cda5232a27411311ad85f463734b62e8b9099 Mon Sep 17 00:00:00 2001 From: Yuuki Takano Date: Mon, 27 Apr 2026 11:38:53 +0900 Subject: [PATCH 1/3] feat(igc): add on-demand netdump observability --- applications/awkernel_shell/Cargo.toml | 2 ++ applications/awkernel_shell/src/lib.rs | 19 +++++++++++++++++++ awkernel_drivers/src/pcie/intel/igc.rs | 4 ++++ awkernel_lib/src/net.rs | 13 +++++++++++++ awkernel_lib/src/net/net_device.rs | 3 +++ 5 files changed, 41 insertions(+) diff --git a/applications/awkernel_shell/Cargo.toml b/applications/awkernel_shell/Cargo.toml index b26d7df57..14ecc0c42 100644 --- a/applications/awkernel_shell/Cargo.toml +++ b/applications/awkernel_shell/Cargo.toml @@ -9,6 +9,8 @@ edition = "2021" blisp = "0.4" log = "0.4" byteorder = { version = "1.0", default-features = false } +num-bigint = { version = "0.4", default-features = false } +num-traits = { version = "0.2", default-features = false } [dependencies.awkernel_async_lib] path = "../../awkernel_async_lib" diff --git a/applications/awkernel_shell/src/lib.rs b/applications/awkernel_shell/src/lib.rs index 916a2cdee..8e0d67bda 100644 --- a/applications/awkernel_shell/src/lib.rs +++ b/applications/awkernel_shell/src/lib.rs @@ -16,6 +16,8 @@ use awkernel_async_lib::{ use awkernel_lib::{console, sync::mutex::MCSNode, IS_STD}; use blisp::{embedded, runtime::FFI}; use core::time::Duration; +use num_bigint::BigInt; +use num_traits::ToPrimitive; const SERVICE_NAME: &str = "[Awkernel] shell"; @@ -48,6 +50,7 @@ async fn console_handler() -> TaskResult { Box::new(TaskFfi), Box::new(InterruptFfi), Box::new(IfconfigFfi), + Box::new(NetdumpFfi), Box::new(RebootFfi), Box::new(ShutdownFfi), ]; @@ -169,6 +172,9 @@ const CODE: &str = "(export factorial (n) (Pure (-> (Int) Int)) (export ifconfig () (IO (-> () [])) (ifconfig_ffi)) +(export netdump (interface_id) (IO (-> (Int) [])) + (netdump_ffi interface_id)) + (export reboot () (IO (-> () [])) (reboot_ffi)) @@ -192,6 +198,7 @@ fn help_ffi() { lines.push_str("(task) ; print tasks\r\n"); lines.push_str("(interrupt) ; print interrupt information\r\n"); lines.push_str("(ifconfig) ; print network interfaces\r\n"); + lines.push_str("(netdump if); dump device registers\r\n"); lines.push_str("(reboot) ; reboot x86_64 systems\r\n"); lines.push_str("(shutdown) ; power off x86_64 systems\r\n"); @@ -247,6 +254,18 @@ fn ifconfig_ffi() { } } +#[embedded] +fn netdump_ffi(interface_id: BigInt) { + let Some(interface_id) = interface_id.to_u64() else { + console::print("netdump failed: interface_id must fit in u64\r\n"); + return; + }; + + if let Err(e) = awkernel_lib::net::debug_dump_interface(interface_id) { + console::print(&format!("netdump failed: {e}\r\n")); + } +} + #[embedded] fn reboot_ffi() { #[cfg(all(target_arch = "x86_64", target_os = "none"))] diff --git a/awkernel_drivers/src/pcie/intel/igc.rs b/awkernel_drivers/src/pcie/intel/igc.rs index 8f7b69644..fe114577a 100644 --- a/awkernel_drivers/src/pcie/intel/igc.rs +++ b/awkernel_drivers/src/pcie/intel/igc.rs @@ -315,6 +315,10 @@ impl NetDevice for Igc { .or(Err(net_device::NetDevError::DeviceError)) } + fn debug_dump(&self) { + self.inner.read().dump(); + } + fn add_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), net_device::NetDevError> { let mut inner = self.inner.write(); inner.multicast_addrs.add_addr(*addr); diff --git a/awkernel_lib/src/net.rs b/awkernel_lib/src/net.rs index b8446a086..90968cae0 100644 --- a/awkernel_lib/src/net.rs +++ b/awkernel_lib/src/net.rs @@ -428,6 +428,19 @@ pub fn get_interface(interface_id: u64) -> Result { Ok(if_status) } +pub fn debug_dump_interface(interface_id: u64) -> Result<(), NetManagerError> { + let net_manager = NET_MANAGER.read(); + + let if_net = net_manager + .interfaces + .get(&interface_id) + .ok_or(NetManagerError::InvalidInterfaceID)?; + + if_net.net_device.debug_dump(); + + Ok(()) +} + pub fn get_all_interface() -> Vec { let net_manager = NET_MANAGER.read(); diff --git a/awkernel_lib/src/net/net_device.rs b/awkernel_lib/src/net/net_device.rs index 17e2a9efa..6b6b8ff87 100644 --- a/awkernel_lib/src/net/net_device.rs +++ b/awkernel_lib/src/net/net_device.rs @@ -220,6 +220,9 @@ pub trait NetDevice { Ok(()) } + /// Dump device-specific debug state on demand. + fn debug_dump(&self) {} + fn add_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), NetDevError>; fn remove_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), NetDevError>; } From b4176f833279644d59bd65cf4c31331163734397 Mon Sep 17 00:00:00 2001 From: Yuuki Takano Date: Mon, 27 Apr 2026 03:14:18 +0000 Subject: [PATCH 2/3] Address netdump review feedback Clone the selected network device while holding the net manager read lock, then release the lock before invoking the debug dump path. This keeps potentially slow diagnostic dumping outside the shared manager lock and matches the existing interface operation pattern. --- awkernel_lib/src/net.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/awkernel_lib/src/net.rs b/awkernel_lib/src/net.rs index 90968cae0..57fd29771 100644 --- a/awkernel_lib/src/net.rs +++ b/awkernel_lib/src/net.rs @@ -429,14 +429,18 @@ pub fn get_interface(interface_id: u64) -> Result { } pub fn debug_dump_interface(interface_id: u64) -> Result<(), NetManagerError> { - let net_manager = NET_MANAGER.read(); + let net_device = { + let net_manager = NET_MANAGER.read(); - let if_net = net_manager - .interfaces - .get(&interface_id) - .ok_or(NetManagerError::InvalidInterfaceID)?; + let if_net = net_manager + .interfaces + .get(&interface_id) + .ok_or(NetManagerError::InvalidInterfaceID)?; + + if_net.net_device.clone() + }; - if_net.net_device.debug_dump(); + net_device.debug_dump(); Ok(()) } From a0ec611ec401f4a9833a78d93a0d406e16457e96 Mon Sep 17 00:00:00 2001 From: Yuuki Takano Date: Mon, 27 Apr 2026 18:43:29 +0900 Subject: [PATCH 3/3] reflect the review Signed-off-by: Yuuki Takano --- awkernel_drivers/src/pcie/intel/igc.rs | 7 ++++--- awkernel_lib/src/net.rs | 5 +++++ awkernel_lib/src/net/net_device.rs | 4 +++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/awkernel_drivers/src/pcie/intel/igc.rs b/awkernel_drivers/src/pcie/intel/igc.rs index fe114577a..976a67dd9 100644 --- a/awkernel_drivers/src/pcie/intel/igc.rs +++ b/awkernel_drivers/src/pcie/intel/igc.rs @@ -316,7 +316,8 @@ impl NetDevice for Igc { } fn debug_dump(&self) { - self.inner.read().dump(); + let msg = self.inner.read().dump(); + log::debug!("igc: dump:\r\n{msg}"); } fn add_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), net_device::NetDevError> { @@ -706,7 +707,7 @@ impl IgcInner { } } - fn dump(&self) { + fn dump(&self) -> alloc::string::String { let mut msg = alloc::string::String::new(); msg = format!("BDF: {}\r\n", self.info.get_bdf()); @@ -806,7 +807,7 @@ impl IgcInner { msg = format!("{msg}TDBAL{i}: {tdbal:#08x}\r\n"); } - log::debug!("igc: dump:\r\n{msg}"); + msg } #[inline(always)] diff --git a/awkernel_lib/src/net.rs b/awkernel_lib/src/net.rs index 57fd29771..5a7f8f8b4 100644 --- a/awkernel_lib/src/net.rs +++ b/awkernel_lib/src/net.rs @@ -428,6 +428,11 @@ pub fn get_interface(interface_id: u64) -> Result { Ok(if_status) } +/// Emit debug state for the interface identified by `interface_id` via `log::debug!`. +/// +/// Returns [`NetManagerError::InvalidInterfaceID`] if no interface with that ID exists. +/// The NET_MANAGER read lock is held only to look up and clone the device reference; +/// the device dump runs outside that lock. pub fn debug_dump_interface(interface_id: u64) -> Result<(), NetManagerError> { let net_device = { let net_manager = NET_MANAGER.read(); diff --git a/awkernel_lib/src/net/net_device.rs b/awkernel_lib/src/net/net_device.rs index 6b6b8ff87..f6a0685e2 100644 --- a/awkernel_lib/src/net/net_device.rs +++ b/awkernel_lib/src/net/net_device.rs @@ -221,7 +221,9 @@ pub trait NetDevice { } /// Dump device-specific debug state on demand. - fn debug_dump(&self) {} + fn debug_dump(&self) { + log::warn!("debug_dump not implemented for this device"); + } fn add_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), NetDevError>; fn remove_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), NetDevError>;