Ethtool与EEPROM

ethtool

ethtool命令用于获取或修改以太网卡的配置信息。这个命令比较复杂,功能特别多

使用man ethtool可查看详细的使用说明,这里不再详述

这里主要通过探讨ethtool操作MAC地址与EEPROM相关的内容,来梳理ethtool工具的整个工作流程,下面一系列前提是网卡的MAC地址存放在EEPROM里面!

操作EEPROM里面MAC地址相关的命令:

  • 读取MAC地址:
    ethtool -e ${ethname}
  • 烧写MAC地址:
       ethtool -E ${ethname} offset 0 value 0xf4
    ethtool -E ${ethname} offset 1 value 0x4d
    ...
    ethtool工具是怎么和EEPROM操作相关联的呢? 下面分别从内核态和用户态来看看

用户态

ethtool软件包源码:http://www.kernel.org/pub/software/network/ethtool/

{ "-e|--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
  "		[ raw on|off ]\n"
  "		[ offset N ]\n"
  "		[ length N ]\n" },
{ "-E|--change-eeprom", 1, do_seeprom,
  "Change bytes in device EEPROM",
  "		[ magic N ]\n"
  "		[ offset N ]\n"
  "		[ length N ]\n"
  "		[ value N ]\n" },

获取eeprom内容对应的函数为:do_geeprom()
修改eeprom内容对应的函数为:do_seeprom()

do_seeprom()函数大致流程如下,do_geeprom()类似:

do_seeprom()
    -> send_ioctl() [cmd = ETHTOOL_SEEPROM]
        -> ioctl() [cmd = SIOCETHTOOL]

所以可以看出ethtool主要是通过ioctl()接口来与内核进行交互

内核态

具体ioctl接口整个调用流程比较复杂,不在这里详述
这里以stmmac设备、写MAC到eeprom(24c02)为例, 读操作类似:

dev_ioctl() net/core/dev_ioctl.c
    -> dev_ethtool() net/core/ethtool.c [cmd=SIOCETHTOOL] 对应用户态传递过来的
        -> ethtool_set_eeprom() [cmd=ETHTOOL_SEEPROM] 对应用户态传递过来的
            -> ops->set_eeprom() [struct ethtool_ops]
                -> stmmac_set_eeprom() drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
                    -> at24_write_eeprom() drivers/misc/eeprom/at24.c

最重要的是struct ethtool_ops结构体,该结构体成员是一系列显示或修改以太网卡配置的函数指针,然后会赋值给网络设备结构体struct net_device中的ethtool_ops变量
例如:

static const struct ethtool_ops stmmac_ethtool_ops = {
	.get_drvinfo = stmmac_ethtool_getdrvinfo,
	.get_settings = stmmac_ethtool_getsettings,
	.set_settings = stmmac_ethtool_setsettings,
	.get_msglevel = stmmac_ethtool_getmsglevel,
	.set_msglevel = stmmac_ethtool_setmsglevel,
	.get_regs = stmmac_ethtool_gregs,
	.get_regs_len = stmmac_ethtool_get_regs_len,
	.get_link = ethtool_op_get_link,
	.get_eeprom_len = stmmac_get_eeprom_len,
	.get_eeprom = stmmac_get_eeprom,
	.set_eeprom = stmmac_set_eeprom,
	.get_pauseparam = stmmac_get_pauseparam,
	.set_pauseparam = stmmac_set_pauseparam,
	.get_ethtool_stats = stmmac_get_ethtool_stats,
	.get_strings = stmmac_get_strings,
	.get_wol = stmmac_get_wol,
	.set_wol = stmmac_set_wol,
	.get_eee = stmmac_ethtool_op_get_eee,
	.set_eee = stmmac_ethtool_op_set_eee,
	.get_sset_count	= stmmac_get_sset_count,
	.get_ts_info = stmmac_get_ts_info,
	.get_coalesce = stmmac_get_coalesce,
	.set_coalesce = stmmac_set_coalesce,
};

void stmmac_set_ethtool_ops(struct net_device *netdev)
{
	netdev->ethtool_ops = &stmmac_ethtool_ops;
}

参考

  • ethtool4.5源码
  • 内核源码(Kernel v4.4.131)