ethtool 命令对应的driver的具体实现

来源:互联网 发布:2017年nba数据库排名 编辑:程序博客网 时间:2024/05/22 08:11
在net/core/dev_ethtool 中的dev_ethtool定义了ethtool 这个工具向下调用的接口
int dev_ethtool(struct net *net, struct ifreq *ifr)
{
    struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
    void __user *useraddr = ifr->ifr_data;
    u32 ethcmd, sub_cmd;
    int rc;
    netdev_features_t old_features;

    if (!dev || !netif_device_present(dev))
        return -ENODEV;

    if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
        return -EFAULT;

    if (ethcmd == ETHTOOL_PERQUEUE) {
        if (copy_from_user(&sub_cmd, useraddr + sizeof(ethcmd), sizeof(sub_cmd)))
            return -EFAULT;
    } else {
        sub_cmd = ethcmd;
    }
    /* Allow some commands to be done by anyone */
        switch (ethcmd) {
    case ETHTOOL_GSET:
        rc = ethtool_get_settings(dev, useraddr);
        break;
    case ETHTOOL_SSET:
        rc = ethtool_set_settings(dev, useraddr);
        break;
    case ETHTOOL_GDRVINFO:
        rc = ethtool_get_drvinfo(dev, useraddr);
        break;
    return rc;
}

这里先通过netif_device_present 来判断要通过ioctl查询的net device是否存在
static inline bool netif_device_present(struct net_device *dev)
{
    return test_bit(__LINK_STATE_PRESENT, &dev->state);
}
其实也就是判断dev->state 是否包含__LINK_STATE_PRESENT 这个flag.
然后通过copy_from_user将user space的值copy到kernel space,然后根据ethcmd来掉对应的函数,这里以ETHTOOL_GDRVINFO 为例
static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
                          void __user *useraddr)
{
    struct ethtool_drvinfo info;
    const struct ethtool_ops *ops = dev->ethtool_ops;

    memset(&info, 0, sizeof(info));
    info.cmd = ETHTOOL_GDRVINFO;
    if (ops->get_drvinfo) {
        ops->get_drvinfo(dev, &info);
    } else if (dev->dev.parent && dev->dev.parent->driver) {
        strlcpy(info.bus_info, dev_name(dev->dev.parent),
            sizeof(info.bus_info));
        strlcpy(info.driver, dev->dev.parent->driver->name,
            sizeof(info.driver));
    } else {
        return -EOPNOTSUPP;
    }

    /*
     * this method of obtaining string set info is deprecated;
     * Use ETHTOOL_GSSET_INFO instead.
     */
    if (ops->get_sset_count) {
        int rc;

        rc = ops->get_sset_count(dev, ETH_SS_TEST);
        if (rc >= 0)
            info.testinfo_len = rc;
        rc = ops->get_sset_count(dev, ETH_SS_STATS);
        if (rc >= 0)
            info.n_stats = rc;
        rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
        if (rc >= 0)
            info.n_priv_flags = rc;
    }
    if (ops->get_regs_len)
        info.regdump_len = ops->get_regs_len(dev);
    if (ops->get_eeprom_len)
        info.eedump_len = ops->get_eeprom_len(dev);

    if (copy_to_user(useraddr, &info, sizeof(info)))
        return -EFAULT;
    return 0;
}
注意这里的const struct ethtool_ops *ops = dev->ethtool_ops;的赋值,也就是说driver到底支持多少ethtool的命令是有driver自己实现的。
这里通过ops->get_drvinfo(dev, &info);将的到的至存在info中,如果driver本事没有实现这个get_drvinfo 这个函数,则将其parent的businfo 和driver info复制到info中.
最后通过copy_to_user将得到的info copy到user space。
那这里的dev->ethtool_ops 是在哪里赋值的呢?
一般是在net driver 底层实现总赋值的,举例如下:
static const struct ethtool_ops hns_ethtool_ops = {
    .get_drvinfo = hns_nic_get_drvinfo,
    .get_link  = hns_nic_get_link,
    .get_ringparam = hns_get_ringparam,

};

void hns_ethtool_set_ops(struct net_device *ndev)
{
    ndev->ethtool_ops = &hns_ethtool_ops;
}
通过调用hns_ethtool_set_ops 就会给ndev->ethtool_ops 赋值,这样在ethtool_get_drvinfo 中就可以通过const struct ethtool_ops *ops = dev->ethtool_ops; 来得到这个ops。
我们还是以get_drvinfo 的实现函数hns_nic_get_drvinfo为例继续看
static void hns_nic_get_drvinfo(struct net_device *net_dev,
                struct ethtool_drvinfo *drvinfo)
{
    struct hns_nic_priv *priv = netdev_priv(net_dev);

    strncpy(drvinfo->version, HNAE_DRIVER_VERSION,
        sizeof(drvinfo->version));
    drvinfo->version[sizeof(drvinfo->version) - 1] = '\0';

    strncpy(drvinfo->driver, HNAE_DRIVER_NAME, sizeof(drvinfo->driver));
    drvinfo->driver[sizeof(drvinfo->driver) - 1] = '\0';

    strncpy(drvinfo->bus_info, priv->dev->bus->name,
        sizeof(drvinfo->bus_info));
    drvinfo->bus_info[ETHTOOL_BUSINFO_LEN - 1] = '\0';

    strncpy(drvinfo->fw_version, "N/A", ETHTOOL_FWVERS_LEN);
    drvinfo->eedump_len = 0;
}
原来所谓的driverinfo就是HNAE_DRIVER_VERSION/HNAE_DRIVER_NAME/priv->dev->bus->name/"N/A" 这四个字符串啊



原创粉丝点击