这些天开始下决心写写Linux网络方面的文章。由于能力和时间有限,当前还没有对Linux的网络有深入的了解。我一开始打算从网卡基本知识到PHY寄存器,到MAC控制器,到以太网协议栈,一步一步地学习。但实际中发现不能如此,在公司不同在学校,不可能有集中的时间精力去学习的,比如,刚刚使用了iperf来测试网卡性能,又要在内核中打印出PHY芯片寄存器,而前提是要对PHY有一定了解。同时又要了解设备所处的网络拓扑,又不得不去看看交换机方面的资料。在这种情形下,似乎没有规律地做事,完全由工作需求来驱动。在做事的同时我也在记录要点,希望可以整理出主线。在业余时便将这些要点发散、整理。因此,在写文章时就已经对自己进行定位,从感性的认识上入手,慢慢去学习,去接触。比如,因工作上的需要学习了ethtool,于是以此为切入点,看看内核关于ethtool到底是怎么控制的。再比如从网卡使能到禁止跟踪相关的内核流程。
前面的文章讲了ethtool工具的源码分析,内核集成了ethtool命令的控制,所以用户空间才能如此方便地查询、设置以太网卡。本文主要讲一下内核空间ethtool的跟踪。
ethtool可以认为是一种框架,内核已经集成了,它担负着用户空间和具体网络设备驱动之间的交互,包括查询、设置网卡信息。
主要结构体在函数在include/linux/ethtool.h中定义。
控制命令结构体如下:
1 | struct ethtool_cmd { |
当查询网卡信息时这个结构体保存着查询到的信息,比如网速、双工,是否自动协商,等。当设置网卡时,里面的字段就是用户指定的信息。这个结构体负责着信息传递的作用。
另一个重要的网络操作函数集结构体定义如下:
1 |
|
里面的函数指针由具体的网络驱动程序来赋值。在下面将要分析到的函数,我们可以看到实际上就是调用ethtool_ops中的函数指针的。
常用的共用函数:
1 | u32 ethtool_op_get_link(struct net_device *dev); |
这些函数可以由具体的驱动程序来使用,比如获取当前连接状态的ethtool_op_get_link,就有很多驱动在使用。当然至于使用哪些,由网络驱动来决定。
下面是常见的控制命令和宏定义:
1 | //支持的命令: |
ethtool的关键函数为dev_ethtool,在该函数中根据不同的命令调用不同的函数。函数如下:
1 | /* The main entry point in this file. Called from net/core/dev.c */ |
dev_ethtool函数是被dev_ioctl函数(位于net/core/dev.c)调用的,dev_ioctl是网络设备的ioctl总入口函数,ethtool用到的SIOCETHTOOL命令,实际是其中的一个命令分支,而如ETHTOOL_GSET之类的命令,是dev_ethtool函数的中命令。这两类的命令层次是十分明显的。dev_ioctl:
1 | int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) |
获取网卡信息的控制命令为ETHTOOL_GSET,调用的函数为ethtool_get_settings:
1 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) |
而该函数实际调用的是ethtool_ops结构体中的get_settings。所有的命令控制过程大多是如此。
设置网卡信息:
1 | static int ethtool_set_settings(struct net_device *dev, void __user *useraddr) |
常用的公共函数使用EXPORT_SYMBOL导出,以便其它模块也可以使用,如获取当前连接状态的函数:
1 | u32 ethtool_op_get_link(struct net_device *dev) |
以Intel网卡驱动igb为例看看如何使用ethtool_ops。igb驱动代码位于drivers/net/igb。与ethtool有关的代码在igb_ethtool.c文件。ethtool_ops定义如下:
1 | static const struct ethtool_ops igb_ethtool_ops = { |
igb支持的函数(即ethtool工具可以使用的参数)很多。像get_sg,就直接使用了ethtool.c定义的ethtool_op_get_sg,其它大部分则自定义实现。igb_ethtool_ops在igb_set_ethtool_ops被调用,而igb_set_ethtool_ops则在igb的探测函数igb_probe中被调用,这样,当驱动运行时,ethtool也就可以使用了。
1 | void igb_set_ethtool_ops(struct net_device *netdev) |
实际上就是将igb_ethtool_ops赋值给net_device结构体的ethtool_ops指针,从而使得ethtool.c中对应的函数指针可以被调用。比如dev->ethtool_ops->get_settings。 再看一下dm9000的使用,ethtool_ops定义:
1 | static const struct ethtool_ops dm9000_ethtool_ops = { |
从上述结构体赋值可以看到,igb驱动支持的命令要比dm9000多很多。
同样在dm9000探测函数中进行赋值:
1 |
|
2015年3月29日 着手写