提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:这里可以添加本文要记录的大概内容:
linux服务器下统计 网卡信息
可以通过sys节点统计
提示:以下是本篇文章正文内容,下面案例可供参考
一、sys节点统计服务器网卡信息?
sys节点查看:
查询系统中所有网络设备:
ls /sys/class/net/ 每一个目录都是一个网络设备
如何确定不是 虚拟设备而是真正的网络设备
目前查看 cat /sys/class/net/enp2s0/type 的值是 1(此方法不能区分vlan eth0和eth0.1,能区分lo,和网络隧道设备)
获取网卡的 属性:
address:mac地址
speed:当前速率
duplex:全双工/半双工
carrier:网络设备 up/down
statistics统计属性:
rx_dropped: 接收丢包
tx_dropped:发送丢包
rx_bytes:接收数据
tx_bytes:发送数据
二、通过socket获取网卡的速率和自协商,并进行online selftest
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/ethtool.h> // 包含 ethtool 相关定义
#include <linux/sockios.h>
#include <unistd.h>
#include <stddef.h>
#include <errno.h>
typedef unsigned long long u64;
typedef unsigned int u32;
int send_ioctl(int socket, char * if_name, void *cmd)
{
struct ifreq ifr = {0};
if(if_name == NULL)
{
return -1;
}
ifr.ifr_data = cmd;
strcpy(ifr.ifr_name, if_name);
return ioctl(socket, SIOCETHTOOL, &ifr);
}
static struct ethtool_gstrings *
get_stringset(int socket, enum ethtool_stringset set_id,
ptrdiff_t drvinfo_offset, char * if_name)
{
struct {
struct ethtool_sset_info hdr;
u32 buf[1];
} sset_info;
struct ethtool_drvinfo drvinfo;
u32 len, i;
struct ethtool_gstrings *strings;
sset_info.hdr.cmd = ETHTOOL_GSSET_INFO;
sset_info.hdr.reserved = 0;
sset_info.hdr.sset_mask = 1ULL << set_id;
if (send_ioctl(socket, if_name, &sset_info) == 0) {
const u32 *sset_lengths = sset_info.hdr.data;
len = sset_info.hdr.sset_mask ? sset_lengths[0] : 0;
} else if (errno == EOPNOTSUPP && drvinfo_offset != 0) {
/* Fallback for old kernel versions */
drvinfo.cmd = ETHTOOL_GDRVINFO;
if (send_ioctl(socket, if_name, &drvinfo))
return NULL;
len = *(u32 *)((char *)&drvinfo + drvinfo_offset);
} else {
return NULL;
}
strings = calloc(1, sizeof(*strings) + len * ETH_GSTRING_LEN);
if (!strings)
return NULL;
strings->cmd = ETHTOOL_GSTRINGS;
strings->string_set = set_id;
strings->len = len;
if (len != 0 && send_ioctl(socket, if_name, strings)) {
free(strings);
return NULL;
}
for (i = 0; i < len; i++)
strings->data[(i + 1) * ETH_GSTRING_LEN - 1] = 0;
return strings;
}
int netdev_selftest(char *name)
{
int sockfd;
struct ifreq ifr;
char if_name[16] = {0};
// 创建一个新的套接字
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("Failed to create socket");
return -1;
}
strncpy(if_name, name, 16);
struct ethtool_test *test;
struct ethtool_gstrings *strings;
strings = get_stringset(sockfd, ETH_SS_TEST, offsetof(struct ethtool_drvinfo, testinfo_len), if_name);
if (!strings) {
perror("Cannot get strings");
return -1;
}
test = malloc(sizeof(*test) + strings->len * sizeof(u64));
printf("sizeof(*test) + strings->len * sizeof(u64) = %d\n", sizeof(*test) + strings->len * sizeof(u64));
memset(test, 0, sizeof(*test) + strings->len * sizeof(u64));
test->cmd = ETHTOOL_TEST;
test->len = 0;
test->flags = 0; // ONLINE
// 设置 ifr 结构体中的 ifr_data 成员为指向 ethtool 命令的指针
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, if_name);
// 将 ethtool 命令的指针设置为 ifr 的 ifr_data 字段
ifr.ifr_data = (void*)test;
// 发送 ioctl 命令 SIOCETHTOOL 到内核
if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) {
perror("Cannot test");
close(sockfd);
free(test);
free(strings);
}
int rc = test->flags & ETH_TEST_FL_FAILED;
fprintf(stdout, "The test result is %s\n", rc ? "FAIL" : "PASS");
printf("test->len = %d\n", test->len);
for (int i = 0; i < strings->len; i++) {
fprintf(stdout, "%s\t %d\n",
(char *)(strings->data + i * ETH_GSTRING_LEN),
(u32) test->data[i]);
}
free(test);
free(strings);
close(sockfd);
return 0;
}
int main(int argc, char *argv[]) {
int sockfd;
struct ifreq ifr;
struct ethtool_cmd cmd;
if (argc != 2) {
fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
return 1;
}
// 创建一个套接字
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
return 1;
}
// 初始化 ifr 结构体
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1);
// 初始化 ethtool_cmd 结构体
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = ETHTOOL_GSET; // 设置 ioctl 请求为 ETHTOOL_GSET
// 将 ethtool_cmd 结构体指针赋给 ifr.ifr_data
ifr.ifr_data = (char *)&cmd;
// 使用 ioctl 调用来获取设置信息
if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) {
perror("ioctl(SIOCETHTOOL)");
close(sockfd);
return 1;
}
// 关闭套接字
close(sockfd);
// 输出速度和双工模式
printf("Interface '%s':\n", argv[1]);
printf(" Speed: %d Mbps\n", cmd.speed);
printf(" Duplex: %s\n", (cmd.duplex == DUPLEX_HALF) ? "Half" : "Full");
printf(" advertising: 0x%x\n", cmd.advertising);
printf(" autoneg: 0x%x\n", cmd.autoneg);
netdev_selftest(argv[1]); //online self_test
return 0;
}
总结
主要介绍了 linux服务器下网络设备的sys节点和c代码简单获取当前速率和自协商状态并进行online selftest,online selftest的代码从ethtool工具代码中提取的。