как использовать новое API ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS

Всем привет, версия ядра 4.19, хочу получить поддерживаемые 'link modes' с помощью API ethtool, моя сетевая карточка поддерживает много режимов:

Supported link modes:   1000baseKX/Full 
                            10000baseKR/Full 
                            40000baseKR4/Full 
                            40000baseCR4/Full 
                            40000baseSR4/Full 
                            40000baseLR4/Full 
                            25000baseCR/Full 
                            25000baseKR/Full 
                            25000baseSR/Full 
                            50000baseCR2/Full 
                            50000baseKR2/Full

и я хочу получать эти режимы из своей программы не используя терминал. вот пример кода:

#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32 (SCHAR_MAX)
#define ETHTOOL_DECLARE_LINK_MODE_MASK(name)     \
    uint32_t name[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32]


int netlink_get_link_speed (const char *dev_name, int *speed)
{
    int sock;
    struct ifreq ifr = {{{0}}};
    //struct ethtool_cmd edata = {0};
    int rc;
    //int err;
    struct {
        struct ethtool_link_settings req;
        __u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
    } ecmd;

/*
    struct ethtool_link_usettings {
        struct {
            uint8_t transceiver;
        } deprecated;
        struct ethtool_link_settings base;
        struct {
            ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
            ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
            ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
        } link_modes;
    };

    struct ethtool_link_usettings *link_usettings;
    unsigned int u32_offs;*/

    if (0 == strcmp(dev_name, "lo"))
    {
        *speed = 0;
        return ERR_OK;
    }

    sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (sock < 0) {
        err("Unable to open socket (for location)");
        return ERR_OK;
    }

    memset(&ecmd, 0, sizeof(ecmd));
    ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;

    strcpy(ifr.ifr_name, dev_name);
    ifr.ifr_data = (void *)&ecmd;

    rc = ioctl(sock, SIOCETHTOOL, &ifr);
    if (rc < 0)
    {
        err("Cannot read speed '%s' interface", dev_name);
        close(sock);
        return ERR_SYS_API;
    }

    /* see above: we expect a strictly negative value from kernel.
    */
    if (ecmd.req.link_mode_masks_nwords >= 0
        || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
    {
        err("Incorrect kernel answer");
        close(sock);
        *speed = 0;
        return ERR_SYS_API;
    }

    /* got the real ecmd.req.link_mode_masks_nwords,
    * now send the real request
    */
    ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
    ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
    rc = ioctl( sock, SIOCETHTOOL, &ifr);
    if (rc < 0)
    {
        err("Cannot read speed '%s' interface", dev_name);
        close(sock);
        return ERR_SYS_API;
    }

    if (ecmd.req.link_mode_masks_nwords <= 0
        || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
    {
        err("Incorrect kernel answer");
        close(sock);
        *speed = 0;
        return ERR_SYS_API;
    }
close(sock);
return 0;
}

я выяснил что информация(выставленные биты) вроде как содержатся в переменной link_mode_masks структуры ethtool_link_settings, но как применить не знаю, инфы в интернете не нашел. есть макрос в ethtool.h SUPPORTED_56000baseKR4_Full который путем сравнения битов можно узнать поддерживается этот режим или нет, но он уже устарел, и его просят не использовать, вот выдержка из ethtool.h:

    /* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
     * 31. Please do NOT define any SUPPORTED_* or ADVERTISED_*
     * macro for bits > 31. The only way to use indices > 31 is to
     * use the new ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API.
     */

так как 50000baseKR2/Full равна 35 d списке enum, то макрос написанный выше уже не подойдет. каким образом тогда можно получить поддерживается данный режим или нет?


Ответы (1 шт):