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(ðcmd, 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" 这四个字符串啊
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(ðcmd, 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" 这四个字符串啊
阅读全文
0 0
- ethtool 命令对应的driver的具体实现
- 实验常用的ethtool命令
- Ethtool设置网卡参数的命令
- ethtool 命令输出的注意点
- cat命令的具体实现代码
- 具体命令的分析
- ethtool命令
- ethtool测定Linux服务器上网卡硬件与网口的对应关系
- 在 Windows7、64x、VS2010环境下安装C++ driver/mongoDB并配置的具体实现
- java.sql.Types的具体对应值
- ethtool的内核流程跟踪
- 编译arm平台的ethtool
- 编译arm平台的ethtool
- C#利用dig命令解析SRV方法的具体实现
- itext的具体实现
- LocalConnection的具体实现
- String的具体实现
- 堆的具体实现
- Failed to register in JMX: javax.naming.NamingException: Could not load resource factory class
- 经典KVM详解,太详细太深入了
- 第二十一章 授予身份及切换身份——《跟我学Shiro》
- java运行时异常和检查异常
- 深入理解bootloader_2 ----- Linux开发环境
- ethtool 命令对应的driver的具体实现
- Eclipse恢复已删除的文件和代码、svn使用了还原,但本地的没有提交找回没提交代码的方法
- C++实现快速排序算法
- SDUT 3806 离散题目12
- SQLite学习手册(C/C++接口简介)
- 设置input中placeholder的字体颜色及属性
- 第二十二章 集成验证码——《跟我学Shiro》
- Openssl命令行生成公私钥
- 台湾大学林轩田机器学习基石课程学习笔记13 -- Hazard of Overfitting