Linux 如何从 C 程序中获取 NIC 详细信息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14264371/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get NIC details from a C program?
提问by Bruce
I want to get the following details for all the NICs attached to my computer:
我想获取连接到我的计算机的所有 NIC 的以下详细信息:
1) Interface name (eg. eth0)
1) 接口名称(例如 eth0)
2) Interface Number (like in Windows) if such a thing exists in Linux
2) 接口编号(如在Windows 中),如果 Linux 中存在这样的东西
3) NIC bandwidth capacity and mode (eg. 1Gb/s full duplex)
3) NIC 带宽容量和模式(例如 1Gb/s 全双工)
采纳答案by Nominal Animal
You can use getifaddrs()
/freeifaddrs()
to obtain a linked list of all interfaces, then ioctl(fd, SIOCGIFINDEX, struct ifreq *)
to obtain the interface index for each. Since the interfaces are consecutive and always listed (regardless of whether or they are up (active) or not), I choose to enumerate them with a loop using ioctl(fd, SIOCGIFNAME, struct ifreq *)
instead. In all cases fd
is an AF_INET
socket.
您可以使用getifaddrs()
/freeifaddrs()
获取所有接口的链表,然后ioctl(fd, SIOCGIFINDEX, struct ifreq *)
获取每个接口的索引。由于接口是连续的并且始终列出(无论它们是否启动(活动)),我选择使用循环来枚举它们ioctl(fd, SIOCGIFNAME, struct ifreq *)
。在所有情况下fd
都是一个AF_INET
套接字。
To obtain the duplex and speed of the interface, you need to use the ioctl(fd, SIOCETHTOOL, struct ifreq *)
with the ifr_data
pointing to a struct ethtool_cmd
having cmd = ETHTOOL_GSET
.
要获得接口的双工和速度,您需要使用ioctl(fd, SIOCETHTOOL, struct ifreq *)
并ifr_data
指向一个struct ethtool_cmd
具有cmd = ETHTOOL_GSET
。
The ioctls should return -1 if they fail, and a nonnegative value (zero, I believe) if success.
如果失败,ioctl 应该返回 -1,如果成功则返回非负值(我相信为零)。
Here is an example program:
这是一个示例程序:
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct interface {
int index;
int flags; /* IFF_UP etc. */
long speed; /* Mbps; -1 is unknown */
int duplex; /* DUPLEX_FULL, DUPLEX_HALF, or unknown */
char name[IF_NAMESIZE + 1];
};
static int get_interface_common(const int fd, struct ifreq *const ifr, struct interface *const info)
{
struct ethtool_cmd cmd;
int result;
/* Interface flags. */
if (ioctl(fd, SIOCGIFFLAGS, ifr) == -1)
info->flags = 0;
else
info->flags = ifr->ifr_flags;
ifr->ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET; /* "Get settings" */
if (ioctl(fd, SIOCETHTOOL, ifr) == -1) {
/* Unknown */
info->speed = -1L;
info->duplex = DUPLEX_UNKNOWN;
} else {
info->speed = ethtool_cmd_speed(&cmd);
info->duplex = cmd.duplex;
}
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1)
return errno;
return 0;
}
int get_interface_by_index(const int index, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (index < 1 || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
ifr.ifr_ifindex = index;
if (ioctl(socketfd, SIOCGIFNAME, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = index;
strncpy(info->name, ifr.ifr_name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = 'gcc -W -Wall -O3 iflist.c -o iflist
';
return get_interface_common(socketfd, &ifr, info);
}
int get_interface_by_name(const char *const name, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (!name || !*name || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(socketfd, SIOCGIFINDEX, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = ifr.ifr_ifindex;
strncpy(info->name, name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = './iflist
';
return get_interface_common(socketfd, &ifr, info);
}
int main(int argc, char *argv[])
{
struct interface iface;
int arg;
int status = 0;
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s { -h | --help }\n", argv[0]);
fprintf(stderr, " %s\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 1;
}
if (argc > 1) {
for (arg = 1; arg < argc; arg++) {
if (get_interface_by_name(argv[arg], &iface) != 0) {
fprintf(stderr, "%s: No such interface.\n", argv[arg]);
status = 1;
continue;
}
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
} else {
for (arg = 1; ; arg++) {
if (get_interface_by_index(arg, &iface) != 0)
break;
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
}
return status;
}
If you save the above as iflist.c
, you can compile it using
如果将上述内容另存为iflist.c
,则可以使用
./iflist eth0 lo
To see the usage, run iflist -h
. To list all interfaces, run it without parameters:
要查看用法,请运行iflist -h
. 要列出所有接口,请在不带参数的情况下运行它:
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int ethernet_interface(const char *const name,
int *const index, int *const speed, int *const duplex)
{
struct ifreq ifr;
struct ethtool_cmd cmd;
int fd, result;
if (!name || !*name) {
fprintf(stderr, "Error: NULL interface name.\n");
fflush(stderr);
return errno = EINVAL;
}
if (index) *index = -1;
if (speed) *speed = -1;
if (duplex) *duplex = -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
const int err = errno;
fprintf(stderr, "%s: Cannot create AF_INET socket: %s.\n", name, strerror(err));
fflush(stderr);
return errno = err;
}
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
ifr.ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET;
if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
const int err = errno;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
fprintf(stderr, "%s: SIOCETHTOOL ioctl: %s.\n", name, strerror(err));
return errno = err;
}
if (speed)
*speed = ethtool_cmd_speed(&cmd);
if (duplex)
switch (cmd.duplex) {
case DUPLEX_HALF: *duplex = 0; break;
case DUPLEX_FULL: *duplex = 1; break;
default:
fprintf(stderr, "%s: Unknown mode (0x%x).\n", name, cmd.duplex);
fflush(stderr);
*duplex = -1;
}
if (index && ioctl(fd, SIOCGIFINDEX, &ifr) >= 0)
*index = ifr.ifr_ifindex;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int err = errno;
fprintf(stderr, "%s: Error closing socket: %s.\n", name, strerror(err));
return errno = err;
}
return 0;
}
int main(int argc, char *argv[])
{
int arg, speed, index, duplex;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 0;
}
for (arg = 1; arg < argc; arg++) {
if (ethernet_interface(argv[arg], &index, &speed, &duplex))
return 1;
if (index == -1)
printf("%s: (no interface index)", argv[arg]);
else
printf("%s: interface %d", argv[arg], index);
if (speed == -1)
printf(", unknown bandwidth");
else
printf(", %d Mbps bandwidth", speed);
if (duplex == 0)
printf(", half duplex.\n");
else if (duplex == 1)
printf(", full duplex.\n");
else
printf(", unknown mode.\n");
}
return 0;
}
The above will use the enumeration method I described. To list only specific interfaces, run it naming the interfaces:
上面将使用我描述的枚举方法。要仅列出特定接口,请运行它命名接口:
ethtool eth1
Duplex and speed is only listed for ethernet interfaces, of course.
当然,双工和速度仅针对以太网接口列出。
Edited to add:
编辑添加:
If the above program does not supply the bandwidth and mode for an interface, here is a simplified version which reports the exact reason (errors). This one takes the interface names as commandline parameters; it does not enumerate interfaces.
如果上面的程序没有为接口提供带宽和模式,这里是一个报告确切原因(错误)的简化版本。这个将接口名称作为命令行参数;它不枚举接口。
FILE *popen(const char *command, const char *type);
Questions?
问题?
回答by george
FILE *popen(const char *command, const char *type);
this command will list all the details about eth1 including speed, duplex, port...
此命令将列出有关 eth1 的所有详细信息,包括速度、双工、端口...
you can use popen() to get the output and map it.
您可以使用 popen() 获取输出并映射它。
POPEN(3) Linux Programmer's Manual
POPEN(3)NAME popen, pclose - pipe stream to or from a process
SYNOPSIS #include
##代码##
POPEN(3) Linux 程序员手册
POPEN(3)NAME popen, pclose - 进出进程的管道流
概要#include
##代码##
回答by Duck
(1) getifaddrs()
(1) getifaddrs()
(2) if_indextoname(), if_nameindex(), if_nametoindex()
(2) if_indextoname(), if_nameindex(), if_nametoindex()
(3) I'm not sure about this one but you might be able to get at it through ioctl()and one of the SIOCGIF*
parameters or from /proc
.
(3) 我不确定这个,但您可以通过ioctl()和SIOCGIF*
参数之一或从/proc
.
回答by Davide Berra
the following link well explain the getifaddrs
function with a working example
以下链接getifaddrs
通过一个工作示例很好地解释了该功能