目录
RSS 多队列网卡
在以往,一张 NIC 只具有一个 Rx Queue,对应一个 CPU Core 来进行收包处理。在多核时代,为了充分利用 Multi-CPU Cores,NIC 也相应的提供了 Multi-Queue(多队列)功能。
结合 NIC RSS(Receive Side Scaling,接收侧扩展)功能,可以将多个 Rx Queues 通过硬中断绑定到不同的 CPU cores 上处理,以此均衡利用 CPU 资源并提高网络吞吐量。例如:Intel 82599 NIC 有 16 个 Queues,可以分别将每个 Queue 的中断号绑定到 16 个 CPU Cores 上。
此外,有些 NIC 还能够同时支持 Multi-Queue Receive 和 Multi-Queue Transmit。
RSS 技术实现原理
RSS Filter
NIC 通过 HW Filters(过滤器)来分发报文,Filters 首先会将报文分配给某条 Stream(逻辑流),然后将每条 逻辑流 中的报文都被导向不同的 Receive Queues,然后再由不同 CPU Cores 处理。
以 Intel 82599 NIC 为例,有以下 HW Filters 类型:
- L2 filter
- MAC filter
- VLAN filter
- L2 type filter
- Syn filter
- 5-Tuple filter
- Flow dirctor
- RSS
如上图,当报文经过了一系列 Filters,最后再交由 RSS 处理。
RSS HASH
RSS Hash function(e.g. Toeplitz HASH),通过计算 Incoming traffic 中的 Hash type specified(2-3-4-Tuple)得到一个 Hash value,然后再取出 Hash value 中的 LSBs(最低有效位。7bits)去 Lookup Indirection table(RETA,间接寻址表)找到这条 Traffic Flow 对应的 Rx queue。
同时,Hash type specified 和 Indirection table entries 都是可以被 Ethernet driver 或 ethtool CLI 进行编程的。
-
Hash type specified:可以是以下类型。
- IP 2-tuple(srcIP、dstIP)
- TCP/UDP 3-tuple(srcIP、dstIP、dstPort)
- TCP/UDP 4-tuple(srcIP、dstIP、srcPort、dstPort)
-
Indirection table entries:具有 128 个条目,对应 128 个不同的 Queues,还可以设置不同的权重参数。
硬中断信号绑定
为了避免 Multi-Queues 导致的报文乱序问题,以及均衡的发挥多核处理器平台的并行能力,通常会通过硬件中断信号绑定的方式将 Multi-Queues 绑定到相应的 CPU Cores 上,结合 RSS 技术,实现将同一条 Flow 的 Traffic 总是交给相同的 Rx Queue 以及相同的 CPU Core 处理。
Linux Kernel v2.6.21 开始支持多队列网卡特性。在 NIC Driver 初始化流程中,Kernel 获悉 net_device 所支持的 Rx/Tx Queue 得数量。然后结合 CPU Cores 的数量,通过 Sum=Min(NIC Queue, CPU Core) 公式计算得出应该被激活 Sum 个 Queues,并申请 Sum 个 IRQ Numbers(硬中断请求号),分配给激活的每个 Queues。
多队列网卡通常采用 MSI-X(Message Signaled Interrupts X,消息信令中断)中断类型。MSI-X 支持为每个 NIC 分配多个 IRQ Numbers,使得每个 Rx Queues 都具有独立的 IRQ Number,因此可以绑定到不同的 CPU Cores 上。
处理 Rx Queue 硬中断的 CPU Core 也是随后进行处理收包的 CPU Core,如上图所示,当某个 NIC Rx Queue 收到 Frames 时,就触发自己的 IRQ,收到 IRQ 的 CPU Core 就执行 IRQ Number 对应的硬中断处理程序,最终将收包任务下发给该 Core 的 NET_RX_SOFTIRQ 实例处理(每个 Core 都有一个 NET_RX_SOFTIRQ 实例)。
在 NET_RX_SOFTIRQ 中会调用 NAPI 的收包接口,将 Frames 收到具有多个 netdev_queue 的 net_device 结构体中。
查看网卡启用的中断类型,如下图 MSI-X: Enable+。
$ lspci -vvv
可以使用 cat /proc/interrupts 查看 IPQs 的 Queue mappings 关系。
下面截选了 Network interface ens192 在每个 CPU cores 上的 IRQs 和 Queues 关系。可以看见,ens192 在 8 个 Cores 上都有中断处理,这是 IRQ 负载均衡器 irqbalance Daemon 作用的结果,但是这种均衡在高性能应用场景并不是最佳实践。例如在 DPDK 场景中,应该将 Queue 绑定到指定的 Core 上。
$ cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
...
57: 20342 30923 33789 25533 46977 64504 78884 70780 PCI-MSI-edge ens192-rxtx-0
58: 5162 6797 10395 11019 17324 19285 21365 24282 PCI-MSI-edge ens192-rxtx-1
59: 14154 21925 28098 25550 48416 46239 59652 67793 PCI-MSI-edge ens192-rxtx-2
60: 429 836 924 1155 1917 2304 2227 3131 PCI-MSI-edge ens192-rxtx-3
61: 6667 16537 23922 20526 34824 38050 48226 43089 PCI-MSI-edge ens192-rxtx-4
62: 218 617 1149 1235 2559 2551 2098 3710 PCI-MSI-edge ens192-rxtx-5
63: 36892 78273 78853 27126 78559 55956 68976 107141 PCI-MSI-edge ens192-rxtx-6
64: 3027 6627 7506 6994 12081 13225 14441 19625 PCI-MSI-edge ens192-rxtx-7
65: 0 0 0 0 0 0 0 0 PCI-MSI-edge ens192-event-8
...
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
如果希望手动分配,则需要先关闭 irqbalance Daemon。
$ service irqbalance stop
$ echo 01 > /proc/irq/57/smp_affinity
- 2
但需要注意的是,在大部分场景中,irqbalance Daemon 提供的中断分配优化都是可以起到积极作用的。irqbalance 会自动收集系统数据来分析出使用模式,并依据系统负载状况将工作状态调整为以下两种模式:
- Performance mode:irqbalance 会将中断尽可能均匀地分发给各个 CPU 的 Core,以充分提升性能。
- Power-save mode:irqbalance 会将中断处理集中到第一个 CPU,保证其它空闲 CPU 的睡眠时间,降低能耗。
ethtool 操作指令
- 设置使用 TCPv4 4-tuple HASH 计算。
ethtool -n eth0 rx-flow-hash tcp4
- 设置使用 UDPv4 4-tuple HASH 计算。
ethtool -N eth0 rx-flow-hash udp4 sdfn
- 设置 RETA 使用 6 个 Queues 的负载均衡。
ethtool -x eth0
ethtool -X eth0 equal 6
- 2
- 设置开启 Flow director,并将 IPv4 2-tuple 重定向到 Queue0。
ethtool -K eth0 ntuple on
ethtool -N eth0 flow-type ip4 action 0
ethtool -n eth0 flow-type
- 2
- 3
- 设置开启 Flow director,并使用 flexbytes 特性将 TCPv4 dstPort 5001 重定向到 Queue7。
ethtool -K net2 ntuple on
ethtool -N net2 flow-type tcp4 vlan-etype 5001 action 7
ethtool -n eth0 flow-type
- 2
- 3