You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中借助ethtool获取NIC设备统计信息?

在Rust中实现ethtool -S等效功能

手动实现netlink交互(最简无依赖)

如果不想依赖第三方库,直接通过netlink与内核通信是最直接的方式,核心是处理ETHTOOL的GET_STATS命令:

步骤分解

  1. 创建NETLINK_GENERIC套接字:
    用libc直接创建套接字,指定AF_NETLINK和NETLINK_GENERIC协议。
  2. 获取ETHTOOL的family ID:
    发送CTRL_CMD_GETFAMILY请求到GENL_ID_CTRL,查询ETHTOOL对应的family编号,这是后续请求的基础。
  3. 构造GET_STATS请求:
    组装genl消息,设置命令为ETHTOOL_MSG_GET_STATS,并添加ETHTOOL_A_HEADER_DEV_NAME属性指定目标网卡。
  4. 解析响应:
    内核返回的消息中包含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库:

  1. 参考内核源码中ethtool -S的实现,复制对应的netlink消息构造逻辑
  2. 复用ethtool库已有的NetlinkConnection和属性处理代码,添加get_stats方法
  3. 测试验证后可以提交PR给上游库,也可以自己fork使用

内容的提问来源于stack exchange,提问作者mohitmayank

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:25:11