启用中断
此时,几乎所有东西都已设置好。剩下的只是启用网卡的中断并等待数据到达。启用中断是硬件特定的,但 igb
驱动程序在 __igb_open
中调用名为 igb_irq_enable
的辅助函数来实现。
写入寄存器为此设备启用中断。
static void igb_irq_enable(struct igb_adapter *adapter) { /* ... */ wr32(E1000_IMS, IMS_ENABLE_MASK | E1000_IMS_DRSTA); wr32(E1000_IAM, IMS_ENABLE_MASK | E1000_IMS_DRSTA); /* ... */ }
网络设备现已启动
驱动程序可能会做一些其他事情,如启动计时器、工作队列或其他硬件特定的设置。一旦完成,网络设备就已启动并准备好使用。
让我们看看如何监控和调优网络设备驱动程序的设置。
监控网络设备
有几种不同的方法可以监控您的网络设备,提供不同程度的粒度和复杂性。让我们从最精细的开始,逐渐过渡到最粗略的。
ethtool -S
使用
您可以运行 sudo apt-get install ethtool
在 Ubuntu 系统上安装 ethtool
。
安装完成后,您可以传递 -S
标志以及您想要获取统计信息的网络设备名称来访问统计信息。
使用 ethtool -S
监控详细的网卡设备统计信息(例如,数据包丢弃)。
$ sudo ethtool -S eth0 NIC statistics: rx_packets: 597028087 tx_packets: 5924278060 rx_bytes: 112643393747 tx_bytes: 990080156714 rx_broadcast: 96 tx_broadcast: 116 rx_multicast: 20294528 ....
监控这些数据可能很困难。它很容易获得,但字段值没有标准化。不同的驱动程序,甚至不同版本的 相同 驱动程序可能会产生具有相同含义的不同字段名称。
您应该寻找带有 “drop”、“buffer”、“miss” 等标签的值。接下来,您将不得不阅读驱动程序源代码。您能够确定哪些值完全在软件中计算(例如,没有内存时增加),哪些值直接读取寄存器从硬件获得。对于寄存器值,您应该查阅硬件的数据表,以确定计数器的真实含义; ethtool
给出的许多标签都可能是误导性的。
sysfs 使用
sysfs 也提供了许多统计值,但它们的层级比直接提供的网卡级别统计值略高一些。
您可以使用 cat
在文件上查找丢弃的传入网络数据帧的数量,例如 eth0。
使用 sysfs 监控更高层级的网卡统计信息。
$ cat /sys/class/net/eth0/statistics/rx_dropped 2
计数器值分为 collisions
、rx_dropped
、rx_errors
、rx_missed_errors
等文件。
不幸的是,由驱动程序决定每个字段的含义,何时增加它们以及值来自哪里。您可能会注意到,有些驱动程序将某种类型的错误条件计为丢弃,但其他驱动程序可能将其计为错过。
如果这些值对您至关重要,您需要阅读驱动程序源代码,以准确了解您的驱动程序认为每个值的含义。
/proc/net/dev
使用
一个更高层级的文件是 /proc/net/dev
,它为系统上的每个网络适配器提供高层级概要信息。
读取 /proc/net/dev
监控高层级网卡统计信息。
$ cat /proc/net/dev Inter-| Receive | Transmit face | bytes packets errs drop fifo frame compressed multicast | bytes packets errs drop fifo colls carrier compressed eth0: 110346752214 597737500 0 2 0 0 0 20963860 990024805984 6066582604 0 0 0 0 0 0 lo: 428349463836 1579868535 0 0 0 0 0 0 428349463836 1579868535 0 0 0 0 0 0
这个文件显示了上面提到的 sysfs 文件中找到的值的子集,但它可能作为一个有用的一般参考。
上面提到的警告在这里也适用:如果这些值对您很重要,您仍然需要阅读驱动程序源代码,以准确了解何时、何地以及为什么它们会增加,以确保您对 error、drop 或 fifo 的理解与你的驱动程序相同。
调优网络设备
检查正在使用的接收队列数量
如果您的网卡和系统上加载的设备驱动程序支持 RSS / 多队列,您通常可以使用 ethtool
调整接收队列(也称为接收通道)的数量。
使用 ethtool
检查网卡接收队列的数量。
$ sudo ethtool -l eth0 Channel parameters for eth0: Pre-set maximums: RX: 0 TX: 0 Other: 0 Combined: 8 Current hardware settings: RX: 0 TX: 0 Other: 0 Combined: 4
此输出显示预设的最大值(由驱动程序和硬件强制执行)和当前设置。
注意: 并非所有设备驱动程序都支持此操作。
如果您的 NIC 不支持此操作,则会出现错误。
$ sudo ethtool -l eth0 Channel parameters for eth0: Cannot get device channel parameters : Operation not supported
这意味着您的驱动程序没有实现 ethtool 的 get_channels
操作。这可能是因为网卡不支持调整队列数量,不支持 RSS / 多队列,或者您的驱动程序尚未更新以处理此功能。
调整接收队列的数量
一旦您找到了当前和最大队列数,您可以使用 sudo ethtool -L
调整这些值。
注意: 一些设备及其驱动程序仅支持组合队列,用于传输和接收,如上一节中的示例。
使用 ethtool -L
设置组合网卡传输和接收队列为 8。
$ sudo ethtool -L eth0 combined 8
如果您的设备和驱动程序支持单独设置接收队列和传输队列,并且您只想更改接收队列数为 8,则可以运行:
使用 ethtool -L
设置 NIC 接收队列数为 8。
$ sudo ethtool -L eth0 rx 8
注意: 对于大多数驱动程序,这些更改将使接口下线,然后重新启动;与此接口的连接将中断。对于一次性更改,这可能并不重要。
调整接收队列的大小
一些网卡及其驱动程序也支持调整接收队列的大小。具体如何操作取决于硬件,但幸运的是,ethtool
为用户提供了一种通用的调整大小的方法。在接收大量数据帧的时期,增加接收队列的大小可以帮助防止网卡丢失网络数据。不过,数据仍然可能在软件中丢失,并且需要其他调整来减少或完全消除丢失。
使用 ethtool -g
检查当前网卡队列大小。
$ sudo ethtool -g eth0 Ring parameters for eth0: Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 Current hardware settings: RX: 512 RX Mini: 0 RX Jumbo: 0 TX: 512
上述输出表明硬件支持最多 4096 个接收和传输描述符,但目前仅使用 512 个。
使用 ethtool -G
增加每个接收队列的大小到 4096。
$ sudo ethtool -G eth0 rx 4096
注意: 对于大多数驱动程序,这些更改将使接口下线,然后重新启动;与此接口的连接将中断。对于一次性更改,这可能并不重要。
调整接收队列的处理权重
一些网卡支持设置权重来调整网络数据在接收队列之间的分配。
如果满足以下条件,您可以进行配置:
- 网卡支持流量引导。
- 驱动程序实现了
ethtool
函数get_rxfh_indir_size
和get_rxfh_indir
。 - 运行的
ethtool
版本足够新,支持命令行选项-x
和-X
分别显示和设置引导表。
使用 ethtool -x
检查 RX 流量引导表。
$ sudo ethtool -x eth0 RX flow hash indirection table for eth3 with 2 RX ring(s): 0: 0 1 0 1 0 1 0 1 8: 0 1 0 1 0 1 0 1 16: 0 1 0 1 0 1 0 1 24: 0 1 0 1 0 1 0 1
此输出在左侧显示数据包哈希值,其中列出了接收队列 0 和 1。 因此,散列到 2 的数据包将被递送到接收队列 0,而散列到 3 的数据包将被递送到接收队列 1。
示例:在前两个接收队列之间均匀扩散处理
$ sudo ethtool -X eth0 equal 2
如果你想设置自定义权重来改变命中特定接收队列(以及CPU)的数据包数量,你也可以在命令行中指定这些权重:
使用 ethtool -X
设置自定义收队队列权重
$ sudo ethtool -X eth0 weight 6 2
上述命令指定接收队列 0 的权重为 6,接收队列 1 权重为 2,使得推送更多的数据到队列 0 处理。
一些网卡还允许您调整哈希算法中使用的字段,我们接下来会看到。
调整网络流的接收哈希字段
您可以使用 ethtool
来调整计算 RSS 时使用的哈希字段。
使用 ethtool -n
检查 UDP 接收流哈希所用的字段。
$ sudo ethtool -n eth0 rx-flow-hash udp4 UDP over IPV4 flows use these fields for computing Hash flow key: IP SA IP DA
对于 eth0,计算 UDP 流的哈希的字段是 IPv4 源地址和目标地址。让我们添加源端口和目标端口:
使用 ethtool -N
设置 UDP 接收流哈希字段。
$ sudo ethtool -N eth0 rx-flow-hash udp4 sdfn
sdfn
字符串有点神秘;请查看 ethtool
手册页获取每个字母的解释。
调整哈希的字段很有用,但是,对于更精细地控制哪些流将由哪个接收队列处理, ntuple
过滤更有用。
ntuple 过滤引导网络流
一些网卡支持一种称为 “ntuple 过滤” 的功能。此功能允许用户通过 ethtool
指定一组参数,在硬件中过滤传入的网络数据并将其排队到特定的接收队列。例如,用户可以指定目标为特定端口的 TCP 数据包应发送到接收队列 1。
在英特尔网卡上,此功能通常称为 Intel Ethernet Flow Director。其他网卡供应商可能为此功能提供其他营销名称。
正如我们稍后将看到的,ntuple 过滤是另一种称为加速接收流引导 (aRFS) 的功能的关键组成部分,如果您的网卡支持它,则使用 ntuple 更容易。aRFS 将在后面介绍。
如果系统的运行要求最大化数据局部性,以期在处理网络数据时提高 CPU 缓存命中率,那么此功能可能很有用。例如,考虑在端口 80 上运行的 Web 服务器的以下配置:
- 在端口 80 上运行的 Web 服务器被固定在 CPU 2 上运行。
- 接收队列的 IRQ 被分配给 CPU 2 处理。
- 目标为端口 80 的 TCP 流量使用 ntuple 过滤到 CPU 2。
- 所有传入端口 80 的流量都由 CPU 2 处理,从数据到达用户程序开始。
- 需要仔细监控系统,包括缓存命中率和网络堆栈延迟,以确定有效性。
如前所述,可以使用 ethtool
配置 ntuple 过滤,但首先,您需要确保在您的设备上启用了此功能。
使用 ethtool -k
检查是否启用了 ntuple 过滤。
$ sudo ethtool -k eth0 Offload parameters for eth0: ... ntuple-filters: off receive-hashing: on
正如所见,在这个设备上 ntuple-filters
被禁用。
使用 ethtool -K
启用 ntuple 过滤
$ sudo ethtool -K eth0 ntuple on
一旦你启用了 ntuple 过滤,或者验证它已经启用,你可以使用 ethtool
检查现有的ntuple 规则:
使用 ethtool -u
检查现有的 ntuple 过滤
$ sudo ethtool -u eth0 40 RX rings available Total 0 rules
如您所见,此设备没有 ntuple 过滤规则。您可以在 ethtool
命令行上指定它来添加规则。让我们添加一个规则,定向目标端口为 80 的所有 TCP 流量到接收队列 2:
添加 ntuple 过滤器,发送目标端口为 80 的 TCP 流量到接收队列 2。
$ sudo ethtool -U eth0 flow-type tcp4 dst-port 80 action 2
您还可以使用 ntuple 过滤在硬件级别丢弃特定流的数据包。这对于缓解来自特定 IP 地址的大量传入流量很有用。有关配置 ntuple 过滤规则的更多信息,请参阅 ethtool
手册页。
您通常可以检查 ethtool -S [设备名称]
输出的值来获取有关 ntuple 规则成功(或失败)的统计信息。例如,在英特尔网卡上,统计信息 fdir_match
和 fdir_miss
计算您的 ntuple 过滤规则的匹配和未命中次数。请查阅您的设备驱动程序源代码和设备数据表以追查统计计数器(如果可用)。