使用ioctl获取网卡统计信息
ethtool -S获取接口统计信息总共分三步:
1、获取统计项个数,使用SIOCETHTOOL+ETHTOOL_GSSET_INFO
2、(可选)获取统计项名字,使用SIOCETHTOOL+ETHTOOL_GSTRINGS,需要使用第1步中获取的统计项个数来申请足够大的内存
3、获取统计值,使用SIOCETHTOOL+ETHTOOL_GSTATS,需要使用第1步中获取的统计项个数来申请足够大的内存
上代码:
#include <sys/types.h> #include <string.h> #include <stdlib.h> #include <sys/ioctl.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <net/if.h> #include <linux/sockios.h> #include <linux/ethtool.h> int main(int argc, char* argv[]) { int fd; int ret; unsigned int n_stats, i; struct ifreq ifr; struct { struct ethtool_sset_info hdr; unsigned int buf[1]; } sset_info; struct ethtool_stats *stats; struct ethtool_gstrings *strings; unsigned int sz_stats; fd = socket(AF_INET, SOCK_DGRAM, 0); sset_info.hdr.cmd = ETHTOOL_GSSET_INFO; sset_info.hdr.reserved = 0; sset_info.hdr.sset_mask = 1ULL << ETH_SS_STATS; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, "eth2"); ifr.ifr_data = (void*)&sset_info; ret = ioctl(fd, SIOCETHTOOL, &ifr); if (0 != ret) { printf("ETHTOOL_GSSET_INFO errno=%d\n", errno); return -1; } n_stats = sset_info.hdr.sset_mask ? sset_info.hdr.data[0] : 0; printf("stats n_stats=%d\n", n_stats); /*strings = calloc(1, sizeof(*strings) + n_stats * ETH_GSTRING_LEN); if (!strings) return -1; strings->cmd = ETHTOOL_GSTRINGS; strings->string_set = ETH_SS_STATS; strings->len = n_stats; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, "eth2"); ifr.ifr_data = (void*)strings; ret = ioctl(fd, SIOCETHTOOL, &ifr); if (0 != ret) { printf("ETH_SS_STATS, errno=%d\n", errno); return -1; } */ sz_stats = n_stats * sizeof(unsigned long long); stats = calloc(1, sz_stats + sizeof(struct ethtool_stats)); stats->cmd = ETHTOOL_GSTATS; stats->n_stats = n_stats; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, "eth2"); ifr.ifr_data = (void*)stats; ret = ioctl(fd, SIOCETHTOOL, &ifr); if (0 != ret) { printf("ETHTOOL_GSTATS errno=%d\n", errno); return -1; } for (i = 0; i < n_stats; i++) { printf("%llu\n", stats->data[i]); } return 0; }