ethtool在Linux里的交互

目录

介绍

ethtool在Linux的框架

Linux内核部分

ethtool应用程序


介绍

ethtool是Linux里查询或配置网络驱动和设备的重要工具。

使用概要:
ethtool ethx        //查询ethx网口基本设置,其中 x 是对应网卡的编号,如eth0、eth1等等
ethtool –h           //显示ethtool的命令帮助(help)
ethtool –i ethX    //查询ethX网口的相关信息 
ethtool –d ethX   //查询ethX网口注册性信息
ethtool –r ethX    //重置ethX网口到自适应模式
ethtool –S ethX   //查询ethX网口收发包统计
ethtool –s ethX [speed 10|100|1000] [duplex half|full]  [autoneg on|off]        //设置网口速率10/100/1000M、设置网口半/全双工、设置网口是否自协商

ethtool -E eth0 magic 0x10798086 offset 0x10 value 0x1A  //修改网卡EEPROM内容(0x1079 网卡device id , 0x8086网卡verdor id  )

ethtool -e eth0    //dump网卡EEPROM内容

ethtool在Linux里的帮助信息如下:

$ ethtool -h
ethtool version 5.10
Usage:
        ethtool [ FLAGS ] DEVNAME       Display standard information about device
        ethtool [ FLAGS ] -s|--change DEVNAME   Change generic options
                [ speed %d ]
                [ duplex half|full ]
                [ port tp|aui|bnc|mii|fibre|da ]
                [ mdix auto|on|off ]
                [ autoneg on|off ]
                [ advertise %x[/%x] | mode on|off ... [--] ]
                [ phyad %d ]
                [ xcvr internal|external ]
                [ wol %d[/%d] | p|u|m|b|a|g|s|f|d... ]
                [ sopass %x:%x:%x:%x:%x:%x ]
                [ msglvl %d[/%d] | type on|off ... [--] ]
                [ master-slave master-preferred|slave-preferred|master-force|slave-force ]
        ethtool [ FLAGS ] -a|--show-pause DEVNAME       Show pause options
        ethtool [ FLAGS ] -A|--pause DEVNAME    Set pause options
                [ autoneg on|off ]
                [ rx on|off ]
                [ tx on|off ]
        ethtool [ FLAGS ] -c|--show-coalesce DEVNAME    Show coalesce options
        ethtool [ FLAGS ] -C|--coalesce DEVNAME Set coalesce options
                [adaptive-rx on|off]
                [adaptive-tx on|off]
                [rx-usecs N]
                [rx-frames N]
                [rx-usecs-irq N]
                [rx-frames-irq N]
                [tx-usecs N]
                [tx-frames N]
                [tx-usecs-irq N]
                [tx-frames-irq N]
                [stats-block-usecs N]
                [pkt-rate-low N]
                [rx-usecs-low N]
                [rx-frames-low N]
                [tx-usecs-low N]
                [tx-frames-low N]
                [pkt-rate-high N]
                [rx-usecs-high N]
                [rx-frames-high N]
                [tx-usecs-high N]
                [tx-frames-high N]
                [sample-interval N]
        ethtool [ FLAGS ] -g|--show-ring DEVNAME        Query RX/TX ring parameters
        ethtool [ FLAGS ] -G|--set-ring DEVNAME Set RX/TX ring parameters
                [ rx N ]
                [ rx-mini N ]
                [ rx-jumbo N ]
                [ tx N ]
        ethtool [ FLAGS ] -k|--show-features|--show-offload DEVNAME     Get state of protocol offload and other features
        ethtool [ FLAGS ] -K|--features|--offload DEVNAME       Set protocol offload and other features
                FEATURE on|off ...
        ethtool [ FLAGS ] -i|--driver DEVNAME   Show driver information
        ethtool [ FLAGS ] -d|--register-dump DEVNAME    Do a register dump
                [ raw on|off ]
                [ file FILENAME ]
        ethtool [ FLAGS ] -e|--eeprom-dump DEVNAME      Do a EEPROM dump
                [ raw on|off ]
                [ offset N ]
                [ length N ]
        ethtool [ FLAGS ] -E|--change-eeprom DEVNAME    Change bytes in device EEPROM
                [ magic N ]
                [ offset N ]
                [ length N ]
                [ value N ]
        ethtool [ FLAGS ] -r|--negotiate DEVNAME        Restart N-WAY negotiation
        ethtool [ FLAGS ] -p|--identify DEVNAME Show visible port identification (e.g. blinking)
               [ TIME-IN-SECONDS ]
        ethtool [ FLAGS ] -t|--test DEVNAME     Execute adapter self test
               [ online | offline | external_lb ]
        ethtool [ FLAGS ] -S|--statistics DEVNAME       Show adapter statistics
        ethtool [ FLAGS ] --phy-statistics DEVNAME      Show phy statistics
        ethtool [ FLAGS ] -n|-u|--show-nfc|--show-ntuple DEVNAME        Show Rx network flow classification options or rules
                [ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|tcp6|udp6|ah6|esp6|sctp6 [context %d] |
                  rule %d ]
        ethtool [ FLAGS ] -N|-U|--config-nfc|--config-ntuple DEVNAME    Configure Rx network flow classification options or rules
                rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |
                flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|ip6|tcp6|udp6|ah6|esp6|sctp6
                        [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]
                        [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]
                        [ proto %d [m %x] ]
                        [ src-ip IP-ADDRESS [m IP-ADDRESS] ]
                        [ dst-ip IP-ADDRESS [m IP-ADDRESS] ]
                        [ tos %d [m %x] ]
                        [ tclass %d [m %x] ]
                        [ l4proto %d [m %x] ]
                        [ src-port %d [m %x] ]
                        [ dst-port %d [m %x] ]
                        [ spi %d [m %x] ]
                        [ vlan-etype %x [m %x] ]
                        [ vlan %x [m %x] ]
                        [ user-def %x [m %x] ]
                        [ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]
                        [ action %d ] | [ vf %d queue %d ]
                        [ context %d ]
                        [ loc %d]] |
                delete %d
        ethtool [ FLAGS ] -T|--show-time-stamping DEVNAME       Show time stamping capabilities
        ethtool [ FLAGS ] -x|--show-rxfh-indir|--show-rxfh DEVNAME      Show Rx flow hash indirection table and/or RSS hash key
                [ context %d ]
        ethtool [ FLAGS ] -X|--set-rxfh-indir|--rxfh DEVNAME    Set Rx flow hash indirection table and/or RSS hash key
                [ context %d|new ]
                [ equal N | weight W0 W1 ... | default ]
                [ hkey %x:%x:%x:%x:%x:.... ]
                [ hfunc FUNC ]
                [ delete ]
        ethtool [ FLAGS ] -f|--flash DEVNAME    Flash firmware image from the specified file to a region on the device
               FILENAME [ REGION-NUMBER-TO-FLASH ]
        ethtool [ FLAGS ] -P|--show-permaddr DEVNAME    Show permanent hardware address
        ethtool [ FLAGS ] -w|--get-dump DEVNAME Get dump flag, data
                [ data FILENAME ]
        ethtool [ FLAGS ] -W|--set-dump DEVNAME Set dump flag of the device
                N
        ethtool [ FLAGS ] -l|--show-channels DEVNAME    Query Channels
        ethtool [ FLAGS ] -L|--set-channels DEVNAME     Set Channels
               [ rx N ]
               [ tx N ]
               [ other N ]
               [ combined N ]
        ethtool [ FLAGS ] --show-priv-flags DEVNAME     Query private flags
        ethtool [ FLAGS ] --set-priv-flags DEVNAME      Set private flags
                FLAG on|off ...
        ethtool [ FLAGS ] -m|--dump-module-eeprom|--module-info DEVNAME Query/Decode Module EEPROM information and optical diagnostics if available
                [ raw on|off ]
                [ hex on|off ]
                [ offset N ]
                [ length N ]
        ethtool [ FLAGS ] --show-eee DEVNAME    Show EEE settings
        ethtool [ FLAGS ] --set-eee DEVNAME     Set EEE settings
                [ eee on|off ]
                [ advertise %x ]
                [ tx-lpi on|off ]
                [ tx-timer %d ]
        ethtool [ FLAGS ] --set-phy-tunable DEVNAME     Set PHY tunable
                [ downshift on|off [count N] ]
                [ fast-link-down on|off [msecs N] ]
                [ energy-detect-power-down on|off [msecs N] ]
        ethtool [ FLAGS ] --get-phy-tunable DEVNAME     Get PHY tunable
                [ downshift ]
                [ fast-link-down ]
                [ energy-detect-power-down ]
        ethtool [ FLAGS ] --get-tunable DEVNAME Get tunable
                [ rx-copybreak ]
                [ tx-copybreak ]
                [ pfc-precention-tout ]
        ethtool [ FLAGS ] --set-tunable DEVNAME Set tunable
                [ rx-copybreak N]
                [ tx-copybreak N]
                [ pfc-precention-tout N]
        ethtool [ FLAGS ] --reset DEVNAME       Reset components
                [ flags %x ]
                [ mgmt ]
                [ mgmt-shared ]
                [ irq ]
                [ irq-shared ]
                [ dma ]
                [ dma-shared ]
                [ filter ]
                [ filter-shared ]
                [ offload ]
                [ offload-shared ]
                [ mac ]
                [ mac-shared ]
                [ phy ]
                [ phy-shared ]
                [ ram ]
                [ ram-shared ]
                [ ap ]
                [ ap-shared ]
                [ dedicated ]
                [ all ]
        ethtool [ FLAGS ] --show-fec DEVNAME    Show FEC settings
        ethtool [ FLAGS ] --set-fec DEVNAME     Set FEC settings
                [ encoding auto|off|rs|baser|llrs [...]]
        ethtool [ FLAGS ] -Q|--per-queue DEVNAME        Apply per-queue command.
The supported sub commands include --show-coalesce, --coalesce             [queue_mask %x] SUB_COMMAND
        ethtool [ FLAGS ] --cable-test DEVNAME  Perform a cable test
        ethtool [ FLAGS ] --cable-test-tdr DEVNAME      Print cable test time domain reflectrometery data
                [ first N ]
                [ last N ]
                [ step N ]
                [ pair N ]
        ethtool [ FLAGS ] --show-tunnels DEVNAME        Show NIC tunnel offload information
        ethtool [ FLAGS ] -h|--help             Show this help
        ethtool [ FLAGS ] --version             Show version number
        ethtool --monitor               Show kernel notifications
                ( [ --all ]
                  | -s | --change
                  | -s | --change
                  | -s | --change
                  | -s | --change
                  | -k | --show-features | --show-offload | -K | --features | --offload
                  | --show-priv-flags | --set-priv-flags
                  | -g | --show-ring | -G | --set-ring
                  | -l | --show-channels | -L | --set-channels
                  | -c | --show-coalesce | -C | --coalesce
                  | -a | --show-pause | -A | --pause
                  | --show-eee | --set-eee
                  | --cable-test
                  | --cable-test-tdr )
                [ DEVNAME | * ]

FLAGS:
        --debug MASK    turn on debugging messages
        --json          enable JSON output format (not supported by all commands)
        -I|--include-statistics         request device statistics related to the command (not supported by all commands)

ethtool在Linux的框架

用户空间和内核空间上下交互的流程如下:

Linux内核部分

Linux内核里struct net_device结构体成员ethtool_ops结构体如下:

struct ethtool_ops {
    int (*get_settings)(struct net_device *, struct ethtool_cmd *);
    /* 通常使用 %get_link_ksettings/%set_link_ksettings API。获取多项设备设置,比如以太网Link设置。*/
    int (*set_settings)(struct net_device *, struct ethtool_cmd *);
    /* 通常使用 %get_link_ksettings/%set_link_ksettings API。设置多项设备设置,包括以太网Link设置。*/
    void    (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
    /* 报告驱动/设备信息。只能设置@driver, @version, @fw_version and @bus_info这些域。如果没有实现,@driver 和 @bus_info 域会根据netdev的父设备填充。  */
    int (*get_regs_len)(struct net_device *);
    /* 获取get_regs需要的字符串长度。 */
    void    (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
    /* 获取设备寄存器 */
    void    (*get_wol)(struct net_device *, struct ethtool_wolinfo *);
    /* 报告是否Wake-on-Lan启用 */
    int (*set_wol)(struct net_device *, struct ethtool_wolinfo *);
    /* 关闭或开启Wake-on-Lan功能 */
    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 *);
    /* 报告是否物理Link状态是UP的。*/
    int (*get_eeprom_len)(struct net_device *);
    /* 读取EEPROM有效地址范围 */
    int (*get_eeprom)(struct net_device *,
                  struct ethtool_eeprom *, u8 *);
    /* 从EEPROM设备中读取数据 */
    int (*set_eeprom)(struct net_device *,
                  struct ethtool_eeprom *, u8 *);
    /* 向EEPROM设备中写入数据 */
    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 *);
    /* 报告ring大小 */
    int (*set_ringparam)(struct net_device *,
                 struct ethtool_ringparam *);
    /* 设置ring大小 */
    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 *);
    /* 所有其他操作之后被调用的函数,除了begin */
    u32 (*get_priv_flags)(struct net_device *);
    /* 报告驱动特有的特性标记 */
    int (*set_priv_flags)(struct net_device *, u32);
    /* 设置驱动特有的特性标记 */
    int (*get_sset_count)(struct net_device *, int);
    /* 获取@get_strings会写入的字符串个数 */
    int (*get_rxnfc)(struct net_device *,
                 struct ethtool_rxnfc *, u32 *rule_locs);
    /* 获取RX流分类规则 */
    int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
    /* 设置RX流分类规则 */
    int (*flash_device)(struct net_device *, struct ethtool_flash *);
    /* 将固件镜像写入flash存储空间 */
    int (*reset)(struct net_device *, u32 *);
    /* 重置设备 */
    u32 (*get_rxfh_indir_size)(struct net_device *);
    /* 获取RX流摘要key的大小 */
    int (*get_rxfh_indir)(struct net_device *, u32 *);
    /**/
    int (*set_rxfh_indir)(struct net_device *, const u32 *);
    /**/
    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 *);
    /* 获取可插拔模块内eeprom包含的大小和类型 */
    int     (*get_module_eeprom)(struct net_device *,
                     struct ethtool_eeprom *, u8 *);
    /* 从可插拔模块内获取eeprom信息 */
    int (*get_eee)(struct net_device *, struct ethtool_eee *);
    /**/
    int (*set_eee)(struct net_device *, struct ethtool_eee *);
    /**/

    /* RHEL SPECIFIC
     *
     * The following padding has been inserted before ABI freeze to
     * allow extending the structure while preserve ABI. Feel free
     * to replace reserved slots with required structure field
     * additions of your backport.
     */
    RH_KABI_USE_P(1, u32    (*get_rxfh_key_size)(struct net_device *))
    RH_KABI_USE_P(2, int    (*get_rxfh)(struct net_device *, u32 *indir,
                        u8 *key, u8 *hfunc))
    RH_KABI_USE_P(3, int    (*set_rxfh)(struct net_device *,
                        const u32 *indir, const u8 *key,
                        const u8 hfunc))
    RH_KABI_USE_P(4, int    (*get_tunable)(struct net_device *,
                           const struct ethtool_tunable *,
                           void *))
    RH_KABI_USE_P(5, int    (*set_tunable)(struct net_device *,
                           const struct ethtool_tunable *,
                           const void *))
    RH_KABI_USE_P(6, int    (*get_per_queue_coalesce)(struct net_device *,
                              u32,
                              struct ethtool_coalesce *))
    RH_KABI_USE_P(7, int    (*set_per_queue_coalesce)(struct net_device *,
                              u32,
                              struct ethtool_coalesce *))
    RH_KABI_USE_P(8, int    (*get_link_ksettings)(struct net_device *,
                          struct ethtool_link_ksettings *))
    RH_KABI_USE_P(9, int    (*set_link_ksettings)(struct net_device *,
                      const struct ethtool_link_ksettings *))
    RH_KABI_USE_P(10,int    (*get_fecparam)(struct net_device *,
                      struct ethtool_fecparam *))
    RH_KABI_USE_P(11,int    (*set_fecparam)(struct net_device *,
                      struct ethtool_fecparam *))
    RH_KABI_USE_P(12,int    (*get_rxfh_context)(struct net_device *, u32 *indir, u8 *key,
                    u8 *hfunc, u32 rss_context))
    RH_KABI_USE_P(13,int    (*set_rxfh_context)(struct net_device *, const u32 *indir,
                    const u8 *key, const u8 hfunc,
                    u32 *rss_context, bool delete))
    RH_KABI_RESERVE_P(14)
    RH_KABI_RESERVE_P(15)
    RH_KABI_RESERVE_P(16)
};

/* include/linux/ethtool.h */

以Intel网卡驱动igb举例,在pci probe函数里调用igb_set_ethtool_ops(netdev),给ethtool_ops结构体里的成员函数赋值。

1. module_init(igb_init_module);

2. ret = pci_register_driver(&igb_driver);

3. static int igb_probe(struct pci_dev *, const struct pci_device_id *)
{
        ......
        igb_set_ethtool_ops(netdev);
        ......
}
/* linux-3.10.0-957.el7/drivers/net/ethernet/intel/igb/igb_main.c */

static int igb_get_module_eeprom(struct net_device *netdev,
                                 struct ethtool_eeprom *ee, u8 *data)
{
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        u32 status = 0;
        u16 *dataword;
        u16 first_word, last_word;
        int i = 0;

        if (ee->len == 0)
                return -EINVAL;

        first_word = ee->offset >> 1;
        last_word = (ee->offset + ee->len - 1) >> 1;

        dataword = kmalloc(sizeof(u16) * (last_word - first_word + 1),
                           GFP_KERNEL);
        if (!dataword)
                return -ENOMEM;

        /* Read EEPROM block, SFF-8079/SFF-8472, word at a time */
        for (i = 0; i < last_word - first_word + 1; i++) {
                status = igb_read_phy_reg_i2c(hw, (first_word + i) * 2,
                                              &dataword[i]);
                if (status) {
                        /* Error occurred while reading module */
                        kfree(dataword);
                        return -EIO;
                }

                be16_to_cpus(&dataword[i]);
        }

        memcpy(data, (u8 *)dataword + (ee->offset & 1), ee->len);
        kfree(dataword);

        return 0;
}

static const struct ethtool_ops igb_ethtool_ops = {
        .get_drvinfo            = igb_get_drvinfo,
        .get_regs_len           = igb_get_regs_len,
        .get_regs               = igb_get_regs,
        .get_wol                = igb_get_wol,
        .set_wol                = igb_set_wol,
        .get_msglevel           = igb_get_msglevel,
        .set_msglevel           = igb_set_msglevel,
        .nway_reset             = igb_nway_reset,
        .get_link               = igb_get_link,
        .get_eeprom_len         = igb_get_eeprom_len,
        .get_eeprom             = igb_get_eeprom,
        .set_eeprom             = igb_set_eeprom,
        .get_ringparam          = igb_get_ringparam,
        .set_ringparam          = igb_set_ringparam,
        .get_pauseparam         = igb_get_pauseparam,
        .set_pauseparam         = igb_set_pauseparam,
        .self_test              = igb_diag_test,
        .get_strings            = igb_get_strings,
        .set_phys_id            = igb_set_phys_id,
        .get_sset_count         = igb_get_sset_count,
        .get_ethtool_stats      = igb_get_ethtool_stats,
        .get_coalesce           = igb_get_coalesce,
        .set_coalesce           = igb_set_coalesce,
        .get_ts_info            = igb_get_ts_info,
        .get_rxnfc              = igb_get_rxnfc,
        .set_rxnfc              = igb_set_rxnfc,
        .get_eee                = igb_get_eee,
        .set_eee                = igb_set_eee,
        .get_module_info        = igb_get_module_info,
        .get_module_eeprom      = igb_get_module_eeprom,
        .get_rxfh_indir_size    = igb_get_rxfh_indir_size,
        .get_rxfh               = igb_get_rxfh,
        .set_rxfh               = igb_set_rxfh,
        .get_channels           = igb_get_channels,
        .set_channels           = igb_set_channels,
        .get_priv_flags         = igb_get_priv_flags,
        .set_priv_flags         = igb_set_priv_flags,
        .begin                  = igb_ethtool_begin,
        .complete               = igb_ethtool_complete,
        .get_link_ksettings     = igb_get_link_ksettings,
        .set_link_ksettings     = igb_set_link_ksettings,
};

void igb_set_ethtool_ops(struct net_device *netdev)
{
        netdev->ethtool_ops = &igb_ethtool_ops;
}
/* linux-3.10.0-957.el7/drivers/net/ethernet/intel/igb/igb_ethtool.c */

ethtool应用程序

github地址

#ifndef TEST_ETHTOOL
int send_ioctl(struct cmd_context *ctx, void *cmd)
{
    ctx->ifr.ifr_data = cmd;
    return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
}
#endif

static int do_getmodule(struct cmd_context *ctx)
{
    struct ethtool_modinfo modinfo;
    struct ethtool_eeprom *eeprom;
    u32 geeprom_offset = 0;
    u32 geeprom_length = -1;
    int geeprom_changed = 0;
    int geeprom_dump_raw = 0;
    int geeprom_dump_hex = 0;
    int err;

    struct cmdline_info cmdline_geeprom[] = {
        { "offset", CMDL_U32, &geeprom_offset, NULL },
        { "length", CMDL_U32, &geeprom_length, NULL },
        { "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
        { "hex", CMDL_BOOL, &geeprom_dump_hex, NULL },
    };

    parse_generic_cmdline(ctx, &geeprom_changed,
                  cmdline_geeprom, ARRAY_SIZE(cmdline_geeprom));

    if (geeprom_dump_raw && geeprom_dump_hex) {
        printf("Hex and raw dump cannot be specified together\n");
        return 1;
    }

    modinfo.cmd = ETHTOOL_GMODULEINFO;
    err = send_ioctl(ctx, &modinfo);
    if (err < 0) {
        perror("Cannot get module EEPROM information");
        return 1;
    }

    if (geeprom_length == -1)
        geeprom_length = modinfo.eeprom_len;

    if (modinfo.eeprom_len < geeprom_offset + geeprom_length)
        geeprom_length = modinfo.eeprom_len - geeprom_offset;

    eeprom = calloc(1, sizeof(*eeprom)+geeprom_length);
    if (!eeprom) {
        perror("Cannot allocate memory for Module EEPROM data");
        return 1;
    }

    eeprom->cmd = ETHTOOL_GMODULEEEPROM;
    eeprom->len = geeprom_length;
    eeprom->offset = geeprom_offset;
    err = send_ioctl(ctx, eeprom);
    if (err < 0) {
        perror("Cannot get Module EEPROM data");
        free(eeprom);
        return 1;
    }

    /*
     * SFF-8079 EEPROM layout contains the memory available at A0 address on
     * the PHY EEPROM.
     * SFF-8472 defines a virtual extension of the EEPROM, where the
     * microcontroller on the SFP/SFP+ generates a page at the A2 address,
     * which contains data relative to optical diagnostics.
     * The current kernel implementation returns a blob, which contains:
     *  - ETH_MODULE_SFF_8079 => The A0 page only.
     *  - ETH_MODULE_SFF_8472 => The A0 and A2 page concatenated.
     */
    if (geeprom_dump_raw) {
        fwrite(eeprom->data, 1, eeprom->len, stdout);
    } else {
        if (eeprom->offset != 0  ||
            (eeprom->len != modinfo.eeprom_len)) {
            geeprom_dump_hex = 1;
        } else if (!geeprom_dump_hex) {
            switch (modinfo.type) {
#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
            case ETH_MODULE_SFF_8079:
                sff8079_show_all(eeprom->data);
                break;
            case ETH_MODULE_SFF_8472:
                sff8079_show_all(eeprom->data);
                sff8472_show_all(eeprom->data);
                break;
#endif
            default:
                geeprom_dump_hex = 1;
                break;
            }
        }
        if (geeprom_dump_hex)
            dump_hex(stdout, eeprom->data,
                 eeprom->len, eeprom->offset);
    }

    free(eeprom);

    return 0;
}


static const struct option {
    const char *opts;
    int want_device;
    int (*func)(struct cmd_context *);
    char *help;
    char *opthelp;
} args[] = {

    { "-i|--driver", 1, do_gdrv, "Show driver information" },
    { "-m|--dump-module-eeprom|--module-info", 1, do_getmodule,
      "Query/Decode Module EEPROM information and optical diagnostics if available",
      "     [ raw on|off ]\n"
      "     [ hex on|off ]\n"
      "     [ offset N ]\n"
      "     [ length N ]\n" },
    {}
};

/* ethtool.c */

ethtool应用程序在获取可插拔模块eeprom信息的时候,根据命令行-m参数,调用do_getmodule函数,在具体代码实现过程描述为,通过ioclt socket套接字下发获取命令,得到eeprom->data后通过sff8079_show_all(eeprom->data);和sff8472_show_all(eeprom->data);把EEPROM信息打印出来。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值