Please, help me get ethtool settings (speed, duplex, autoneg).
If I use ETHTOOL_GSET, I get ethtool settings. But in ethtool.h written to use ETHTOOL_GLINKSETTINGS instead of ETHTOOL_GSET. I don't know how to use ETHTOOL_GLINKSETTINGS.
ETHTOOL_GSET
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
int main()
{
int s; // socket
int r; // result
struct ifreq ifReq;
strncpy(ifReq.ifr_name, "enp3s0", sizeof(ifReq.ifr_name));
struct ethtool_cmd ethtoolCmd;
ethtoolCmd.cmd = ETHTOOL_GSET;
ifReq.ifr_data = ðtoolCmd;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
r = ioctl(s, SIOCETHTOOL, &ifReq);
if (s != -1)
{
printf("%s | ethtool_cmd.speed = %i \n", ifReq.ifr_name, ethtoolCmd.speed);
printf("%s | ethtool_cmd.duplex = %i \n", ifReq.ifr_name, ethtoolCmd.duplex);
printf("%s | ethtool_cmd.autoneg = %i \n", ifReq.ifr_name, ethtoolCmd.autoneg);
}
else
printf("Error #r");
close(s);
}
else
printf("Error #s");
return 0;
}
Result:
enp3s0 | ethtool_cmd.speed = 1000
enp3s0 | ethtool_cmd.duplex = 1
enp3s0 | ethtool_cmd.autoneg = 1
ETHTOOL_GLINKSETTINGS
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
int main()
{
int s; // socket
int r; // result
struct ifreq ifReq;
strncpy(ifReq.ifr_name, "enp3s0", sizeof(ifReq.ifr_name));
struct ethtool_link_settings ethtoolLinkSettings;
ethtoolLinkSettings.cmd = ETHTOOL_GLINKSETTINGS;
ifReq.ifr_data = ðtoolLinkSettings;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
r = ioctl(s, SIOCETHTOOL, &ifReq);
if (s != -1)
{
printf("%s | ethtool_link_settings.speed = %i \n", ifReq.ifr_name, ethtoolLinkSettings.speed);
printf("%s | ethtool_link_settings.duplex = %i \n", ifReq.ifr_name, ethtoolLinkSettings.duplex);
printf("%s | ethtool_link_settings.autoneg = %i \n", ifReq.ifr_name, ethtoolLinkSettings.autoneg);
}
else
printf("Error #r");
close(s);
}
else
printf("Error #s");
return 0;
}
Result:
enp3s0 | ethtool_link_settings.speed = 0
enp3s0 | ethtool_link_settings.duplex = 45
enp3s0 | ethtool_link_settings.autoneg = 0
Why ETHTOOL_GLINKSETTINGS return incorrect values? What is the problem?
Definitely this code is a problem
r = ioctl(s, SIOCETHTOOL, &ifReq);
if (s != -1)
how ever fixing this doesn't resolve the issue and the interface properties cannot be queried using ETHTOOL_GLINKSETTINGS. A peek into the header file shows this.
from /usr/include/linux/ethtool.h
1532 /**
1533 * struct ethtool_link_settings - link control and status
1534 *
1535 * IMPORTANT, Backward compatibility notice: When implementing new
1536 * user-space tools, please first try %ETHTOOL_GLINKSETTINGS, and
1537 * if it succeeds use %ETHTOOL_SLINKSETTINGS to change link
1538 * settings; do not use %ETHTOOL_SSET if %ETHTOOL_GLINKSETTINGS
1539 * succeeded: stick to %ETHTOOL_GLINKSETTINGS/%SLINKSETTINGS in
1540 * that case. Conversely, if %ETHTOOL_GLINKSETTINGS fails, use
1541 * %ETHTOOL_GSET to query and %ETHTOOL_SSET to change link
1542 * settings; do not use %ETHTOOL_SLINKSETTINGS if
1543 * %ETHTOOL_GLINKSETTINGS failed: stick to
1544 * %ETHTOOL_GSET/%ETHTOOL_SSET in that case.
I do see the same behavior as reported and observe the correct values being reported using ETHTOOL_GSET
with ETHTOOL_GSET
~/working/exp$./ethtool-exp ens33
ens33 | ethtool_cmd.speed = 1000
ens33 | ethtool_cmd.duplex = 1
ens33 | ethtool_cmd.advertising= 239
ens33 | ethtool_cmd.autoneg = 1
ens33 | ethtool_cmd.port= 0
ens33 | ethtool_cmd.phy_address= 0
ens33 | ethtool_cmd.transceiver= 0
ens33 | ethtool_cmd.maxrxpkt= 0
ens33 | ethtool_cmd.maxtxpkt= 0
with ETHTOOL_GLINKSETTINGS
~/working/exp$./ethtool-glink ens33
ens33 | ethtool_link_settings.speed = 0
ens33 | ethtool_link_settings.duplex = 0
ens33 | ethtool_link_settings.autoneg = 0
As you can see in the function do_ioctl_glinksettings()
in ethtool.c, you should reserve some space behind your ethtoolLinkSettings
buffer for the variable sized members map_supported
, map_advertising
, and map_lp_advertising
(only indirectly accessible via link_mode_masks
).
As a result of the first call of ioctl()
you will get the real size of these members in link_mode_masks_nwords
with a negative sign. Then set the link_mode_masks_nwords
to this real size (non-negative) and call ioctl()
again. Then you will get real data.
eg. (not tested)
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd > 0)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, "enp3s0");
char buffer[sizeof(struct ethtool_link_settings) + sizeof(__u32) * 3 * 128];
struct ethtool_link_settings* ethtoolLinkSettings = (struct ethtool_link_settings*)buffer;
memset(buffer, 0, sizeof(buffer));
ethtoolLinkSettings->cmd = ETHTOOL_GLINKSETTINGS;
ifr.ifr_data = (caddr_t)ethtoolLinkSettings;
if (ioctl(fd, SIOCETHTOOL, &ifr) != -1)
{
if (ethtoolLinkSettings->link_mode_masks_nwords < 0)
{
ethtoolLinkSettings->cmd = ETHTOOL_GLINKSETTINGS;
ethtoolLinkSettings->link_mode_masks_nwords = -ethtoolLinkSettings->link_mode_masks_nwords;
if (ioctl(fd, SIOCETHTOOL, &ifr) != -1)
{
printf("%s | ethtool_link_settings.speed = %i \n", ifReq.ifr_name, ethtoolLinkSettings.speed);
printf("%s | ethtool_link_settings.duplex = %i \n", ifReq.ifr_name, ethtoolLinkSettings.duplex);
printf("%s | ethtool_link_settings.autoneg = %i \n", ifReq.ifr_name, ethtoolLinkSettings.autoneg);
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With