多PF Netdev¶
目录¶
背景¶
多PF NIC 技术使多路服务器中的多个 CPU 能够通过其自己的专用 PCIe 接口直接连接到网络。可以通过分割两个卡之间的 PCIe 通道的连接线束,或者通过分叉单个卡的 PCIe 插槽来实现。这样可以消除网络流量在插槽之间的内部总线上穿梭,从而显著降低开销和延迟,此外还可以减少 CPU 利用率并提高网络吞吐量。
概述¶
该特性增加了对在 Multi-PF 环境中将同一端口的多个 PF 组合在一个 netdev 实例下的支持。它在 netdev 层实现。较低层实例(如 pci func、sysfs 条目和 devlink)保持分离。通过属于不同 NUMA 插槽的不同设备传递流量可以节省跨 NUMA 流量,并允许从不同 NUMA 运行在同一 netdev 上的应用程序仍然感受到与设备的邻近性,从而提高性能。
mlx5 实现¶
mlx5 中的 Multi-PF 或 Socket-direct 通过将属于同一 NIC 且启用了 socket-direct 属性的 PF 分组在一起来实现,一旦所有 PF 都被探测到,我们就会创建一个单一的 netdev 来代表所有这些 PF,对称地,每当任何 PF 被移除时,我们都会销毁 netdev。
netdev 网络通道在所有设备之间分配,正确的配置会在处理某个应用/CPU 时利用正确的近 NUMA 节点。
我们选择一个 PF 作为主 PF(领导者),它承担着特殊的角色。其他设备(辅助设备)在芯片级别与网络断开连接(设置为静默模式)。在静默模式下,没有南 <-> 北的流量直接流经辅助 PF。它需要领导者 PF 的帮助(东 <-> 西的流量)才能正常工作。所有 Rx/Tx 流量都通过主 PF 路由到/从辅助设备。
目前,我们将支持限制为仅 PF,最多支持两个 PF(插槽)。
通道分配¶
我们在不同的 PF 之间分配通道,以在多个 NUMA 节点上实现本地 NUMA 节点性能。
每个组合通道都针对一个特定的 PF 工作,针对它创建所有其数据路径队列。我们以轮询策略将通道分配给 PF。
Example for 2 PFs and 5 channels:
+--------+--------+
| ch idx | PF idx |
+--------+--------+
| 0 | 0 |
| 1 | 1 |
| 2 | 0 |
| 3 | 1 |
| 4 | 0 |
+--------+--------+
我们更喜欢轮询的原因是,它受通道数量变化的影响较小。无论用户配置多少通道,通道索引和 PF 之间的映射都是固定的。由于通道统计信息在通道关闭后仍然存在,因此每次更改映射都会使累积统计信息更少地代表通道的历史记录。
这是通过在每个通道中使用正确的核心设备实例 (mdev) 来实现的,而不是它们都使用 “priv->mdev” 下的同一个实例。
可观察性¶
PF、irq、napi 和队列之间的关系可以通过 netlink spec 观察到
$ ./tools/net/ynl/pyynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump queue-get --json='{"ifindex": 13}'
[{'id': 0, 'ifindex': 13, 'napi-id': 539, 'type': 'rx'},
{'id': 1, 'ifindex': 13, 'napi-id': 540, 'type': 'rx'},
{'id': 2, 'ifindex': 13, 'napi-id': 541, 'type': 'rx'},
{'id': 3, 'ifindex': 13, 'napi-id': 542, 'type': 'rx'},
{'id': 4, 'ifindex': 13, 'napi-id': 543, 'type': 'rx'},
{'id': 0, 'ifindex': 13, 'napi-id': 539, 'type': 'tx'},
{'id': 1, 'ifindex': 13, 'napi-id': 540, 'type': 'tx'},
{'id': 2, 'ifindex': 13, 'napi-id': 541, 'type': 'tx'},
{'id': 3, 'ifindex': 13, 'napi-id': 542, 'type': 'tx'},
{'id': 4, 'ifindex': 13, 'napi-id': 543, 'type': 'tx'}]
$ ./tools/net/ynl/pyynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump napi-get --json='{"ifindex": 13}'
[{'id': 543, 'ifindex': 13, 'irq': 42},
{'id': 542, 'ifindex': 13, 'irq': 41},
{'id': 541, 'ifindex': 13, 'irq': 40},
{'id': 540, 'ifindex': 13, 'irq': 39},
{'id': 539, 'ifindex': 13, 'irq': 36}]
在这里您可以清楚地观察到我们的通道分配策略
$ ls /proc/irq/{36,39,40,41,42}/mlx5* -d -1
/proc/irq/36/mlx5_comp0@pci:0000:08:00.0
/proc/irq/39/mlx5_comp0@pci:0000:09:00.0
/proc/irq/40/mlx5_comp1@pci:0000:08:00.0
/proc/irq/41/mlx5_comp1@pci:0000:09:00.0
/proc/irq/42/mlx5_comp2@pci:0000:08:00.0
控制¶
辅助 PF 设置为“静默”模式,这意味着它们与网络断开连接。
在 Rx 中,控制表仅属于主 PF,并且它的作用是通过交叉 vhca 控制功能将传入流量分配给其他 PF。仍然保持一个默认的 RSS 表,该表能够指向不同 PF 的接收队列。
在 Tx 中,主 PF 创建一个新的 Tx 流表,该表被辅助设备别名,以便它们可以通过它连接到网络。
此外,我们设置了默认的 XPS 配置,该配置基于 CPU 选择与 CPU 位于同一节点上的 PF 的 SQ。
XPS 默认配置示例
NUMA 节点:2 NUMA 节点 0 CPU:0-11 NUMA 节点 1 CPU:12-23
节点 0 上的 PF0,节点 1 上的 PF1。
/sys/class/net/eth2/queues/tx-0/xps_cpus:000001
/sys/class/net/eth2/queues/tx-1/xps_cpus:001000
/sys/class/net/eth2/queues/tx-2/xps_cpus:000002
/sys/class/net/eth2/queues/tx-3/xps_cpus:002000
/sys/class/net/eth2/queues/tx-4/xps_cpus:000004
/sys/class/net/eth2/queues/tx-5/xps_cpus:004000
/sys/class/net/eth2/queues/tx-6/xps_cpus:000008
/sys/class/net/eth2/queues/tx-7/xps_cpus:008000
/sys/class/net/eth2/queues/tx-8/xps_cpus:000010
/sys/class/net/eth2/queues/tx-9/xps_cpus:010000
/sys/class/net/eth2/queues/tx-10/xps_cpus:000020
/sys/class/net/eth2/queues/tx-11/xps_cpus:020000
/sys/class/net/eth2/queues/tx-12/xps_cpus:000040
/sys/class/net/eth2/queues/tx-13/xps_cpus:040000
/sys/class/net/eth2/queues/tx-14/xps_cpus:000080
/sys/class/net/eth2/queues/tx-15/xps_cpus:080000
/sys/class/net/eth2/queues/tx-16/xps_cpus:000100
/sys/class/net/eth2/queues/tx-17/xps_cpus:100000
/sys/class/net/eth2/queues/tx-18/xps_cpus:000200
/sys/class/net/eth2/queues/tx-19/xps_cpus:200000
/sys/class/net/eth2/queues/tx-20/xps_cpus:000400
/sys/class/net/eth2/queues/tx-21/xps_cpus:400000
/sys/class/net/eth2/queues/tx-22/xps_cpus:000800
/sys/class/net/eth2/queues/tx-23/xps_cpus:800000
互斥特性¶
Multi-PF 的本质是不同的通道与不同的 PF 一起工作,这与在其中一个 PF 中维护状态的有状态特性相冲突。例如,在 TLS 设备卸载功能中,每个连接都会创建特殊的上下文对象并在 PF 中维护。在不同的 RQ/SQ 之间转换会破坏该功能。因此,我们暂时禁用此组合。