8

コンピューターに接続されているすべての NIC について、次の詳細を取得したいと考えています。

1) インターフェース名 (例: eth0)

2) Linux にそのようなものが存在する場合は、( Windowsのような) インターフェース番号

3) NIC 帯域幅の容量とモード (例: 1Gb/s 全二重)

4

4 に答える 4

18

getifaddrs()/freeifaddrs()を使用して、すべてのインターフェイスのリンク リストをioctl(fd, SIOCGIFINDEX, struct ifreq *)取得し、それぞれのインターフェイス インデックスを取得できます。インターフェイスは連続しており、常にリストされているため (アップ (アクティブ) かどうかに関係なく)、代わりにループを使用してそれらを列挙することにしましたioctl(fd, SIOCGIFNAME, struct ifreq *)。いずれの場合もfdソケットAF_INETです。

インターフェイスのデュプレックスと速度を取得するには、 をを指すioctl(fd, SIOCETHTOOL, struct ifreq *)とともに使用する必要があります。ifr_datastruct ethtool_cmdcmd = ETHTOOL_GSET

ioctl は、失敗した場合は -1 を返し、成功した場合は負でない値 (ゼロだと思います) を返します。

以下にプログラム例を示します。

#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] = '\0';

    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] = '\0';

    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;
}

上記を として保存するとiflist.c、次を使用してコンパイルできます。

gcc -W -Wall -O3 iflist.c -o iflist

使用状況を確認するには、 を実行しますiflist -h。すべてのインターフェイスを一覧表示するには、パラメーターを指定せずに実行します。

./iflist

上記は、私が説明した列挙方法を使用します。特定のインターフェイスのみを一覧表示するには、インターフェイスに名前を付けて実行します。

./iflist eth0 lo

もちろん、デュプレックスと速度はイーサネットインターフェイスについてのみリストされています。


追加するために編集:

上記のプログラムがインターフェイスの帯域幅とモードを提供しない場合、正確な理由 (エラー) を報告する簡易バージョンを次に示します。これはインターフェイス名をコマンドライン パラメータとして受け取ります。インターフェイスを列挙しません。

#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;
}

質問?

于 2013-01-10T20:30:25.390 に答える
4

(1) getifaddrs()

(2) if_indextoname()if_nameindex()if_nametoindex()

(3) これについてはよくわかりませんが、ioctl()SIOCGIF*パラメーターの 1 つまたは から取得できる可能性があります/proc

于 2013-01-10T19:41:32.973 に答える
2

次のリンクgetifaddrsは、実際の例で機能をよく説明しています

getifaddrs()

于 2013-01-10T19:55:24.130 に答える
1
ethtool eth1

このコマンドは、速度、デュプレックス、ポートなど、eth1に関するすべての詳細を一覧表示します。

popen()を使用して出力を取得し、マップすることができます。

POPEN(3)Linuxプログラマーマニュアル
POPEN(3)

NAME popen、pclose-プロセスとの間のパイプストリーム

概要#include

   FILE *popen(const char *command, const char *type);
于 2013-01-10T18:12:46.177 に答える