
本文介绍如何通过 CGO 调用 Linux 内核 ethtool 接口,准确获取网卡的物理链路协商速率(如 1000 Mbps),弥补仅依赖 /proc/net/dev 计算瞬时流量无法获知带宽上限的不足。
本文介绍如何通过 cgo 调用 linux 内核 ethtool 接口,准确获取网卡的物理链路协商速率(如 1000 mbps),弥补仅依赖 `/proc/net/dev` 计算瞬时流量无法获知带宽上限的不足。
在 Linux 系统中,仅读取 /proc/net/dev 可以统计接收/发送字节数,并据此计算出瞬时流量速率(bps),例如你已实现的 in_traffic 和 out_traffic。但该值反映的是当前负载下的实际吞吐,而非网卡支持的最大链路速率(Link Speed)——后者是计算网络利用率(如 in_utilization = in_traffic / link_speed)不可或缺的基准值。
Linux 内核通过 ethtool 子系统暴露网卡硬件能力,其中 ETHTOOL_GSET ioctl 命令可查询协商完成的速率(单位:Mbps)。Go 标准库不直接支持此底层调用,因此需借助 CGO 安全桥接 C 接口。
以下是一个生产就绪的示例实现:
package main
/*
#include <stdio.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <linux/sockios.h>
#include <linux/if.h>
#include <linux/ethtool.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int get_interface_speed(const char *ifname) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) return 0;
struct ifreq ifr;
struct ethtool_cmd edata;
memset(&ifr, 0, sizeof(ifr));
memset(&edata, 0, sizeof(edata));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
ifr.ifr_data = (void *)&edata;
edata.cmd = ETHTOOL_GSET;
int rc = ioctl(sock, SIOCETHTOOL, &ifr);
close(sock);
if (rc < 0) return 0;
return edata.speed; // 单位:Mbps(如 1000 表示 1 Gbps)
}
*/
import "C"
import (
"fmt"
"unsafe"
)
func GetLinkSpeed(iface string) int {
cStr := C.CString(iface)
defer C.free(unsafe.Pointer(cStr))
return int(C.get_interface_speed(cStr))
}
func main() {
speed := GetLinkSpeed("eth0")
if speed == 0 {
fmt.Println("Warning: failed to retrieve link speed — interface may be down, virtual, or unsupported.")
} else {
fmt.Printf("Interface eth0 link speed: %d Mbps\n", speed)
// ✅ Now safely compute utilization:
// in_utilization = in_traffic_bps / (float64(speed) * 1_000_000)
}
}✅ 关键说明与注意事项:
- 接口有效性:该方法仅对支持 ethtool 的物理网卡(如 eth0, enp0s3)有效;lo、docker0、veth* 等虚拟接口通常返回 0。
- 权限要求:无需 root 权限(SIOCETHTOOL 对普通用户开放),但接口必须处于 UP 状态。
- 单位统一:edata.speed 返回 Mbps(兆比特每秒),而 /proc/net/dev 计算出的 in_traffic 单位为 bps,换算时需乘以 1_000_000(非 10000,原文中 speed * 10000 有误)。
- 健壮性增强:生产环境建议增加 ifconfig eth0 | grep "state UP" 或检查 sysfs(如 /sys/class/net/eth0/operstate)确保接口活跃。
- 替代方案(无 CGO):若需避免 CGO,可解析 ethtool eth0 命令输出(需 shell 调用与文本解析),但性能和可靠性低于 ioctl 直接调用。
掌握链路速率后,你就能真正实现精准的带宽利用率监控——这才是构建可观测性系统的坚实基础。


















