ethtool功能十分强大,本文就其源码进行简单的分析,一来很久没好好分析过别人家的代码,和代码几乎都脱节了;二来趁机整理下自己最近所搞的东西。

本文使用的版本下载地址:http://sourceforge.net/projects/gkernel/files/ethtool/2.6.35/

最新的代码在linux kernel官网上:https://www.kernel.org/pub/software/network/ethtool/

代码树结构

主代码:所有主要代码在ethtool.c这个文件,

头文件:类型定义和打印各网卡的寄存器函数在ethtool-util.h头文件,另外该工程没有使用系统提供的ethtool.h头文件,而是在ethtool-copy.h重新定义了ethtool_cmd结构体,也定义了ioctl函数使用到的命令ETHTOOL_GSET、ETHTOOL_SSET等,另外也定义了如SUPPORTED_10baseT_Half、SUPPORTED_10baseT_Full、SUPPORTED_100baseT_Half、SUPPORTED_100baseT_Full、ADVERTISED_10baseT_Half这类宏,总之,从其文件名称可以知道,其实它就是系统的ethtool.h的拷贝。

其它文件:其它大部分文件是打印不同网卡寄存器的实现代码,比如intel的有e100.c、e1000.c、igb.c等,realtek的有realtek.c文件。

代码讲解

主函数十分简单,如下:

int main(int argc, char **argp, char **envp)
{parse_cmdline(argc, argp);return doit();
}

其中用以分析用户传入的参数,而doit是真正执行的函数,它们使用全局变量来传递参数,所以显示主函数十分简单。

在这里先总结一下ethtool使用的形式,以便有一个认识:

struct ifreq ifr; // 定义ifreq
struct ethtool_cmd ecmd; // 定义ethtool_cmd结构体strcpy(ifr.ifr_name, devname); //指定网卡名称
fd = socket(AF_INET, SOCK_DGRAM, 0); // 打开socket
ecmd.cmd = ETHTOOL_GSET; // ethtool的某一命令
ifr.ifr_data = (caddr_t)&ecmd;
ioctl(fd, SIOCETHTOOL, &ifr); // 执行SIOCETHTOOL

变量及函数

上面提到真正执行的函数是doit(),其实它是根据不同的mode来执行不同的函数的,这些函数一般是do_XX的形式。其中第一个参数为socket描述符,第二个是ifreq结构体指针,ifreq是所有socket的ioctl用到的结构体,具体可以看头文件的定义。这类的函数列举几个,如下:

static int do_gdrv(int fd, struct ifreq *ifr); // 获取驱动信息
static int do_gset(int fd, struct ifreq *ifr); // 获取网卡参数
static int do_sset(int fd, struct ifreq *ifr); // 设置网卡参数

这些函数没有看到SIOCETHTOOL,是因为调用了send_ioctl:

static int send_ioctl(int fd, struct ifreq *ifr)
{return ioctl(fd, SIOCETHTOOL, ifr);
}

mode为枚举,如下:

static enum {MODE_HELP = -1,MODE_GSET=0,MODE_SSET,MODE_GDRV,MODE_GREGS,MODE_NWAY_RST,MODE_GEEPROM,MODE_SEEPROM,MODE_TEST,MODE_PHYS_ID,MODE_GPAUSE,MODE_SPAUSE,MODE_GCOALESCE,MODE_SCOALESCE,MODE_GRING,MODE_SRING,MODE_GOFFLOAD,MODE_SOFFLOAD,MODE_GSTATS,MODE_GNFC,MODE_SNFC,MODE_GRXFHINDIR,MODE_SRXFHINDIR,MODE_SNTUPLE,MODE_GNTUPLE,MODE_FLASHDEV,MODE_PERMADDR,
} mode = MODE_GSET;

另外,有许多静态全局变量用于传递参数,如:

static int speed_wanted = -1; // 手动指定的网速,比如百兆,则此值为100,千兆为1000
static int duplex_wanted = -1; // 全双工或半双工
static int autoneg_wanted = -1; // 自动协商
static int advertising_wanted = -1;
static int gset_changed = 0; /* did anything in GSET change? */ // 在设置网卡信息时,此标志是否需要先读取网卡再进行设置

像网速、双工这类的参数,在ethtool-copy.h定义有,如:

/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
#define SPEED_10        10
#define SPEED_100       100
#define SPEED_1000      1000
#define SPEED_2500      2500
#define SPEED_10000     10000/* Duplex, half or full. */
#define DUPLEX_HALF     0x00
#define DUPLEX_FULL     0x01

自动协商的定义:

#define AUTONEG_DISABLE      0x00
#define AUTONEG_ENABLE      0x01

其它的函数、变量还有很多,不一一列举出来了。

参数解析

ethtool的帮助信息使用结构体option来管理。通过show_usage来打印。定义如下:

static struct option {char *srt, *lng;int Mode;char *help;char *opthelp;
}

这个结构体内容比较多,具体参考代码。
先看看解析用户参数的parse_cmdline函数,

操作函数

doit函数如下:

static int doit(void)
{struct ifreq ifr;int fd;/* Setup our control structures. */memset(&ifr, 0, sizeof(ifr));strcpy(ifr.ifr_name, devname);/* Open control socket. */fd = socket(AF_INET, SOCK_DGRAM, 0);if (fd < 0) {perror("Cannot get control socket");return 70;}/* all of these are expected to populate ifr->ifr_data as needed */if (mode == MODE_GDRV) {return do_gdrv(fd, &ifr);} else if (mode == MODE_GSET) {return do_gset(fd, &ifr);} else if (mode == MODE_SSET) {return do_sset(fd, &ifr);} else if (mode == MODE_GREGS) {return do_gregs(fd, &ifr);} else if (mode == MODE_NWAY_RST) {return do_nway_rst(fd, &ifr);} else if (mode == MODE_GEEPROM) {return do_geeprom(fd, &ifr);} else if (mode == MODE_SEEPROM) {return do_seeprom(fd, &ifr);} else if (mode == MODE_TEST) {return do_test(fd, &ifr);} else if (mode == MODE_PHYS_ID) {return do_phys_id(fd, &ifr);} else if (mode == MODE_GPAUSE) {return do_gpause(fd, &ifr);} else if (mode == MODE_SPAUSE) {return do_spause(fd, &ifr);} else if (mode == MODE_GCOALESCE) {return do_gcoalesce(fd, &ifr);} else if (mode == MODE_SCOALESCE) {return do_scoalesce(fd, &ifr);} else if (mode == MODE_GRING) {return do_gring(fd, &ifr);} else if (mode == MODE_SRING) {return do_sring(fd, &ifr);} else if (mode == MODE_GOFFLOAD) {return do_goffload(fd, &ifr);} else if (mode == MODE_SOFFLOAD) {return do_soffload(fd, &ifr);} else if (mode == MODE_GSTATS) {return do_gstats(fd, &ifr);} else if (mode == MODE_GNFC) {return do_grxclass(fd, &ifr);} else if (mode == MODE_SNFC) {return do_srxclass(fd, &ifr);} else if (mode == MODE_GRXFHINDIR) {return do_grxfhindir(fd, &ifr);} else if (mode == MODE_SRXFHINDIR) {return do_srxfhindir(fd, &ifr);} else if (mode == MODE_SNTUPLE) {return do_srxntuple(fd, &ifr);} else if (mode == MODE_GNTUPLE) {return do_grxntuple(fd, &ifr);} else if (mode == MODE_FLASHDEV) {return do_flash(fd, &ifr);} else if (mode == MODE_PERMADDR) {return do_permaddr(fd, &ifr);}return 69;
}

这个函数先是将网卡名称赋值给ifreq结构体的ifr_name,再打开socket,然后再调用do_XX形式的函数。虽然调用的函数很多,但结构很清晰,只需了解我们当前是执行哪一种模式的,跟进该函数即可一步一步分析。

下面看看执行ethtool eth0的过程,这是输出指定网卡信息的命令。首先看其输出结果,如下:

root@localhost:~# ethtool eth0
Settings for eth0:Supported ports: [ TP ]Supported link modes:   10baseT/Half 10baseT/Full  // 支持十兆/百兆/千兆半双工、全双工模式100baseT/Half 100baseT/Full1000baseT/Full Supported pause frame use: Symmetric // 当前支持的暂停帧模式为SymmetricSupports auto-negotiation: Yes // 支持自动协商,一般都是支持的Advertised link modes:  10baseT/Half 10baseT/Full // 同上100baseT/Half 100baseT/Full1000baseT/FullAdvertised pause frame use: Symmetric // 这里暂时还不知道是什么意思Advertised auto-negotiation: Yes // 同上Speed: 1000Mb/s // 当前是千兆,如网络断开,此处显示UnknownDuplex: Full    // 双全工Port: Twisted Pair // 双绞线PHYAD: 1 // PHY地址Transceiver: internalAuto-negotiation: on // 自动协商MDI-X: off (auto)Supports Wake-on: pumbgWake-on: gCurrent message level: 0x00000007 (7)drv probe linkLink detected: yes // 当前已经连接到网络中(如交换机),如果拨掉网线,则显示on

(说实话,这里及手册中提到的“Advertised”我还不太知道该怎么理解。)

各种的信息都有,连接模式、暂停帧、自动协商、当前的网速、双工、接口类型、是否已连接上,等等。

不详细分析代码了,主要流程如下所示:

main
-> doit-> do_gset-> send_ioctl(ETHTOOL_GSET)-> dump_ecmd-> dump_supported (打印支持的端口、速率)-> 打印支持端口 "    Supported ports: [ "-> 打印支持速率 "    Supported link modes:   "-> 打印自动协商 "   Supports auto-negotiation: "-> dump_advertised-> 打印支持速率" Advertised link modes:  "-> 打印支持暂停帧" Advertised pause frame use:  " -> 打印自动协商" Advertised auto-negotiation:   "-> 打印速率" Speed: "-> 打印双工"   Duplex: "-> 打印端口"  Port: "-> 打印地址"    PHYAD: %d\n"-> 打印" Transceiver: "-> 打印自动协商"   Auto-negotiation: %s\n"-> 如果是PORT_TP,打印"    MDI-X: "-> send_ioctl(ETHTOOL_GWOL)-> dump_wol-> 打印WOL支持"Supports Wake-on:"-> send_ioctl(ETHTOOL_GMSGLVL)-> 打印信息等级"Current message level"-> send_ioctl(ETHTOOL_GLINK)-> 打印连接状态"Link detected:"

李迟 2015年3月30日写,4月上旬补充



ethtool源码分析相关推荐

  1. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  2. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  3. SpringBoot-web开发(二): 页面和图标定制(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) 目录 一.首页 1. 源码分析 2. 访问首页测试 二.动态页面 1. 动态资源目录t ...

  4. SpringBoot-web开发(一): 静态资源的导入(源码分析)

    目录 方式一:通过WebJars 1. 什么是webjars? 2. webjars的使用 3. webjars结构 4. 解析源码 5. 测试访问 方式二:放入静态资源目录 1. 源码分析 2. 测 ...

  5. Yolov3Yolov4网络结构与源码分析

    Yolov3&Yolov4网络结构与源码分析 从2018年Yolov3年提出的两年后,在原作者声名放弃更新Yolo算法后,俄罗斯的Alexey大神扛起了Yolov4的大旗. 文章目录 论文汇总 ...

  6. ViewGroup的Touch事件分发(源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,View的touch事件分发相对比较简单,可参考 View的Touch事件分发(一.初步了解) View的Touch事 ...

  7. View的Touch事件分发(二.源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,先来看简单的View的touch事件分发. 主要分析View的dispatchTouchEvent()方法和onTou ...

  8. MyBatis原理分析之四:一次SQL查询的源码分析

    上回我们讲到Mybatis加载相关的配置文件进行初始化,这回我们讲一下一次SQL查询怎么进行的. 准备工作 Mybatis完成一次SQL查询需要使用的代码如下: Java代码   String res ...

  9. [转]slf4j + log4j原理实现及源码分析

    slf4j + log4j原理实现及源码分析 转载于:https://www.cnblogs.com/jasonzeng888/p/6051080.html

最新文章

  1. VMRC控制台的连接已断开..正在尝试重新连接
  2. 献给新手的深度学习综述
  3. 组合搜索(combinatorial search)在算法求解中的应用
  4. 【音频处理】Polyphone 样本编辑 和 样本工具 ( 波形图 | 信息 | 频率分析 | 均衡器 | 播放器 | 终点裁剪 | 自动循环节 | 空白移除 | 音量 平衡 音调 调整 )
  5. jQuery 侧栏菜单点击body消失
  6. ASP.NET Core on K8S学习初探(2)
  7. CodeSmith注册机,支持5.2.2和5.2.1版
  8. 关于MSDTC - 与基础事务管理器的通信失败 错误解决的小备忘
  9. graphpad饼状图_应用 Graphpad 统计作图,助你写文章事半功倍
  10. java时间格式转换
  11. 金融笔记:货币的概念
  12. 通达信交易服务器修改,GitHub - sjj6love/TdxTradeServer: TongDaXin Tarde Server 通达信交易服务器...
  13. XML文件约束之DTD详解
  14. 如果应用闪退,怎么获取相关日志?
  15. 在64位的Linux系统使用gcc的-m32选项编译32位的程序得到了多余的代码(多余指令call和add)、有多余的.text.__x86.get_pc_thunk.ax
  16. CrossFire和SLI
  17. 三种编程规则:驼峰命名法、帕斯卡命名法、匈牙利名
  18. 【pandas数据分析】pandas概述
  19. SPO 二,SharePoint On-Premises, Online, On Azure.
  20. 色即是空,空即是色---java有关null的几件小事

热门文章

  1. 女性最容易动心的21种时刻
  2. 中概股暴跌后的大厂员工:230万缩水至23万、和家人一起“开源节流”
  3. 死磕苹果,小米飘了?
  4. 晶方科技拟进一步加强对以色列第三代半导体公司VisIC的投资
  5. 贝壳反击浑水做空报告 股价上涨近6%
  6. Beats发布Beats Fit Pro耳机 停产Powerbeats等三款旧耳机
  7. 谷歌Pixel 6系列手机发布会官宣定档 10月19日发布
  8. 小米11 Pro屏幕细节曝光:至少要上2K+分辨率
  9. 拼多多市值超1600亿美元 成中国第四大互联网公司
  10. 罗永浩今晚带货iPhone 12:价格将有惊喜!