如何在Rust中借助ethtool获取NIC设备统计信息?
在Rust中实现
ethtool -S等效功能 手动实现netlink交互(最简无依赖)
如果不想依赖第三方库,直接通过netlink与内核通信是最直接的方式,核心是处理ETHTOOL的GET_STATS命令:
步骤分解
- 创建NETLINK_GENERIC套接字:
用libc直接创建套接字,指定AF_NETLINK和NETLINK_GENERIC协议。 - 获取ETHTOOL的family ID:
发送CTRL_CMD_GETFAMILY请求到GENL_ID_CTRL,查询ETHTOOL对应的family编号,这是后续请求的基础。 - 构造GET_STATS请求:
组装genl消息,设置命令为ETHTOOL_MSG_GET_STATS,并添加ETHTOOL_A_HEADER_DEV_NAME属性指定目标网卡。 - 解析响应:
内核返回的消息中包含ETHTOOL_A_STATS数组,每个元素包含ETHTOOL_A_STAT_NAME(统计项名称)和ETHTOOL_A_STAT_VALUE(数值),遍历提取即可。
核心代码片段(简化版)
use libc::{c_int, c_void, size_t, socket, AF_NETLINK, SOCK_RAW, NETLINK_GENERIC, sendto, recvfrom}; use std::ffi::CString; use std::mem::zeroed; const GENL_ID_CTRL: u16 = 0x10; const CTRL_CMD_GETFAMILY: u8 = 3; const ETHTOOL_MSG_GET_STATS: u8 = 0x13; const ETHTOOL_A_HEADER_DEV_NAME: u16 = 0x01; const ETHTOOL_A_STATS: u16 = 0x02; const ETHTOOL_A_STAT_NAME: u16 = 0x01; const ETHTOOL_A_STAT_VALUE: u16 = 0x02; fn get_nic_stats(ifname: &str) -> Result<Vec<(String, u64)>, std::io::Error> { // 创建socket let sock_fd = unsafe { socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC) }; if sock_fd < 0 { return Err(std::io::Error::last_os_error()); } // 省略查询ETHTOOL family ID的代码(需构造并发送CTRL_CMD_GETFAMILY请求) // 假设已获取到ethtool_family_id // 构造GET_STATS请求 let ifname_cstr = CString::new(ifname)?; // 组装netlink消息头、genl消息头和属性(需严格遵循netlink属性格式:nla_len, nla_type, payload) // 发送请求 // 此处替换为实际的消息缓冲区 let msg_buf = Vec::new(); let send_result = unsafe { sendto( sock_fd, msg_buf.as_ptr() as *const c_void, msg_buf.len() as size_t, 0, std::ptr::null(), 0, ) }; if send_result < 0 { return Err(std::io::Error::last_os_error()); } // 接收并解析响应 let mut recv_buf = [0u8; 4096]; let recv_len = unsafe { recvfrom( sock_fd, recv_buf.as_mut_ptr() as *mut c_void, recv_buf.len() as size_t, 0, std::ptr::null_mut(), std::ptr::null_mut(), ) }; if recv_len < 0 { return Err(std::io::Error::last_os_error()); } // 解析recv_buf中的统计项,提取名称和数值 let mut stats = Vec::new(); // 省略解析逻辑:遍历ETHTOOL_A_STATS数组,逐个提取ETHTOOL_A_STAT_NAME和ETHTOOL_A_STAT_VALUE Ok(stats) }
解决你遇到的错误
你之前用neli库遇到的device not found或operation not supported,大概率是以下原因:
- 权限不足:需要root或
CAP_NET_ADMIN权限,普通用户无法访问ethtool的netlink接口 - 设备名错误:确认网卡名称正确(可通过
ls /sys/class/net/查看) - family ID未正确获取:ETHTOOL的family ID不是固定值,必须通过
GENL_ID_CTRL查询,不能硬编码 - 属性ID不匹配:不同内核版本的ETHTOOL属性ID可能有变化,需对应目标内核的定义
基于现有库的快速方案
如果你不想从零写netlink逻辑,可以扩展ethtool库:
- 参考内核源码中
ethtool -S的实现,复制对应的netlink消息构造逻辑 - 复用
ethtool库已有的NetlinkConnection和属性处理代码,添加get_stats方法 - 测试验证后可以提交PR给上游库,也可以自己fork使用
内容的提问来源于stack exchange,提问作者mohitmayank
相关产品推荐
相关产品推荐

