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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 18:37:58  来源:igfitidea点击:

How to get NIC details from a C program?

clinux

提问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 fdis an AF_INETsocket.

您可以使用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_datapointing to a struct ethtool_cmdhaving 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 getifaddrsfunction with a working example

以下链接getifaddrs通过一个工作示例很好地解释了该功能

getifaddrs()

getifaddrs()