ethtool ioctl 返回未填充的 ethtool_link_settings

Posted

技术标签:

【中文标题】ethtool ioctl 返回未填充的 ethtool_link_settings【英文标题】:ethtool ioctl returns unpopulated ethtool_link_settings 【发布时间】:2018-03-30 11:23:54 【问题描述】:

我正在尝试使用 Ethtool ioctl API 从我的 NIC 中检索链接速度数据,但我只是在 ethtool_link_settings 实例中得到零。使用ethtool 命令行工具返回预期值,我的网卡驱动支持更新的ETHTOOL_GLINKSETTINGS API。

#include <iostream>
#include <cstring>

#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>

int main()

    auto ifn = if_nameindex();
    auto fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);

    for (auto i = ifn; i->if_name; ++i) 
        // Skip the loopback
        if (i->if_index == 1) 
            continue;
        

        std::cout << "Testing: " << i->if_name << std::endl;

        auto ifr = ifreq;
        std::strncpy(ifr.ifr_name, i->if_name, IF_NAMESIZE);

        auto msg = ethtool_link_settings;
        msg.cmd = ETHTOOL_GLINKSETTINGS;
        ifr.ifr_data = reinterpret_cast<char*>(&msg);

        if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) 
            std::cerr << "ioctl fail: " << strerror(errno) << std::endl;
        

        std::cout << "\tSpeed: " << msg.speed
                  << "\n\tDuplex: " << static_cast<int>(msg.duplex)
                  << "\n\tPort: " << static_cast<int>(msg.port)
                  << std::endl;
    

    close(fd);
    if_freenameindex(ifn);
    return EXIT_SUCCESS;

结果:

Testing: enp0s3
    Speed: 0
    Duplex: 0
    Port: 0
Testing: enp0s8
    Speed: 0
    Duplex: 0
    Port: 0
Testing: enp0s9
    Speed: 0
    Duplex: 0
    Port: 0
Testing: enp0s10
    Speed: 0
    Duplex: 0
    Port: 0

我确定我在做一些愚蠢的事情,但我看不到。

【问题讨论】:

您可以尝试使用 ETHTOOL_GSET 而不是 ETHTOOL_GLINKSETTINGS 吗? (在这种情况下使用auto msg = ethtool_cmd; 而不是auto msg = ethtool_link_settings; 【参考方案1】:

埋在/usr/include/linux/ethtool.hstruct ethtool_link_settingslink_mode_masks_nwords 字段的 cmets 中是一些令人钦佩的神秘 cmets,ETHTOOL_GLINKSETTINGS 会进行一些握手,因此您需要多次调用它。

我已使用ethtool command 的代码将您的代码调整为 执行 ETHTOOL_GLINKSETTINGS 命令:

#include <iostream>
#include <cstring>

#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <linux/netlink.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>

int main()

    auto ifn = if_nameindex();
    auto fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);

    for (auto i = ifn; i->if_name; ++i) 
        struct 
                struct ethtool_link_settings req;
                __u32 link_mode_data[3 * 127];
             ecmd;

        // Skip the loopback
        if (i->if_index == 1) 
            continue;
        

        std::cout << "Testing: " << i->if_name << std::endl;

        auto ifr = ifreq;
        std::strncpy(ifr.ifr_name, i->if_name, IF_NAMESIZE);

        ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
        ifr.ifr_data = reinterpret_cast<char*>(&ecmd);

        if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) 
            std::cerr << "ioctl fail: " << strerror(errno) << std::endl;
            return 1;
        

        if (ecmd.req.link_mode_masks_nwords >= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
            return 1;

        ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;

        if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) 
            std::cerr << "ioctl fail: " << strerror(errno) << std::endl;
            return 1;
        

        std::cout << "\tSpeed: " << ecmd.req.speed
                  << "\n\tDuplex: " << static_cast<int>(ecmd.req.duplex)
                  << "\n\tPort: " << static_cast<int>(ecmd.req.port)
                  << std::endl;
    

    close(fd);
    if_freenameindex(ifn);
    return EXIT_SUCCESS;

【讨论】:

以上是关于ethtool ioctl 返回未填充的 ethtool_link_settings的主要内容,如果未能解决你的问题,请参考以下文章

ethtool原理介绍和解决网卡丢包排查思路

CentOS网卡无法联网,ethtool显示Link detected: no Speed: Unknown! Duplex: Unknown! (255)

管道到标准输入时使用ioctl填充winsize结构

ioctl 返回 ENOENT 尝试将 URB 请求发布到 Isoc 设备端点(从 android 的 JNI 访问)

错误 C2065:“IOCTL_NDISUIO_OPEN_DEVICE”:未声明的标识符

尽管路径被填充,猫鼬填充()返回未定义