mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
5425 字
16 分钟
SmartNIC 与 DPU
2025-06-29

2021 年,某大型云厂商开始在每台服务器的 SmartNIC 上卸载 OVS 流表匹配,服务器 CPU 占用从 30% 降到 5%,多出的计算资源直接变成收入。SmartNIC 和 DPU 正在重新定义数据中心的计算边界。

一、引言:SmartNIC 与 DPU——从软件定义到硬件可编程#

第 10 章:RDMA 与远程直接内存访问中,我们看到 RNIC 硬件如何将传输协议从 CPU 卸载到网卡——远端 CPU 完全不参与数据搬运,延迟从数十微秒降到个位数微秒。但 RDMA 解决的是”传输层卸载”,而数据中心里还有大量工作仍然消耗着宝贵的 CPU 周期:OVS 流表匹配、VXLAN 封装/解封装、ACL 规则过滤、IPsec 加解密、QoS 流量整形……

当软件旁通(DPDK、XDP)已经把单核吞吐推到极限,当 CPU 核心数无法再线性增长,当云厂商发现 30% 的 CPU 时间花在虚拟网络开销上——硬件卸载(Hardware Offload)成为下一个必然的选择。

SmartNIC(智能网卡)和 DPU(Data Processing Unit,数据处理器)正是这一趋势的产物:它们把网络、存储、安全等基础设施任务从主机 CPU 卸载到网卡上的专用处理器,让 CPU 回归业务计算的本质。本章将深入 SmartNIC 与 DPU 的架构、OVS 硬件卸载的完整流程、P4 可编程数据平面入门,以及动手实践。

一、硬件卸载:为什么把工作交给网卡#

CPU 贵,ASIC 便宜#

在数据中心中,CPU 是最昂贵的资源之一。一颗高端 Xeon 处理器价格数千美元,而一颗网络 ASIC 芯片的成本可能只有其十分之一。更关键的是性能差距

操作CPU(软件)ASIC/FPGA(硬件)加速比
流表匹配(5 元组)~200 ns/条~10 ns/条20×
VXLAN 封装~500 ns~20 ns25×
AES-GCM 256 加密~3 μs/1KB~50 ns/1KB60×
CRC32 校验~100 ns~5 ns20×
TCP 校验和~50 ns~2 ns25×
Note

以上数据为典型量级,实际性能取决于具体硬件实现和配置。核心结论不变:对于固定模式的重复计算,专用硬件比通用 CPU 快一个数量级以上,且功耗更低。

卸载目标:哪些工作适合交给网卡#

并非所有工作都适合硬件卸载。适合卸载的任务具有以下特征:

  1. 流匹配(Flow Matching):OVS/OpenFlow 的 5 元组或更复杂的匹配规则,硬件 TCAM 可以在单时钟周期内完成查找
  2. 包修改(Packet Modification):VXLAN 封装/解封装、VLAN 标签插入/剥离、NAT 地址改写——都是固定偏移的字段替换
  3. 加密/解密(Crypto):IPsec TLS 的对称加密/解密,硬件加密引擎吞吐量可达 100 Gbps+
  4. TCP 处理(TCP Offload):TCP 校验和计算、分段/重组、TSO/LRO——传统网卡已支持
  5. 流量整形(QoS/Shaping):令牌桶、限速、优先级队列——硬件可以精确到纳秒级调度
  6. 计量与统计(Metering/Counting):每流字节数/包数统计,硬件计数器零 CPU 开销

不适合卸载的任务:

  • 复杂控制逻辑:路由协议(BGP/OSPF)计算、编排决策
  • 需要大量内存的操作:深度包检测(DPI)的规则库可能超过片上 SRAM 容量
  • 频繁变化的策略:硬件规则更新有延迟,不适合秒级变化的策略

软件路径 vs 硬件路径#

graph TB subgraph 软件路径["软件路径(传统 OVS)"] direction TB PKT_S["数据包到达"] --> IRQ["硬中断"] IRQ --> SOFTIRQ["软中断 net_rx"] SOFTIRQ --> OVS_DP["OVS 内核数据路径<br>流表匹配"] OVS_DP -->|命中| ACT_S["执行动作<br>CPU 处理"] OVS_DP -->|未命中| UPCALL["upcall 到用户态<br>ovs-vswitchd"] UPCALL --> FLOW_SET["计算流表<br>安装内核规则"] FLOW_SET --> ACT_S ACT_S --> OUT_S["发送"] end subgraph 硬件路径["硬件路径(SmartNIC 卸载)"] direction TB PKT_H["数据包到达"] --> ASIC["SmartNIC ASIC<br>硬件流表匹配"] ASIC -->|命中| ACT_H["硬件执行动作<br>封装/转发/加密"] ASIC -->|未命中| MISS["上送主机<br>软件处理"] MISS --> SW_RULE["软件计算流表"] SW_RULE --> HW_RULE["安装硬件规则"] HW_RULE -.->|"后续包命中"| ASIC ACT_H --> OUT_H["发送"] end style 软件路径 fill:#fff3e0,stroke:#e65100 style 硬件路径 fill:#e8f5e9,stroke:#2e7d32

关键差异在于:软件路径中每个包都需要 CPU 参与匹配和动作执行;硬件路径中,命中硬件规则的包完全不需要 CPU 参与,只有未命中的首包需要上送主机计算规则。

Tip

硬件卸载的核心收益不是”加速单个包的处理”,而是”让 CPU 完全不参与已卸载流的处理”。当 99% 的流量命中硬件规则时,CPU 可以从网络 I/O 中彻底解放出来。

二、SmartNIC 架构#

SmartNIC(Smart Network Interface Card)是在传统网卡基础上增加了可编程处理能力的网络适配器。根据可编程程度,SmartNIC 可以分为三类架构。

固定功能 ASIC(Fixed-Function ASIC)#

代表产品:NVIDIA/Mellanox ConnectX 系列(ConnectX-5/6/7)

这类 SmartNIC 内部是硬连线的 ASIC 逻辑,提供预定义的硬件卸载功能:

  • RoCE/RDMA 卸载:硬件实现可靠传输协议
  • OVS 硬件卸载:通过 ASAP²(Accelerated Switching and Packet Processing)支持
  • VXLAN 封装/解封装:硬件隧道引擎
  • IPsec 加密:硬件加密引擎
  • TCP 拥塞控制:硬件 TSO/LRO
┌──────────────────────────────────────────┐
│ ConnectX-7 ASIC │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ │
│ │ MAC/PHY │→│ Parser │→│ Match │ │
│ │ (100G) │ │ 解析器 │ │ Action │ │
│ └─────────┘ └──────────┘ │ Engine │ │
│ │ 匹配动作 │ │
│ ┌─────────┐ ┌──────────┐ └──────────┘ │
│ │ Crypto │ │ Tunnel │ │
│ │ Engine │ │ Engine │ │
│ │ 加密引擎│ │ 隧道引擎 │ │
│ └─────────┘ └──────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ PCIe 5.0 x16 │ │
│ └─────────────────────────────────────┘ │
└──────────────────────────────────────────┘

优点:性能极致(线速处理)、功耗低、成熟稳定 缺点:功能固定,无法添加新协议或自定义逻辑;新功能需要等芯片迭代

可编程 FPGA/NPU(Programmable FPGA/NPU)#

代表产品:Netronome Agilio CX、Xilinx Alveo

这类 SmartNIC 使用 FPGA 或 NPU(Network Processing Unit) 作为包处理引擎,开发者可以编写自定义逻辑:

  • FPGA:通过 Verilog/VHDL 或 HLS(High-Level Synthesis)编程,完全自定义数据平面
  • NPU:通过微码(microcode)编程,具有大量并行处理核心(Microengine)
┌──────────────────────────────────────────┐
│ FPGA SmartNIC │
│ ┌─────────┐ ┌──────────────────────┐ │
│ │ MAC/PHY │→│ FPGA Fabric │ │
│ │ (100G) │ │ ┌────┐ ┌────┐ │ │
│ └─────────┘ │ │ME 0│ │ME 1│ ... │ │
│ │ └────┘ └────┘ │ │
│ ┌─────────┐ │ ┌──────────────┐ │ │
│ │ DDR4 │ │ │ Custom Logic │ │ │
│ │ Memory │←→│ 自定义逻辑 │ │ │
│ └─────────┘ │ └──────────────┘ │ │
│ └──────────────────────┘ │
│ ┌─────────────────────────────────────┐│
│ │ PCIe 4.0 x16 ││
│ └─────────────────────────────────────┘│
└──────────────────────────────────────────┘

优点:完全可编程,可以添加新协议、自定义匹配动作 缺点:FPGA 开发门槛高(需要硬件描述语言经验)、编译时间长(数小时)、功耗较高

混合架构:ASIC + CPU(Hybrid ASIC+CPU)#

代表产品:NVIDIA BlueField 系列、AMD Pensando

这是当前最主流的 SmartNIC/DPU 架构——在 ASIC 包处理引擎旁边放置一个通用 CPU 子系统,形成”快速路径 + 慢速路径”的分工:

  • ASIC 快速路径:处理已知的、高频的包处理逻辑(流表匹配、封装、加密)
  • CPU 慢速路径:处理控制面逻辑、异常包、新协议的首次迭代
┌──────────────────────────────────────────────────┐
│ Hybrid SmartNIC / DPU │
│ │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ ASIC 快速路径 │ │ ARM CPU 子系统 │ │
│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │
│ │ │ Parser │ │ │ │ Linux OS │ │ │
│ │ │ Match-Action │ │ │ │ OVS / 控制面 │ │ │
│ │ │ Tunnel/Crypto│ │ │ │ 管理代理 │ │ │
│ │ └──────────────┘ │ │ └──────────────┘ │ │
│ │ │ │ │ │
│ └────────┬───────────┘ └──────────┬─────────┘ │
│ │ 内部高速互连 │ │
│ └────────────┬────────────┘ │
│ │ │
│ ┌─────────────────────┴──────────────────────┐ │
│ │ MAC/PHY (100G / 200G) │ │
│ └────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────┐ │
│ │ PCIe 4.0/5.0 x16 │ │
│ └────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘

优点:兼顾性能与可编程性,ASIC 处理快速路径、CPU 处理慢速路径 缺点:芯片面积大、功耗较高、成本高于纯 ASIC 方案

三种架构对比#

graph LR subgraph 固定功能["固定功能 ASIC<br>ConnectX 系列"] A1["硬连线逻辑"] --> A2["预定义功能"] A2 --> A3["线速性能"] end subgraph 可编程["可编程 FPGA/NPU<br>Netronome / Xilinx"] B1["可编程逻辑"] --> B2["自定义功能"] B2 --> B3["灵活但复杂"] end subgraph 混合架构["混合 ASIC+CPU<br>BlueField / Pensando"] C1["ASIC 快速路径"] --> C3["性能 + 灵活性"] C2["CPU 慢速路径"] --> C3 end 固定功能 -.->|"增加可编程性"| 可编程 可编程 -.->|"降低开发门槛"| 混合架构 固定功能 -.->|"增加 CPU"| 混合架构 style 固定功能 fill:#e3f2fd,stroke:#1565c0 style 可编程 fill:#fff3e0,stroke:#e65100 style 混合架构 fill:#e8f5e9,stroke:#2e7d32
特性固定功能 ASIC可编程 FPGA/NPU混合 ASIC+CPU
性能5/54/55/5
可编程性1/55/54/5
开发门槛1/5(无需编程)5/5(HDL/微码)3/5(软件为主)
功耗2/5(低)4/5(高)3/5(中等)
成本2/5(低)4/5(高)3/5(中等)
功能迭代速度慢(芯片周期)中(FPGA 重编程)快(软件更新)

三、DPU:数据处理器#

DPU(Data Processing Unit)是 SmartNIC 的演进形态。如果说 SmartNIC 是”网卡 + 一些卸载能力”,那么 DPU 就是”网卡 + CPU + 加速器”——它本质上是一台运行独立操作系统的嵌入式服务器,专门处理基础设施任务(网络、存储、安全),让主机 CPU 专注于业务计算。

NVIDIA BlueField#

NVIDIA BlueField 是目前市场份额最大的 DPU 产品,已经迭代到第三代:

BlueField-2#

  • ARM 核心:8 个 Cortex-A72 核心,运行 Linux(Ubuntu/RHEL)
  • 网络:集成 ConnectX-6 Dx 网络控制器,支持 25/50/100 Gbps
  • 加速器:加密引擎、正则表达式匹配引擎、数据压缩引擎
  • 内存:8/16 GB DDR4
  • 存储:支持 NVMe SNAP(NVMe over Fabric 硬件卸载)

BlueField-3#

  • ARM 核心:16 个 Cortex-A78 核心,性能提升 3×
  • 网络:集成 ConnectX-7 网络控制器,支持 200/400 Gbps
  • 加速器:增强加密引擎、VirtIO 硬件卸载、OVS ASAP² 升级
  • 内存:16/32 GB DDR5
  • PCIe:PCIe 5.0 x16,支持 NVMe 直接访问

BlueField 架构框图#

graph TB subgraph BlueField_DPU["BlueField DPU 架构"] direction TB subgraph ARM_Sub["ARM 子系统"] ARM_CORE["ARM Cortex-A78 ×16<br>运行 Linux"] ARM_MEM["DDR5 16/32 GB"] ARM_CORE --- ARM_MEM end subgraph Net_Sub["网络子系统(ConnectX-7)"] PARSER["Parser<br>包解析"] MATCH["Match-Action Engine<br>流表匹配"] TUNNEL["Tunnel Engine<br>VXLAN/Geneve"] CRYPTO["Crypto Engine<br>IPsec/TLS"] PARSER --> MATCH --> TUNNEL MATCH --> CRYPTO end subgraph Accel["加速器"] REGEX["RegEx Engine<br>正则匹配"] COMP["Compression<br>数据压缩"] VIRTIO["VirtIO Offload<br>虚拟化卸载"] end ARM_Sub <-->|"内部互连<br>(NVLink / PCIe)"| Net_Sub ARM_Sub <-->|"内部互连"| Accel Net_Sub <-->|"数据路径"| Accel end HOST["主机 CPU<br>(Xeon / EPYC)"] <-->|"PCIe 5.0 x16"| BlueField_DPU NET["网络<br>100G / 200G / 400G"] <-->|"MAC/PHY"| BlueField_DPU style BlueField_DPU fill:#76b900,stroke:#2e7d32,color:#fff style HOST fill:#e3f2fd,stroke:#1565c0 style NET fill:#fff3e0,stroke:#e65100

AMD Pensando#

AMD Pensando DPU 采用P4 可编程 ASIC + ARM CPU 的架构,其核心差异化在于 P4 可编程数据平面:

  • P4 ASIC:数据平面完全由 P4 程序定义,支持自定义解析器、匹配动作表
  • ARM 核心:6 个 Cortex-A72 核心,运行 Pensando OS
  • 性能:100/200 Gbps,支持 100M+ 并发流表
  • 特性:硬件 P4 可编程、分布式防火墙、加密、负载均衡

Pensando 的 P4 可编程性意味着:当新协议出现(如新的隧道封装格式),你可以编写 P4 程序定义新的解析和转发逻辑,无需等待芯片迭代。这是与 BlueField 固定功能 ASIC 的关键区别。

Intel IPU(Infrastructure Processing Unit)#

Intel 的 IPU 走了一条不同的路线——FPGA + Xeon 的组合:

  • FPGA 数据平面:可编程包处理逻辑,支持自定义协议
  • Xeon CPU:运行 Linux,处理控制面和管理任务
  • 产品线:Intel IPU E2100(FPGA + Xeon-D)、IPU C5000(FPGA + Xeon)
  • 差异化:FPGA 提供比 ASIC 更灵活的可编程性,Xeon 提供比 ARM 更强的控制面性能

DPU 产品矩阵对比#

特性NVIDIA BlueField-3AMD Pensando DPUIntel IPU C5000
数据平面ConnectX-7 ASICP4 可编程 ASICFPGA
控制面 CPUARM Cortex-A78 ×16ARM Cortex-A72 ×6Intel Xeon-D
网络带宽200/400 Gbps100/200 Gbps100/200 Gbps
可编程模型ASAP²(固定功能 + 规则)P4(完全可编程)Verilog/HLS(FPGA)
加密引擎AES-GCM 硬件AES-GCM 硬件AES-GCM 硬件
内存DDR5 16/32 GBDDR4 8/16 GBDDR4 16/32 GB
虚拟化卸载VirtIO SNAPVirtIOVirtIO
生态成熟度5/54/53/5
典型场景云网络、存储、安全云防火墙、负载均衡电信、5G UPF
Note

三家 DPU 的核心差异在于数据平面的可编程模型:BlueField 使用固定功能 ASIC + 规则配置,Pensando 使用 P4 可编程 ASIC,Intel IPU 使用 FPGA。选择哪种取决于你的场景——如果只需要标准协议的硬件卸载,BlueField 最成熟;如果需要自定义协议,Pensando 的 P4 最灵活;如果需要极致的自定义能力,Intel IPU 的 FPGA 最强大。

DPU 的核心价值:释放主机 CPU#

DPU 的商业价值可以用一个简单的公式概括:

DPU 收益 = 释放的 CPU 核心数 × 单核成本 - DPU 成本

在典型的云环境中:

  • OVS 转发消耗 2-4 个 CPU 核心(每台主机)
  • IPsec 加密消耗 2-8 个 CPU 核心(取决于带宽)
  • 存储虚拟化消耗 2-4 个 CPU 核心
  • 总计:6-16 个 CPU 核心用于基础设施开销

一台 64 核服务器的 10%-25% CPU 资源花在”非业务计算”上。DPU 将这些任务卸载后,主机 CPU 可以全部用于租户虚拟机/容器,直接提升业务收入。

四、OVS 硬件卸载#

OVS(Open vSwitch)是云数据中心虚拟网络的核心组件,也是硬件卸载最重要的应用场景。本节深入 OVS 硬件卸载的完整流程。

卸载模型:tc / rte_flow / ASAP²#

OVS 硬件卸载有三种主要接口:

接口层级适用场景代表产品
tc(traffic control)Linux 内核内核 OVS + SmartNICConnectX、Broadcom
rte_flowDPDKOVS-DPDK + SmartNICConnectX、Netronome
ASAP²Mellanox 私有ConnectX/BlueField 专用NVIDIA/Mellanox

tc 卸载的工作原理:

  1. OVS 内核数据路径将流表规则转换为 tc 规则
  2. tc 规则通过 flower 分类器下发到网卡驱动
  3. 网卡驱动将 tc 规则转换为硬件流表规则(通过 devlink 或厂商私有接口)
  4. 后续包在硬件中匹配并执行动作

rte_flow 卸载的工作原理:

  1. OVS-DPDK 用户态数据路径将流表规则转换为 rte_flow 规则
  2. 通过 DPDK PMD 驱动下发到网卡硬件
  3. 硬件直接匹配和执行

ASAP²(Accelerated Switching and Packet Processing)是 NVIDIA/Mellanox 的专有卸载框架,在 tc/rte_flow 之上提供了更高效的规则管理和更丰富的卸载能力。

卸载流程:miss → 软件 → 安装硬件规则 → hit → 硬件#

OVS 硬件卸载的核心是一个慢速路径到快速路径的迁移过程

sequenceDiagram participant PKT as 数据包 participant NIC as SmartNIC participant OVS_K as OVS 内核 participant OVS_D as ovs-vswitchd Note over PKT,NIC: 阶段1:首包(miss) PKT->>NIC: 到达网卡 NIC->>NIC: 硬件流表查找 NIC-->>NIC: 未命中(miss) NIC->>OVS_K: 上送主机 OVS_K->>OVS_K: 内核流表查找 OVS_K-->>OVS_K: 未命中 OVS_K->>OVS_D: upcall OVS_D->>OVS_D: 计算新流表规则 Note over OVS_D,NIC: 阶段2:安装硬件规则 OVS_D->>OVS_K: 下发流表规则 OVS_K->>OVS_K: 安装内核规则 OVS_K->>NIC: 转换为 tc/rte_flow<br>下发硬件规则 NIC->>NIC: 写入硬件流表 Note over PKT,NIC: 阶段3:后续包(hit) PKT->>NIC: 同流后续包到达 NIC->>NIC: 硬件流表查找 NIC->>NIC: 命中(hit) NIC->>NIC: 硬件执行动作<br>(转发/封装/加密) NIC->>PKT: 直接发送 Note over NIC: CPU 完全不参与!

这个流程的关键点:

  1. 首包必须上送主机:硬件无法自行计算新流表规则,必须由 ovs-vswitchd 决定
  2. 规则安装有延迟:从首包到硬件规则生效,需要经过 upcall → 用户态处理 → 内核规则 → 硬件规则的完整链路,典型延迟 100μs-1ms
  3. 后续包零 CPU 开销:一旦硬件规则生效,同流的所有后续包完全在硬件中处理

OVS 硬件卸载配置#

启用 tc 卸载(内核 OVS)#

# 1. 启用网卡的 hw-tc-offload
ethtool -K <interface> hw-tc-offload on
# 2. 启用 OVS 硬件卸载
ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
# 3. 重启 OVS
systemctl restart openvswitch-switch
# 4. 验证硬件卸载已启用
ovs-vsctl get Open_vSwitch . other_config:hw-offload
# 输出: "true"
# 5. 查看硬件卸载的流表规则
ovs-dpctl dump-flows -m type=tc

启用 rte_flow 卸载(OVS-DPDK)#

# 1. 在 OVS-DPDK 配置中启用硬件卸载
ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
ovs-vsctl set Open_vSwitch . other_config:tc-policy=skip_sw
# skip_sw: 尽可能将规则安装到硬件,跳过软件规则
# 2. 重启 OVS
systemctl restart openvswitch-switch
# 3. 创建 DPDK 端口时指定 pf socket
ovs-vsctl add-port br0 dpdk0 \
-- set Interface dpdk0 type=dpdk \
options:dpdk-devargs=0000:3b:00.0
# 4. 查看卸载状态
ovs-appctl dpctl/dump-flows -m type=offloaded

tc 命令详解#

tc(traffic control)是 Linux 内核的流量控制子系统,也是 OVS 硬件卸载的核心接口。理解 tc 命令对调试硬件卸载至关重要:

# 查看网卡上的 tc 规则(包括硬件卸载的规则)
tc filter show dev <interface> root
# 查看 ingress 方向的 tc 规则
tc filter show dev <interface> ingress
# 手动添加一条 tc 硬件卸载规则
# 匹配:源 IP 10.0.0.1,目的端口 80
# 动作:转发到端口 2
tc filter add dev <interface> protocol ip parent ffff: \
flower \
src_ip 10.0.0.1 \
dst_port 80 \
ip_proto tcp \
action mirred egress redirect dev <interface2> \
hw_offload 1
# 查看硬件卸载规则的统计
tc -s filter show dev <interface> root
# 删除所有 tc 规则
tc qdisc del dev <interface> clsact
# 查看网卡支持的 tc 卸载能力
ethtool -k <interface> | grep hw-tc-offload
Warning

tc flower 规则的语法与 OVS 流表规则不完全对应。OVS 在内部将流表规则转换为 tc flower 格式,某些复杂动作(如多级封装)可能无法直接卸载。使用 ovs-dpctl dump-flows -m 查看规则时,注意 offloaded:yes 标记确认规则已成功卸载到硬件。

卸载规则优先级与限制#

硬件流表有容量限制,当规则数超过硬件 TCAM 容量时,需要合理的优先级策略:

# 查看硬件流表容量(以 ConnectX 为例)
devlink dev param show pci/0000:3b:00.0 name acl_max
# 设置 OVS 卸载优先级策略
ovs-vsctl set Open_vSwitch . other_config:tc-policy=skip_hw
# skip_hw: 优先软件规则,硬件规则作为加速
# skip_sw: 优先硬件规则,软件规则不安装
# none: 两者都安装(默认)
tc-policy行为适用场景
none软件 + 硬件都安装规则调试阶段
skip_hw优先软件,硬件失败不报错规则数超过硬件容量
skip_sw优先硬件,硬件失败则丢弃追求极致性能

五、P4 编程入门#

P4(Programming Protocol-Independent Packet Processors)是一种数据平面编程语言,它允许你定义数据包的解析方式、匹配动作表的逻辑,以及包的修改和转发行为。P4 是 SmartNIC/DPU 可编程性的核心——理解 P4,就理解了现代可编程数据平面的设计哲学。

P4 架构模型#

P4 的核心架构由四个组件组成:

graph LR subgraph P4架构["P4 程序结构"] HDR["Headers<br>头部定义"] --> PARSER["Parser<br>解析器"] PARSER --> MA["Match-Action Tables<br>匹配动作表"] MA --> MA2["Match-Action Tables<br>(可多级串联)"] MA2 --> DEPARSER["Deparser<br>重组器"] DEPARSER --> OUT["输出"] end subgraph 外部交互["与控制面交互"] CTRL["控制面<br>(CPU / SDN 控制器)"] -->|"下发规则"| MA CTRL -->|"下发规则"| MA2 end style P4架构 fill:#e8f5e9,stroke:#2e7d32 style 外部交互 fill:#e3f2fd,stroke:#1565c0
  1. Headers(头部定义):定义数据包的头部格式——每个字段的名称、位宽、顺序
  2. Parser(解析器):状态机,逐层解析数据包头部,提取匹配所需的字段
  3. Match-Action Tables(匹配动作表):核心处理逻辑——根据字段值匹配,执行对应动作
  4. Deparser(重组器):将修改后的头部重新组装成数据包输出
Note

P4 只定义数据平面(Data Plane)的行为——“如何处理包”。控制平面(Control Plane)——“往表里填什么规则”——由外部控制器(CPU/SDN 控制器)通过 P4Runtime API 下发。这种分离是 P4 设计哲学的核心。

P4₁₆ 基础语法#

P4₁₆ 是 P4 语言的当前版本(2016 年发布),相比 P4₁₄ 增加了类型系统、抽象架构模型等特性。以下是一个完整的 P4₁₆ 程序骨架:

// ============================================
// P4₁₆ 程序骨架
// ============================================
// 1. 包含核心库
#include <core.p4>
#include <v1model.p4>
// 2. 定义头部格式
header ethernet_t {
bit<48> dstAddr;
bit<48> srcAddr;
bit<16> etherType;
}
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
bit<32> srcAddr;
bit<32> dstAddr;
}
// 3. 定义元数据结构
struct metadata_t {
bit<16> ingress_port;
bit<16> egress_port;
}
// 4. 定义头部集合
struct headers_t {
ethernet_t ethernet;
ipv4_t ipv4;
}
// 5. 定义解析器(Parser)
parser MyParser(packet_in packet,
out headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t std_meta) {
state start {
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
0x0800: parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
// 6. 定义动作(Action)
action forward(bit<9> port) {
std_meta.egress_spec = port;
}
action drop() {
mark_to_drop(std_meta);
}
action set_dst_mac(bit<48> mac) {
hdr.ethernet.dstAddr = mac;
}
// 7. 定义匹配动作表(Table)
table ipv4_lpm_table {
key = {
hdr.ipv4.dstAddr: lpm; // 最长前缀匹配
}
actions = {
forward;
drop;
set_dst_mac;
}
size = 1024;
default_action = drop;
}
// 8. 定义控制流(Apply)
control MyIngress(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t std_meta) {
apply {
ipv4_lpm_table.apply();
}
}
// 9. 定义重组器(Deparser)
control MyDeparser(packet_out packet,
in headers_t hdr) {
apply {
packet.emit(hdr.ethernet);
packet.emit(hdr.ipv4);
}
}
// 10. 实例化架构(V1Model)
V1Switch(MyParser(), MyIngress(), MyIngress(), MyDeparser()) main;

P4 关键概念详解#

匹配类型#

P4 支持多种匹配类型,对应不同的硬件实现:

匹配类型语法硬件实现适用场景
精确匹配exact哈希表MAC 地址、VLAN ID
最长前缀匹配lpmTCAM / LPM 树IP 路由
三元匹配ternaryTCAMACL 规则(带掩码)
范围匹配rangeTCAM端口范围

动作(Action)#

P4 的动作是原子操作——要么全部执行,要么不执行。动作可以包含:

  • 修改头部字段hdr.ipv4.ttl = hdr.ipv4.ttl - 1
  • 添加/删除头部hdr.ipv4.setInvalid()
  • 设置输出端口std_meta.egress_spec = port
  • 标记丢弃mark_to_drop(std_meta)

控制流#

P4 的控制流通过 apply 块定义,支持条件分支和表串联:

apply {
if (hdr.ipv4.isValid()) {
switch (ipv4_lpm_table.apply().action_run) {
forward: {
// 转发成功,继续处理
}
drop: {
// 丢弃
}
}
}
}

P4 + SmartNIC 实践#

P4 程序需要编译为特定硬件的目标代码。不同 SmartNIC 有不同的编译后端:

SmartNICP4 编译器目标格式
AMD PensandoP4 Capri CompilerCapri ASIC 微码
Intel IPUP4 Studio / P4SFPGA bitstream
NVIDIA BlueField不直接支持 P4使用 ASAP² 规则配置
Warning

NVIDIA BlueField 的 ConnectX ASIC 不直接支持 P4 编程。BlueField 的数据平面通过 ASAP² 框架配置固定功能的匹配动作规则,而不是通过 P4 程序定义。如果你需要 P4 可编程性,应选择 AMD Pensando 或 Intel IPU。

完整示例:L2 转发的 P4 程序#

以下是一个完整的 L2 MAC 转发 P4 程序,包含 MAC 学习表和转发逻辑:

#include <core.p4>
#include <v1model.p4>
// ============================================
// L2 MAC 转发 P4 程序
// ============================================
header ethernet_t {
bit<48> dstAddr;
bit<48> srcAddr;
bit<16> etherType;
}
struct metadata_t {
bit<16> ingress_port;
}
struct headers_t {
ethernet_t ethernet;
}
// ---- Parser ----
parser L2Parser(packet_in packet,
out headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t std_meta) {
state start {
packet.extract(hdr.ethernet);
meta.ingress_port = std_meta.ingress_port;
transition accept;
}
}
// ---- Actions ----
// 转发到指定端口
action forward(bit<9> egress_port) {
std_meta.egress_spec = egress_port;
}
// 丢弃
action drop() {
mark_to_drop(std_meta);
}
// 学习源 MAC 地址(控制面通过 clone 完成)
action learn_src_mac() {
// 触发 CPU 学习源 MAC → ingress_port 映射
// 实际由控制面完成
clone3(CloneType.I2E, 0, meta);
}
// ---- Tables ----
// 目的 MAC 查找表(精确匹配)
table dst_mac_table {
key = {
hdr.ethernet.dstAddr: exact;
}
actions = {
forward;
drop;
}
size = 4096; // 支持 4K MAC 条目
default_action = drop;
}
// ---- Ingress Control ----
control L2Ingress(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t std_meta) {
apply {
// 1. 学习源 MAC(首包触发 CPU 学习)
learn_src_mac();
// 2. 查找目的 MAC 转发表
dst_mac_table.apply();
}
}
// ---- Egress Control ----
control L2Egress(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t std_meta) {
apply {
// L2 转发不需要额外 egress 处理
}
}
// ---- Deparser ----
control L2Deparser(packet_out packet,
in headers_t hdr) {
apply {
packet.emit(hdr.ethernet);
}
}
// ---- Instantiation ----
V1Switch(L2Parser(), L2Ingress(), L2Egress(), L2Deparser()) main;

控制面通过 P4Runtime API 下发 MAC 转发表规则:

# 使用 P4Runtime 客户端下发规则示例
import p4runtime_pb2 as p4rt
# 添加一条 MAC 转发规则:dst MAC aa:bb:cc:dd:ee:ff → 端口 3
entry = p4rt.TableEntry()
entry.table_id = dst_mac_table_id
entry.match.append(
p4rt.FieldMatch(
field_id=1, # dstAddr
exact=p4rt.FieldMatch.Exact(
value=b'\xaa\xbb\xcc\xdd\xee\xff'
)
)
)
entry.action.action_id = forward_action_id
entry.action.params.append(
p4rt.Action.Param(
param_id=1, # egress_port
value=b'\x00\x03' # port 3
)
)
client.Write(p4rt.WriteRequest(
updates=[p4rt.Update(type=1, entity=p4rt.Entity(table_entry=entry))]
)

六、动手实践#

本节提供四个实践练习,从查看网卡卸载能力到 P4 编译运行,逐步掌握 SmartNIC/DPU 的核心操作。

实践 1:ethtool 查看网卡卸载能力#

# 查看网卡的所有卸载能力
ethtool -k <interface>
# 重点关注以下卸载特性:
# tcp-segmentation-offload: on # TSO
# generic-receive-offload: on # GRO
# rx-checksumming: on # RX 校验和卸载
# tx-checksumming: on # TX 校验和卸载
# hw-tc-offload: on # tc 硬件卸载(OVS 卸载必需)
# rx-vlan-offload: on # VLAN 卸载
# tx-vlan-offload: on # VLAN 卸载
# 启用/禁用特定卸载
sudo ethtool -K <interface> hw-tc-offload on
sudo ethtool -K <interface> tso on
sudo ethtool -K <interface> gro on
# 查看网卡统计(包括硬件卸载的统计)
ethtool -S <interface> | grep -i offload
# 查看 NVIDIA/Mellanox 网卡的加速统计
ethtool -S <interface> | grep -i "tc_offload\|rx_steer\|flow"
Tip

如果 hw-tc-offload 显示为 off 且无法启用,可能是网卡型号不支持或驱动版本过旧。ConnectX-4 以后型号才支持 tc 硬件卸载。

实践 2:OVS 硬件卸载配置与验证#

# ===== 环境准备 =====
# 确保网卡支持 hw-tc-offload
ethtool -k <interface> | grep hw-tc-offload
# 启用网卡的 tc 硬件卸载
sudo ethtool -K <interface> hw-tc-offload on
# ===== OVS 配置 =====
# 启用 OVS 硬件卸载
sudo ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
# 重启 OVS 使配置生效
sudo systemctl restart openvswitch-switch
# 创建 OVS 网桥并添加端口
sudo ovs-vsctl add-br br0
sudo ovs-vsctl add-port br0 <interface>
# ===== 验证 =====
# 生成流量后,查看是否有规则被卸载到硬件
sudo ovs-dpctl dump-flows -m type=tc
# 输出示例(注意 offloaded:yes):
# recirc_id(0),in_port(1),eth(src=aa:bb:cc:dd:ee:ff,dst=11:22:33:44:55:66),
# eth_type(0x0800),ipv4(src=10.0.0.1/0.0.0.0,dst=10.0.0.2/0.0.0.0,
# proto=6,tos=0/0,ttl=64,frag=no),tcp(src=12345/0,dst=80/0),
# packets=1000000,bytes=64000000,offloaded:yes,used:0.001s
# 查看硬件卸载统计
sudo ovs-dpctl show -s
# 关注 offloads 字段
# ===== 调试 =====
# 如果规则没有被卸载,检查 OVS 日志
sudo journalctl -u openvswitch-switch | grep -i offload
# 查看网卡上的 tc 规则
sudo tc filter show dev <interface> ingress
# 检查规则是否在硬件中
sudo tc -s filter show dev <interface> ingress
# 如果看到 "in hw" 标记,说明规则已卸载到硬件

实践 3:P4 程序编译与模拟#

如果没有 SmartNIC 硬件,可以使用 BMv2(Behavioral Model v2)——P4 的软件模拟器来学习和调试 P4 程序:

# ===== 安装 P4 开发工具 =====
# 安装依赖
sudo apt install cmake g++ git automake libtool libboost-dev \
libboost-filesystem-dev libboost-program-options-dev \
libboost-system-dev libgrpc++-dev libprotobuf-dev \
protobuf-compiler libgmp-dev libpcap-dev
# 编译安装 BMv2
git clone https://github.com/p4lang/behavioral-model.git
cd behavioral-model
git submodule update --init --recursive
./autogen.sh
./configure
make -j$(nproc)
sudo make install
# 编译安装 p4c(P4 编译器)
git clone https://github.com/p4lang/p4c.git
cd p4c
git submodule update --init --recursive
mkdir build && cd build
cmake ..
make -j$(nproc)
sudo make install
# ===== 编译 P4 程序 =====
# 编译 L2 转发程序为 BMv2 JSON
p4c --target bmv2 --arch v1model l2_forward.p4 -o l2_forward.json
# ===== 运行 BMv2 =====
# 启动 BMv2 交换机(简单交换机)
simple_switch --interface 0@veth0 --interface 1@veth1 \
l2_forward.json &
# 使用 CLI 下发规则
simple_switch_CLI
# 在 CLI 中:
# table_add dst_mac_table forward aa:bb:cc:dd:ee:ff => 1
# table_add dst_mac_table forward 11:22:33:44:55:66 => 0
# ===== 发送测试流量 =====
# 在 veth0 上发送包
sudo python3 send_packet.py --interface veth0 \
--src-mac aa:bb:cc:dd:ee:ff \
--dst-mac 11:22:33:44:55:66
# 在 veth1 上抓包验证
sudo tcpdump -i veth1 -nn

实践 4:硬件卸载 vs 软件转发性能基准#

# ===== 测试环境 =====
# 发送端:使用 pktgen-dpdk 或 MoonGen 生成流量
# 接收端:运行 OVS(分别测试软件转发和硬件卸载)
# ===== 软件转发基准 =====
# 禁用硬件卸载
sudo ovs-vsctl set Open_vSwitch . other_config:hw-offload=false
sudo systemctl restart openvswitch-switch
# 生成 64B 小包流量,测量吞吐量
# 预期:~2-5 Mpps(取决于 CPU 核心数和频率)
# 记录 CPU 使用率
mpstat -P ALL 1 10 > software_cpu.txt
# ===== 硬件卸载基准 =====
# 启用硬件卸载
sudo ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
sudo systemctl restart openvswitch-switch
# 生成相同流量,测量吞吐量
# 预期:~50-100 Mpps(线速,取决于网卡型号)
# 记录 CPU 使用率
mpstat -P ALL 1 10 > hardware_cpu.txt
# ===== 对比分析 =====
# 对比两个场景的:
# 1. 吞吐量(Mpps)
# 2. CPU 使用率(%)
# 3. 延迟(P50/P99)
# 4. 功耗(如果可测量)
# 使用 dpdk-procinfo 查看硬件统计
dpdk-procinfo -- --stats
Warning

性能基准测试需要稳定的测试环境:绑核、关闭超线程、固定 CPU 频率(cpupower frequency-set -g performance)、隔离测试网络。否则结果会有较大波动,无法得出可靠结论。

小结#

本章从”为什么需要硬件卸载”出发,系统梳理了 SmartNIC 与 DPU 的技术栈:

  1. 硬件卸载的动机:CPU 贵且慢,ASIC 便宜且快。当软件旁通已经推到极限,硬件卸载是进一步提升性能和降低 CPU 开销的必然选择。适合卸载的任务具有”固定模式、高频重复”的特征——流匹配、包修改、加密、TCP 处理、流量整形。

  2. SmartNIC 三种架构:固定功能 ASIC(ConnectX,性能极致但不可编程)、可编程 FPGA/NPU(Netronome/Xilinx,完全可编程但门槛高)、混合 ASIC+CPU(BlueField/Pensando,性能与灵活性的最佳平衡)。

  3. DPU 产品矩阵:NVIDIA BlueField(ARM + ConnectX ASIC,生态最成熟)、AMD Pensando(P4 可编程 ASIC + ARM,数据平面最灵活)、Intel IPU(FPGA + Xeon,可编程性最强)。选择取决于场景——标准卸载选 BlueField,自定义协议选 Pensando,极致自定义选 IPU。

  4. OVS 硬件卸载:tc/rte_flow/ASAP² 三种接口,miss→软件→安装硬件规则→hit→硬件的完整流程。配置简单(hw-offload=true),但调试需要理解 tc 命令和硬件规则容量限制。

  5. P4 编程:Headers→Parser→Match-Action→Deparser 的架构模型,P4₁₆ 的类型系统和语法,L2 转发的完整 P4 程序示例。P4 是可编程数据平面的核心语言,掌握 P4 就掌握了 SmartNIC/DPU 可编程性的本质。

Tip

SmartNIC/DPU 不是万能的。它最适合的场景是:大量重复的包处理逻辑(OVS 转发、ACL 过滤、加密、封装),这些逻辑可以被硬件规则固化。对于需要复杂控制逻辑或频繁策略变化的场景,软件方案(OVS-DPDK、VPP)仍然更灵活。最佳实践是”硬件加速快速路径 + 软件处理慢速路径”的混合架构。

参考资料#

规范与标准#

厂商文档#

开源项目#

技术论文与博客#

  • “The Programmable Data Plane: Abstractions, Architectures, Algorithms, and Applications” — P4 可编程数据平面的学术综述
  • “BlueField DPU Architecture” — NVIDIA BlueField 架构白皮书
  • Brendan Gregg’s Blog: Hardware Offload Performance — 硬件卸载性能分析方法
  • NVIDIA Developer Blog: OVS Hardware Offload — OVS 硬件卸载实践详解

延伸阅读#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

部分信息可能已经过时

相关文章 智能推荐
1
OVS-DPDK 与虚拟交换
高性能网络 深入 OVS-DPDK 与虚拟交换——OVS-DPDK 架构与内核 OVS 对比、dpdkvhostuser 端口类型、vhost-user 协议与共享 virtio 环、virtio 前后端、VM-to-VM 交换路径、流分类(EMC/DPCLS/megaflows)、性能调优——掌握云环境虚拟网络加速的完整技术栈。
2
SPDK 与存储旁通
高性能网络 深入 SPDK 与存储旁通——SPDK 架构与 DPDK EAL 共享、用户态 NVMe 驱动(MMIO/SQ/CQ)、vhost-user 协议与共享内存、bdev 抽象层与模块、blobstore 持久化对象存储、iSCSI/NVMe-oF Target——掌握用户态存储的完整技术栈。
3
io_uring 与异步 IO 革命
高性能网络 深入 io_uring 架构——SQ/CQ 环形缓冲区布局与无锁交互、提交与完成流程、固定缓冲区与文件注册、网络 I/O 操作、multishot accept、SQPOLL 模式、与 epoll/AIO 的性能对比——掌握 Linux 异步 I/O 的终极方案。
4
DPDK 多核与并发模型
高性能网络 深入 DPDK 多核与并发模型——lcore 模型与 CPU 亲和性、Run-to-Completion 模型、Pipeline 模型与 rte_ring 跨核通信、原子操作与内存屏障、RCU 机制(rte_rcu_qsbr)、Eventdev 事件驱动框架——掌握多核数据平面编程的完整技术栈。
5
VPP 与 FD.io 数据平面
高性能网络 深入 VPP 与 FD.io 数据平面——矢量包处理(Vector Packet Processing)的 I-Cache 友好设计、插件框架、图节点实现与类型、CLI 与 binary API、预取优化与批量处理、VPP + DPDK 输入节点——掌握下一代数据平面的架构与编程。