1. 说明
-
用户层ethtool使用的是: ethtool-6.5 为例,下载来自:
https://mirrors.edge.kernel.org/pub/software/network/ethtool/ -
内核层:在内核源码中,VSCode -->【ctrl+p】搜索文件:linux/ethtool.h及 core/ethtool.c,相关实现在这两个文件中。
2. 应用层 ethtool-6.5
- ethtool.c
下面的 args 结构体展示了成员的选项(.opts)、执行函数(.func)、netlink执行函数(.nlfunc,暂时不必关心)、帮助(.xhelp)。
通过他们,能看出ethtool命令行后面跟什么选项时,调用了什么函数!
//
static const struct option args[] = {
{
/* "default" entry when no switch is used */
.opts = "",
.func = do_gset,
.nlfunc = nl_gset,
.help = "Display standard information about device",
},
{
.opts = "-s|--change",
.func = do_sset,
.nlfunc = nl_sset,
.help = "Change generic options",
.xhelp = " [ speed %d ]\n"
" [ lanes %d ]\n"
" [ duplex half|full ]\n"
" [ port tp|aui|bnc|mii|fibre|da ]\n"
" [ mdix auto|on|off ]\n"
" [ autoneg on|off ]\n"
" [ advertise %x[/%x] | mode on|off ... [--] ]\n"
" [ phyad %d ]\n"
" [ xcvr internal|external ]\n"
" [ wol %d[/%d] | p|u|m|b|a|g|s|f|d... ]\n"
" [ sopass %x:%x:%x:%x:%x:%x ]\n"
" [ msglvl %d[/%d] | type on|off ... [--] ]\n"
" [ master-slave preferred-master|preferred-slave|forced-master|forced-slave ]\n"
},
{
.opts = "-a|--show-pause",
.json = true,
.func = do_gpause,
.nlfunc = nl_gpause,
.help = "Show pause options",
.xhelp = " [ --src aggregate | emac | pmac ]\n"
},
{
.opts = "-A|--pause",
.func = do_spause,
.nlfunc = nl_spause,
.help = "Set pause options",
.xhelp = " [ autoneg on|off ]\n"
" [ rx on|off ]\n"
" [ tx on|off ]\n"
},
{
.opts = "-c|--show-coalesce",
.json = true,
.func = do_gcoalesce,
.nlfunc = nl_gcoalesce,
.help = "Show coalesce options"
},
{
.opts = "-C|--coalesce",
.func = do_scoalesce,
.nlfunc = nl_scoalesce,
.help = "Set coalesce options",
.xhelp = " [adaptive-rx on|off]\n"
" [adaptive-tx on|off]\n"
" [rx-usecs N]\n"
" [rx-frames N]\n"
" [rx-usecs-irq N]\n"
" [rx-frames-irq N]\n"
" [tx-usecs N]\n"
" [tx-frames N]\n"
" [tx-usecs-irq N]\n"
" [tx-frames-irq N]\n"
" [stats-block-usecs N]\n"
" [pkt-rate-low N]\n"
" [rx-usecs-low N]\n"
" [rx-frames-low N]\n"
" [tx-usecs-low N]\n"
" [tx-frames-low N]\n"
" [pkt-rate-high N]\n"
" [rx-usecs-high N]\n"
" [rx-frames-high N]\n"
" [tx-usecs-high N]\n"
" [tx-frames-high N]\n"
" [sample-interval N]\n"
" [cqe-mode-rx on|off]\n"
" [cqe-mode-tx on|off]\n"
" [tx-aggr-max-bytes N]\n"
" [tx-aggr-max-frames N]\n"
" [tx-aggr-time-usecs N]\n"
},
{
.opts = "-g|--show-ring",
.json = true,
.func = do_gring,
.nlfunc = nl_gring,
.help = "Query RX/TX ring parameters"
},
{
.opts = "-G|--set-ring",
.func = do_sring,
.nlfunc = nl_sring,
.help = "Set RX/TX ring parameters",
.xhelp = " [ rx N ]\n"
" [ rx-mini N ]\n"
" [ rx-jumbo N ]\n"
" [ tx N ]\n"
" [ rx-buf-len N ]\n"
" [ cqe-size N ]\n"
" [ tx-push on|off ]\n"
" [ rx-push on|off ]\n"
" [ tx-push-buf-len N]\n"
},
{
.opts = "-k|--show-features|--show-offload",
.json = true,
.func = do_gfeatures,
.nlfunc = nl_gfeatures,
.help = "Get state of protocol offload and other features"
},
{
.opts = "-K|--features|--offload",
.func = do_sfeatures,
.nlfunc = nl_sfeatures,
.help = "Set protocol offload and other features",
.xhelp = " FEATURE on|off ...\n"
},
{
.opts = "-i|--driver",
.func = do_gdrv,
.help = "Show driver information"
},
{
.opts = "-d|--register-dump",
.func = do_gregs,
.help = "Do a register dump",
.xhelp = " [ raw on|off ]\n"
" [ file FILENAME ]\n"
},
{
.opts = "-e|--eeprom-dump",
.func = do_geeprom,
.help = "Do a EEPROM dump",
.xhelp = " [ raw on|off ]\n"
" [ offset N ]\n"
" [ length N ]\n"
},
{
.opts = "-E|--change-eeprom",
.func = do_seeprom,
.help = "Change bytes in device EEPROM",
.xhelp = " [ magic N ]\n"
" [ offset N ]\n"
" [ length N ]\n"
" [ value N ]\n"
},
{
.opts = "-r|--negotiate",
.func = do_nway_rst,
.help = "Restart N-WAY negotiation"
},
{
.opts = "-p|--identify",
.func = do_phys_id,
.help = "Show visible port identification (e.g. blinking)",
.xhelp = " [ TIME-IN-SECONDS ]\n"
},
{
.opts = "-t|--test",
.func = do_test,
.help = "Execute adapter self test",
.xhelp = " [ online | offline | external_lb ]\n"
},
{
.opts = "-S|--statistics",
.json = true,
.func = do_gnicstats,
.nlchk = nl_gstats_chk,
.nlfunc = nl_gstats,
.help = "Show adapter statistics",
.xhelp = " [ --all-groups | --groups [eth-phy] [eth-mac] [eth-ctrl] [rmon] ]\n"
" [ --src aggregate | emac | pmac ]\n"
},
{
.opts = "--phy-statistics",
.func = do_gphystats,
.help = "Show phy statistics"
},
{
.opts = "-n|-u|--show-nfc|--show-ntuple",
.func = do_grxclass,
.help = "Show Rx network flow classification options or rules",
.xhelp = " [ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
"tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n"
" rule %d ]\n"
},
{
.opts = "-N|-U|--config-nfc|--config-ntuple",
.func = do_srxclass,
.help = "Configure Rx network flow classification options or rules",
.xhelp = " rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
"tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n"
" flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|"
"ip6|tcp6|udp6|ah6|esp6|sctp6\n"
" [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
" [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
" [ proto %d [m %x] ]\n"
" [ src-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
" [ dst-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
" [ tos %d [m %x] ]\n"
" [ tclass %d [m %x] ]\n"
" [ l4proto %d [m %x] ]\n"
" [ src-port %d [m %x] ]\n"
" [ dst-port %d [m %x] ]\n"
" [ spi %d [m %x] ]\n"
" [ vlan-etype %x [m %x] ]\n"
" [ vlan %x [m %x] ]\n"
" [ user-def %x [m %x] ]\n"
" [ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
" [ action %d ] | [ vf %d queue %d ]\n"
" [ context %d ]\n"
" [ loc %d ] |\n"
" delete %d\n"
},
{
.opts = "-T|--show-time-stamping",
.func = do_tsinfo,
.nlfunc = nl_tsinfo,
.help = "Show time stamping capabilities"
},
{
.opts = "-x|--show-rxfh-indir|--show-rxfh",
.json = true,
.func = do_grxfh,
.nlfunc = nl_grss,
.help = "Show Rx flow hash indirection table and/or RSS hash key",
.xhelp = " [ context %d ]\n"
},
{
.opts = "-X|--set-rxfh-indir|--rxfh",
.func = do_srxfh,
.help = "Set Rx flow hash indirection table and/or RSS hash key",
.xhelp = " [ context %d|new ]\n"
" [ equal N | weight W0 W1 ... | default ]\n"
" [ hkey %x:%x:%x:%x:%x:.... ]\n"
" [ hfunc FUNC ]\n"
" [ delete ]\n"
},
{
.opts = "-f|--flash",
.func = do_flash,
.help = "Flash firmware image from the specified file to a region on the device",
.xhelp = " FILENAME [ REGION-NUMBER-TO-FLASH ]\n"
},
{
.opts = "-P|--show-permaddr",
.func = do_permaddr,
.nlfunc = nl_permaddr,
.help = "Show permanent hardware address"
},
{
.opts = "-w|--get-dump",
.func = do_getfwdump,
.help = "Get dump flag, data",
.xhelp = " [ data FILENAME ]\n"
},
{
.opts = "-W|--set-dump",
.func = do_setfwdump,
.help = "Set dump flag of the device",
.xhelp = " N\n"
},
{
.opts = "-l|--show-channels",
.func = do_gchannels,
.nlfunc = nl_gchannels,
.help = "Query Channels"
},
{
.opts = "-L|--set-channels",
.func = do_schannels,
.nlfunc = nl_schannels,
.help = "Set Channels",
.xhelp = " [ rx N ]\n"
" [ tx N ]\n"
" [ other N ]\n"
" [ combined N ]\n"
},
{
.opts = "--show-priv-flags",
.func = do_gprivflags,
.nlfunc = nl_gprivflags,
.help = "Query private flags"
},
{
.opts = "--set-priv-flags",
.func = do_sprivflags,
.nlfunc = nl_sprivflags,
.help = "Set private flags",
.xhelp = " FLAG on|off ...\n"
},
{
.opts = "-m|--dump-module-eeprom|--module-info",
.func = do_getmodule,
.nlfunc = nl_getmodule,
.help = "Query/Decode Module EEPROM information and optical diagnostics if available",
.xhelp = " [ raw on|off ]\n"
" [ hex on|off ]\n"
" [ offset N ]\n"
" [ length N ]\n"
" [ page N ]\n"
" [ bank N ]\n"
" [ i2c N ]\n"
},
{
.opts = "--show-eee",
.func = do_geee,
.nlfunc = nl_geee,
.help = "Show EEE settings",
},
{
.opts = "--set-eee",
.func = do_seee,
.nlfunc = nl_seee,
.help = "Set EEE settings",
.xhelp = " [ eee on|off ]\n"
" [ advertise %x ]\n"
" [ tx-lpi on|off ]\n"
" [ tx-timer %d ]\n"
},
{
.opts = "--set-phy-tunable",
.func = do_set_phy_tunable,
.help = "Set PHY tunable",
.xhelp = " [ downshift on|off [count N] ]\n"
" [ fast-link-down on|off [msecs N] ]\n"
" [ energy-detect-power-down on|off [msecs N] ]\n"
},
{
.opts = "--get-phy-tunable",
.func = do_get_phy_tunable,
.help = "Get PHY tunable",
.xhelp = " [ downshift ]\n"
" [ fast-link-down ]\n"
" [ energy-detect-power-down ]\n"
},
{
.opts = "--get-tunable",
.func = do_gtunable,
.help = "Get tunable",
.xhelp = " [ rx-copybreak ]\n"
" [ tx-copybreak ]\n"
" [ tx-buf-size ]\n"
" [ pfc-prevention-tout ]\n"
},
{
.opts = "--set-tunable",
.func = do_stunable,
.help = "Set tunable",
.xhelp = " [ rx-copybreak N ]\n"
" [ tx-copybreak N ]\n"
" [ tx-buf-size N ]\n"
" [ pfc-prevention-tout N ]\n"
},
{
.opts = "--reset",
.func = do_reset,
.help = "Reset components",
.xhelp = " [ flags %x ]\n"
" [ mgmt ]\n"
" [ mgmt-shared ]\n"
" [ irq ]\n"
" [ irq-shared ]\n"
" [ dma ]\n"
" [ dma-shared ]\n"
" [ filter ]\n"
" [ filter-shared ]\n"
" [ offload ]\n"
" [ offload-shared ]\n"
" [ mac ]\n"
" [ mac-shared ]\n"
" [ phy ]\n"
" [ phy-shared ]\n"
" [ ram ]\n"
" [ ram-shared ]\n"
" [ ap ]\n"
" [ ap-shared ]\n"
" [ dedicated ]\n"
" [ all ]\n"
},
{
.opts = "--show-fec",
.json = true,
.func = do_gfec,
.nlfunc = nl_gfec,
.help = "Show FEC settings",
},
{
.opts = "--set-fec",
.func = do_sfec,
.nlfunc = nl_sfec,
.help = "Set FEC settings",
.xhelp = " [ encoding auto|off|rs|baser|llrs [...] ]\n"
},
{
.opts = "-Q|--per-queue",
.func = do_perqueue,
.help = "Apply per-queue command. ",
.xhelp = "The supported sub commands include --show-coalesce, --coalesce"
" [queue_mask %x] SUB_COMMAND\n",
},
{
.opts = "--cable-test",
.json = true,
.nlfunc = nl_cable_test,
.help = "Perform a cable test",
},
{
.opts = "--cable-test-tdr",
.json = true,
.nlfunc = nl_cable_test_tdr,
.help = "Print cable test time domain reflectrometery data",
.xhelp = " [ first N ]\n"
" [ last N ]\n"
" [ step N ]\n"
" [ pair N ]\n"
},
{
.opts = "--show-tunnels",
.nlfunc = nl_gtunnels,
.help = "Show NIC tunnel offload information",
},
{
.opts = "--show-module",
.json = true,
.nlfunc = nl_gmodule,
.help = "Show transceiver module settings",
},
{
.opts = "--set-module",
.nlfunc = nl_smodule,
.help = "Set transceiver module settings",
.xhelp = " [ power-mode-policy high|auto ]\n"
},
{
.opts = "--get-plca-cfg",
.nlfunc = nl_plca_get_cfg,
.help = "Get PLCA configuration",
},
{
.opts = "--set-plca-cfg",
.nlfunc = nl_plca_set_cfg,
.help = "Set PLCA configuration",
.xhelp = " [ enable on|off ]\n"
" [ node-id N ]\n"
" [ node-cnt N ]\n"
" [ to-tmr N ]\n"
" [ burst-cnt N ]\n"
" [ burst-tmr N ]\n"
},
{
.opts = "--get-plca-status",
.nlfunc = nl_plca_get_status,
.help = "Get PLCA status information",
},
{
.opts = "--show-mm",
.json = true,
.nlfunc = nl_get_mm,
.help = "Show MAC merge layer state",
},
{
.opts = "--set-mm",
.nlfunc = nl_set_mm,
.help = "Set MAC merge layer parameters",
" [ verify-enabled on|off ]\n"
" [ verify-time N ]\n"
" [ tx-enabled on|off ]\n"
" [ pmac-enabled on|off ]\n"
" [ tx-min-frag-size 60-252 ]\n"
},
{
.opts = "--show-pse",
.json = true,
.nlfunc = nl_gpse,
.help = "Show settings for Power Sourcing Equipment",
},
{
.opts = "--set-pse",
.nlfunc = nl_spse,
.help = "Set Power Sourcing Equipment settings",
.xhelp = " [ podl-pse-admin-control enable|disable ]\n"
},
{
.opts = "-h|--help",
.no_dev = true,
.func = show_usage,
.help = "Show this help"
},
{
.opts = "--version",
.no_dev = true,
.func = do_version,
.help = "Show version number"
},
{}
};
读操作
这里以 .opts = “-i|–driver” 为例:读取网卡信息
#使用:ethtool -i ethX
do_gdrv
--> send_ioctl(ETHTOOL_GDRVINFO)
--> ioctl(SIOCETHTOOL);
写操作
这里以 .opts = "-p|–identify"为例,设置网卡点灯时间
#使用:ethtool -p ethX 10
do_phys_id
--> send_ioctl(ETHTOOL_PHYS_ID);
--> ioctl(SIOCETHTOOL);
应用层调用到 ioctl ,到此为止!
3. 内核层
继续上面示例,应用层 ioctl 继续调用内核层 dev_ioctl:
读操作:读取网卡信息
dev_ioctl case SIOCETHTOOL:-->
--> dev_ethtool
--> ethtool_get_drvinfo
--> ops->get_drvinfo #这个函数是 struct ethtool_ops 结构体中,需要自己实现
写操作:设置网卡点灯时间
dev_ioctl case SIOCETHTOOL:-->
--> dev_ethtool
--> ethtool_phys_id
--> ops->set_phys_id #这个函数是 struct ethtool_ops 结构体中,需要自己实现
struct ethtool_ops 内容(linux/ethtool.h)
struct ethtool_ops {
{
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
int (*set_settings)(struct net_device *, struct ethtool_cmd *);
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
int (*get_regs_len)(struct net_device *);
void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
void (*get_wol)(struct net_device *, struct ethtool_wolinfo *);
int (*set_wol)(struct net_device *, struct ethtool_wolinfo *);
u32 (*get_msglevel)(struct net_device *);
void (*set_msglevel)(struct net_device *, u32);
int (*nway_reset)(struct net_device *);
u32 (*get_link)(struct net_device *);
int (*get_eeprom_len)(struct net_device *);
int (*get_eeprom)(struct net_device *,
struct ethtool_eeprom *, u8 *);
int (*set_eeprom)(struct net_device *,
struct ethtool_eeprom *, u8 *);
int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
void (*get_ringparam)(struct net_device *,
struct ethtool_ringparam *);
int (*set_ringparam)(struct net_device *,
struct ethtool_ringparam *);
void (*get_pauseparam)(struct net_device *,
struct ethtool_pauseparam*);
int (*set_pauseparam)(struct net_device *,
struct ethtool_pauseparam*);
void (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
void (*get_strings)(struct net_device *, u32 stringset, u8 *);
int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
void (*get_ethtool_stats)(struct net_device *,
struct ethtool_stats *, u64 *);
int (*begin)(struct net_device *);
void (*complete)(struct net_device *);
u32 (*get_priv_flags)(struct net_device *);
int (*set_priv_flags)(struct net_device *, u32);
int (*get_sset_count)(struct net_device *, int);
int (*get_rxnfc)(struct net_device *,
struct ethtool_rxnfc *, u32 *rule_locs);
int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
int (*flash_device)(struct net_device *, struct ethtool_flash *);
int (*reset)(struct net_device *, u32 *);
u32 (*get_rxfh_key_size)(struct net_device *);
u32 (*get_rxfh_indir_size)(struct net_device *);
int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key,
u8 *hfunc);
int (*set_rxfh)(struct net_device *, const u32 *indir,
const u8 *key, const u8 hfunc);
void (*get_channels)(struct net_device *, struct ethtool_channels *);
int (*set_channels)(struct net_device *, struct ethtool_channels *);
int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);
int (*get_dump_data)(struct net_device *,
struct ethtool_dump *, void *);
int (*set_dump)(struct net_device *, struct ethtool_dump *);
int (*get_ts_info)(struct net_device *, struct ethtool_ts_info *);
int (*get_module_info)(struct net_device *,
struct ethtool_modinfo *);
int (*get_module_eeprom)(struct net_device *,
struct ethtool_eeprom *, u8 *);
int (*get_eee)(struct net_device *, struct ethtool_eee *);
int (*set_eee)(struct net_device *, struct ethtool_eee *);
int (*get_tunable)(struct net_device *,
const struct ethtool_tunable *, void *);
int (*set_tunable)(struct net_device *,
const struct ethtool_tunable *, const void *);
};
ethtool_ops使用的典型参考:dm9000.c
在内核源码中,VScode–【ctrl+p】,输入 dm9000.c
static const struct ethtool_ops dm9000_ethtool_ops = {
.get_drvinfo = dm9000_get_drvinfo,
.get_settings = dm9000_get_settings,
.set_settings = dm9000_set_settings,
.get_msglevel = dm9000_get_msglevel,
.set_msglevel = dm9000_set_msglevel,
.nway_reset = dm9000_nway_reset,
.get_link = dm9000_get_link,
.get_wol = dm9000_get_wol,
.set_wol = dm9000_set_wol,
.get_eeprom_len = dm9000_get_eeprom_len,
.get_eeprom = dm9000_get_eeprom,
.set_eeprom = dm9000_set_eeprom,
};