LINUX.ORG.RU

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

 ,


0

1

Всем привет, версия ядра 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 в списке enum, то макрос написанный выше уже не подойдет. каким образом тогда можно получить поддерживается данный режим или нет?



Последнее исправление: lignumq (всего исправлений: 1)

он уже устарел, и его просят не использовать

Нет. Комментарий говорит не создавать больше 32 таких макросов.

xaizek ★★★★★
()
Ответ на: комментарий от lignumq

The only way to use indices > 31 is to use the new ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API.

тут же все как в анекдоте про гвозди...

safocl ★★
()
Ответ на: комментарий от lignumq

Речь о размере в битах, а не о значении в десятичной системе. 35 занимает 6 бит (100011), что меньше 32. Так что просто использовать этот макрос и всё. Как-то так:

(ecmd.req.link_mode_masks & SUPPORTED_56000baseKR4_Full) == SUPPORTED_56000baseKR4_Full
xaizek ★★★★★
()
Ответ на: комментарий от xaizek

что то не получилось я добавил пару проверок с дебагом, я воспользовался не макросом(потому что такого нет) а сделал то же самое что делает этот макрос, ни в один if не зашла программа

    {
        if (ecmd.req.link_mode_masks[0] & (1UL << ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT))
        {
            err("SUPPORTED");
        }
        if ((ecmd.req.link_mode_masks[0] & (1UL << ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT)) == (1UL << ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT))
        {
            err("SUPPORTED2");
        }
    }
lignumq
() автор топика
Ответ на: комментарий от xaizek

в общем косвенно ссылка помогла, там внутри есть ссылка на исходники, и оттуда достал как можно получать то что мне нужно может кому то еще пригодится: https://kernel.googlesource.com/pub/scm/network/ethtool/ethtool/+/af5af00a644e117c573d9afe591f8ce51348953f/ethtool.c#2442 по этой ссылке смотрим как работает функция(строка 602):

static void dump_link_caps(const char *prefix, const char *an_prefix, const u32 *mask, int link_mode_only)

внутри нее находим вызов функции

ethtool_link_mode_test_bit()

в которой как раз происходит сравнение битов. исходники второй фукнкции по этой ссылке: https://github.com/Kamalheib/ethtool/blob/b888f358763a20625a381e071ea50524a520c7c1/internal.h строка 176

lignumq
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.