← 返回文章

How-To:在 Kubernetes 下安全启用 Switchdev 硬件卸载,解决节点重启问题

介绍 Switchdev 模式核心机制与 Kubernetes SR-IOV 生态,复现 ConnectX-5 因 Dataplane 残留流表在模式切换时触发的节点 Warm Reset 竞态故障,并提供利用 SR-IOV Network Operator 的 Systemd 模式(configurationMode: systemd)固定宿主机启动顺序的完整排障与落地方案。

NetworkingCloud ComputingOS

什么是 Switchdev Mode?

随着智能网卡(SmartNIC)和 DPU 等硬件引入现代数据中心的基础设施中,我们可以利用 Switchdev 模式将数据面的流量处理直接卸载到网卡硬件上。

Switchdev mode turns a network card’s physical port into a smart software-controlled virtual switch (called an e-switch) to offload traffic processing directly to hardware.

  • Core Function:它允许网络适配器上的物理功能(PF)将虚拟功能(VF)和可扩展子功能(SF)作为独立的虚拟交换机端口(vport)来管理。
  • Port Representors:Linux 内核会为每个 VF/SF 创建本地 netdev“代表端口”(Representor),充当未命中硬件流表报文的慢速通道(Slow Path),也可直接挂入 Linux Bridge、OVS 或配置 TC Filter。注意:Representor 仅在 Switchdev 模式下存在。
  • Hardware Offloading:将报文 Steering、Bridging、安全策略和隧道封装/解封装(Geneve/VXLAN)从主机 CPU 直接移到网卡 ASIC 芯片处理。
  • Legacy vs. Switchdev:Legacy 模式依赖传统的宿主机 MAC/VLAN 过滤,而 Switchdev 模式支持高级的硬件加速和 Match-Action 流表卸载,能带来更低延迟、更高 PPS 并大幅降低 CPU 开销。

Kubernetes 下的 SR-IOV 生态

Kubernetes 提供了 SR-IOV Device Plugin 扩展接口让我们发现和暴露 SR-IOV 资源,特别是配合 SR-IOV CNI、ovn-kubernetes CNI 或者其他能够使用 SR-IOV netdevice 的 CNI,我们可以直接把 VF/SF 接入到 Kubernetes Workloads(Pod)中。

既然要在集群中使用这些能力,自然而然我们会选择使用 SR-IOV Network Operator。它在集群中负责声明式地管理底层硬件资源:自动创建/配置 VF、绑定驱动、配置 MTU,以及通过 devlink 把网卡切换为 Switchdev 模式,省去逐台机器手动配置的麻烦。


遇到的问题:节点无限重启

我们在配置过程中遇到了一个典型的幽灵故障:集群里两台硬件与配置完全相同的机器,其中一台工作正常,而另一台却陷入了无限重启(Warm Reset)——每次开机进系统后不久就直接崩溃重置。

为了定位问题:

  1. 我们先想办法 Disable / 暂停了节点上的 SR-IOV Network Operator;
  2. 随后在宿主机上手动执行命令复现切换流程;
  3. 最终收敛出根因:在 ConnectX-5(CX-5)上,如果 PF 上此前已经配置了 Dataplane(例如 OVS/OVN 已下发了流表),此时只要尝试把网卡模式从 Legacy 切到 Switchdev,CX-5 驱动在清理旧对象时就会触发异常,导致系统必定 Warm Reset。

这也完美解释了为什么另一台相同配置的机器安然无恙:纯粹是因为启动竞态(Race Condition)。在正常的那台机器上,恰好是 SR-IOV Network Operator 的 Daemon 先启动并完成了硬件切换;而在出问题的机器上,容器化的 OVS/Dataplane 抢先启动并在 PF 上写了流表,随后 Operator 再切模式就直接引爆了内核崩溃。

由于 SR-IOV Network Operator 默认是以容器化的 DaemonSet(Workload)形式在运行时配置硬件的,而 Kubernetes 最终一致性模型无法严格保证各 Workload 的启动顺序,这种硬件切换的风险随时可能在下一次重启时爆发。


解决方案:利用 Systemd 保证硬件先就绪

解决思路非常简单明了:确保在任何 Dataplane 启动和下发流表之前,SR-IOV 和 Switchdev 模式就已经在宿主机上配置完毕。

我们只需要将 SR-IOV Network Operator 的工作模式切换为 systemd。

1. 配置 Operator 启用 Systemd 模式

在 Operator 的 Helm Values 或 SriovOperatorConfig 配置中指定 configurationMode: systemd:

sriovOperatorConfig:
  deploy: true
  configurationMode: systemd
  disableDrain: false

在此模式下,Operator 会向宿主机注入两个 One-Shot Systemd 单元(sriov-config.service 与 sriov-config-post-network.service),将硬件初始化直接挂载到系统的启动流程中。

2. 确定性的启动顺序

宿主机的启动顺序被严格限定为:

sriov-config.service (创建 VF、切 switchdev 模式)
  └── sriov-config-post-network.service (硬件就绪校验)
        └── kubelet.service (Kubelet 启动)
              └── ovs-node / ovnkube-node (拉起 Dataplane 容器下发流表)

由于 kubelet 必须等待 SR-IOV Systemd 单元执行成功后才会拉起,保证了 OVS 启动时看到的永远是已经切好 Switchdev 的干净硬件状态,彻底规避了切换时的 Warm Reset。


验证与检查

配置完成后,可以在节点上通过以下命令进行验证:

# 1. 检查 SR-IOV 启动单元是否正常执行完毕(退出状态码应为 0)
systemctl show --property=ExecMainStatus --value sriov-config.service
systemctl show --property=ExecMainStatus --value sriov-config-post-network.service

# 2. 检查 Operator 宿主机同步结果
cat /etc/sriov-operator/sriov-interface-result.yaml
# 期望输出: syncStatus: Succeeded

# 3. 验证 e-switch 模式与 VF 数量
devlink dev eswitch show pci/<PCI_BDF>
# 期望输出包含: mode switchdev
cat /sys/class/net/<PF_NAME>/device/sriov_numvfs

# 4. 业务流量发起后,验证硬件流表是否成功 Offload
ovs-appctl dpctl/dump-flows -m | grep "offloaded:yes, dp:tc"