Skip to content

ifethtool 应用指南

本文面向需要直接调用 ioctl(SIOCETHTOOL, ...) 的 SylixOS 应用开发者。

开发前提

c
#include <net/if_ethtool.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>

公共辅助函数:

c
static int ifethtool_ioctl_call(int sock, const char *ifname, void *edata)
{
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
    ifr.ifr_data = edata;
    return ioctl(sock, SIOCETHTOOL, &ifr);
}

查询链路设置

对应命令:ifethtool IFNAME

c
struct ethtool_cmd ecmd;
struct ethtool_value eval;

memset(&ecmd, 0, sizeof(ecmd));
ecmd.cmd = ETHTOOL_GSET;
ifethtool_ioctl_call(sock, ifname, &ecmd);

memset(&eval, 0, sizeof(eval));
eval.cmd = ETHTOOL_GLINK;
ifethtool_ioctl_call(sock, ifname, &eval);

printf(\"speed=%uMb/s duplex=%u autoneg=%u link=%u\
\",
       ethtool_cmd_speed(&ecmd), ecmd.duplex, ecmd.autoneg, eval.data);

查询驱动信息

对应命令:ifethtool -i IFNAME

c
struct ethtool_drvinfo info;
memset(&info, 0, sizeof(info));
info.cmd = ETHTOOL_GDRVINFO;
ifethtool_ioctl_call(sock, ifname, &info);
printf(\"driver=%s version=%s\
\", info.driver, info.version);

查询/设置 Pause

对应命令:ifethtool -a/-A IFNAME

c
/* 查询 */
struct ethtool_pauseparam pp;
memset(&pp, 0, sizeof(pp));
pp.cmd = ETHTOOL_GPAUSEPARAM;
ifethtool_ioctl_call(sock, ifname, &pp);

/* 设置 */
pp.cmd = ETHTOOL_SPAUSEPARAM;
pp.rx_pause = 1;
pp.tx_pause = 1;
ifethtool_ioctl_call(sock, ifname, &pp);

查询/设置 Ring 深度

对应命令:ifethtool -g/-G IFNAME

c
struct ethtool_ringparam rp;
memset(&rp, 0, sizeof(rp));
rp.cmd = ETHTOOL_GRINGPARAM;
ifethtool_ioctl_call(sock, ifname, &rp);

/* 设置 RX ring 深度 */
rp.cmd = ETHTOOL_SRINGPARAM;
rp.rx_pending = 512;
ifethtool_ioctl_call(sock, ifname, &rp);

查询/设置中断合并

对应命令:ifethtool -c/-C IFNAME

c
struct ethtool_coalesce ec;
memset(&ec, 0, sizeof(ec));
ec.cmd = ETHTOOL_GCOALESCE;
ifethtool_ioctl_call(sock, ifname, &ec);

/* 设置 */
ec.cmd = ETHTOOL_SCOALESCE;
ec.rx_coalesce_usecs = 50;
ifethtool_ioctl_call(sock, ifname, &ec);

查询/设置 Channel 数

对应命令:ifethtool -l/-L IFNAME

c
struct ethtool_channels ch;
memset(&ch, 0, sizeof(ch));
ch.cmd = ETHTOOL_GCHANNELS;
ifethtool_ioctl_call(sock, ifname, &ch);

ch.cmd = ETHTOOL_SCHANNELS;
ch.combined_count = 4;
ifethtool_ioctl_call(sock, ifname, &ch);

查询驱动统计

对应命令:ifethtool -S IFNAME

采用两次查询:先获取统计项数量,再按数量分配内存读取值。

c
/* 1. 获取统计项数量 */
struct ethtool_sset_info ssi;
memset(&ssi, 0, sizeof(ssi));
ssi.cmd = ETHTOOL_GSSET_INFO;
ssi.sset_mask = (1ULL << ETH_SS_STATS);
ifethtool_ioctl_call(sock, ifname, &ssi);
uint32_t n_stats = ssi.data[0];

/* 2. 获取名称 */
struct ethtool_gstrings *gs = calloc(1, sizeof(*gs) + n_stats * ETH_GSTRING_LEN);
gs->cmd = ETHTOOL_GSTRINGS;
gs->string_set = ETH_SS_STATS;
gs->len = n_stats;
ifethtool_ioctl_call(sock, ifname, gs);

/* 3. 获取值 */
struct ethtool_stats *stats = calloc(1, sizeof(*stats) + n_stats * sizeof(uint64_t));
stats->cmd = ETHTOOL_GSTATS;
stats->n_stats = n_stats;
ifethtool_ioctl_call(sock, ifname, stats);

开发建议

  • 变长接口采用两次查询:先拿数量,再按数量分配内存
  • 设置类接口遵循"先读后改后写"的模式
  • 不要假定所有网卡都支持所有命令,-EOPNOTSUPP 需要作为正常分支处理
  • 对 feature/offload 接口,不要跳过 NETDEV_HW_FEATURES 检查
  • 成功设置 feature 后,真实硬件状态还依赖 SIOCETHTOOL_SYNC_FEAT 同步路径

翼辉信息 · 网络技术部