ethtool源码分析
来源:互联网 发布:北京域名 编辑:程序博客网 时间:2024/05/20 21:47
本文使用的版本下载地址: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; // 定义ifreqstruct ethtool_cmd ecmd; // 定义ethtool_cmd结构体strcpy(ifr.ifr_name, devname); //指定网卡名称fd = socket(AF_INET, SOCK_DGRAM, 0); // 打开socketecmd.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,千兆为1000static 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_1010#define SPEED_100100#define SPEED_10001000#define SPEED_25002500#define SPEED_1000010000/* Duplex, half or full. */#define DUPLEX_HALF0x00#define DUPLEX_FULL0x01
自动协商的定义:
#define AUTONEG_DISABLE0x00#define AUTONEG_ENABLE0x01
其它的函数、变量还有很多,不一一列举出来了。
参数解析
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 eth0Settings for eth0: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full // 支持十兆/百兆/千兆半双工、全双工模式 100baseT/Half 100baseT/Full 1000baseT/Full Supported pause frame use: Symmetric // 当前支持的暂停帧模式为Symmetric Supports auto-negotiation: Yes // 支持自动协商,一般都是支持的 Advertised link modes: 10baseT/Half 10baseT/Full // 同上 100baseT/Half 100baseT/Full 1000baseT/Full Advertised pause frame use: Symmetric // 这里暂时还不知道是什么意思 Advertised auto-negotiation: Yes // 同上 Speed: 1000Mb/s // 当前是千兆,如网络断开,此处显示Unknown Duplex: Full // 双全工 Port: Twisted Pair // 双绞线 PHYAD: 1 // PHY地址 Transceiver: internal Auto-negotiation: on // 自动协商 MDI-X: off (auto) Supports Wake-on: pumbg Wake-on: g Current message level: 0x00000007 (7) drv probe link Link 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源码分析
- DM9000网卡驱动源码分析系列04 - ethtool
- ethtool
- ethtool
- Linux:Ethtool
- linux ethtool
- ethtool命令
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- mii-tool和ethtool
- ethtool 命令详解
- ethtool 命令详解
- Android 获取Ethernet IP、mask、dns、gw、mac
- 循环-16. 猴子吃桃问题(15)
- Deep Learning(深度学习)学习笔记整理系列之(二)
- Linux集群-LVS+Keepalived(DR模式)
- ethtool的内核流程跟踪
- ethtool源码分析
- 参考ethtool写了个Linux设置、获取网卡模式的接口
- Deep Learning(深度学习)学习笔记整理系列之(三)
- MySQL导入/导出命令
- 最大乘积
- activity之launchMode
- 0.前言
- Android之Adapter用法总结
- C++中的namespace