本文主要是介绍【无标题】ethtool程序,从用户态调用内核态调用分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
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,
};
这篇关于【无标题】ethtool程序,从用户态调用内核态调用分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!