1. DOCA数据面开发总览

DOCA(Data Center Infrastructure on a Chip Architecture)是NVIDIA为BlueField系列DPU提供的软件开发框架。要理解DOCA数据面开发,首先要建立一个基本认知:BlueField DPU不是一块普通的网卡,而是一台"嵌入在PCIe卡上的小型服务器"。它内部集成了Arm多核CPU、专用网络加速硬件、可编程数据包处理引擎以及独立的内存子系统。DOCA的价值,就是把这套异构硬件的能力抽象成统一的编程接口,让开发者既能用Arm核跑控制逻辑,又能把高吞吐的数据处理卸载到硬件加速器上。

数据面与控制面的分工

在BlueField DPU上,数据面(Data Plane)和控制面(Control Plane)运行在不同的执行环境中,这是DOCA开发最核心的架构前提。

控制面运行在DPU的Arm CPU上,通常以Linux用户态进程或内核模块的形式存在。它负责策略下发、连接管理、路由决策、配置更新等"低频但需要灵活性"的工作。控制面代码可以用标准C/C++编写,链接DOCA的库,通过DOCA提供的API去配置硬件加速资源。

数据面则运行在硬件加速引擎上,包括网络流水线、正则表达式引擎、压缩/解压引擎、加解密引擎、DMA引擎等。数据面处理的是每一个到达的数据包或每一段需要搬运的数据,要求极低延迟和极高吞吐。开发者通过DOCA的编程模型,把数据面的处理逻辑"描述"给硬件,而不是在CPU上逐包处理。

这种分工带来的直接好处是:控制面可以慢、可以复杂、可以频繁修改;数据面必须快、必须简单、必须稳定。DOCA的API设计正是围绕这一分工展开的——控制面API负责创建和配置数据面对象,数据面API负责在硬件上执行实际的数据处理。

BlueField DPU 上的 DOCA 数据面与控制面分工 Host (x86服务器) 应用 / 虚拟机 / 容器 PCIe 驱动 通过 PCIe 与 DPU 通信 PCIe BlueField DPU Arm CPU 子系统 控制面 (Control Plane) • DOCA 控制面 API • 策略下发 / 连接管理 • 配置硬件加速资源 • 运行 Linux 用户态进程 硬件加速引擎 数据面 (Data Plane) • 网络流水线 / 正则引擎 • 压缩 / 解压 / 加解密 • DMA / RDMA 引擎 • 逐包 / 逐段数据处理 配置 网络接口 2× 100/200GbE 端口 数据包入口 / 出口 数据流 DOCA SDK 统一编程接口 DOCA Core · DOCA Flow · DOCA Compress · DOCA Crypto · DOCA DMA · DOCA RDMA · DOCA Regex 图例 控制面 (Arm CPU) 数据面 (硬件引擎)

DOCA SDK的组成

DOCA SDK并不是一个单一库,而是一组按功能划分的库和工具的集合。从数据面开发的角度,可以把它分成三个层次来理解。

最底层是DOCA Core,它提供设备抽象、内存管理、事件通知、进度引擎(Progress Engine)等基础设施。所有其他DOCA库都构建在Core之上。开发者需要理解Core中的几个关键概念:doca_dev代表一个DPU设备,doca_mmap代表一段可以被硬件直接访问的内存区域,doca_pe是事件轮询引擎,doca_ctx是各种加速功能的执行上下文。

中间层是各类功能库,按数据面处理类型划分:DOCA Flow用于可编程网络流水线,支持在硬件中匹配和转发数据包;DOCA Compress和DOCA Crypto分别提供压缩和加解密卸载;DOCA DMA用于主机与DPU之间的高效内存搬运;DOCA RDMA提供远程直接内存访问能力;DOCA Regex用于正则表达式匹配加速。每个库都遵循"创建上下文→配置参数→提交任务→轮询完成"的异步编程模式。

最上层是应用与工具,包括DOCA提供的参考应用、命令行工具(如doca_caps用于查询设备能力)以及容器化部署支持。DOCA应用通常以容器形式部署在DPU的Arm侧,通过doca_container工具管理生命周期。

开发环境搭建

DOCA开发环境有两种典型搭建方式:直接在BlueField DPU的Arm侧编译运行,或在x86主机上交叉编译后部署到DPU。对于初学者,建议先在DPU的Arm侧直接开发,减少工具链配置的复杂度。

在DPU上,首先确认DOCA已安装:

# 查看DOCA版本
doca_version

# 查询DPU设备能力
doca_caps --list-devs

# 典型输出示例(示例值,实际以设备为准)
# Device: mlx5_0
#   DOCA Flow: supported
#   DOCA Compress: supported
#   DOCA DMA: supported

编译一个DOCA程序需要链接对应的库。以DOCA Flow为例,编译命令通常形如:

gcc -o my_flow_app my_flow_app.c \
    -I/opt/mellanox/doca/include \
    -L/opt/mellanox/doca/lib \
    -ldoca_flow -ldoca_common -ldoca_core

运行前需要确保DPU的固件版本与DOCA版本匹配,并且相关内核模块已加载。可以用doca_info查看当前环境状态。

第一个DOCA程序:查询设备并创建上下文

下面是一个最小化的DOCA程序示例,它完成三件事:打开DPU设备、查询设备能力、创建一个DOCA Core上下文。这个程序不涉及具体的数据面处理,但它是所有DOCA应用的基础骨架。

#include <doca_common.h>
#include <stdio.h>

int main(void) {
    struct doca_devinfo *devinfo;
    struct doca_dev *dev = NULL;
    struct doca_ctx *ctx = NULL;
    doca_error_t rc;

    /* 1. 获取第一个可用的DPU设备信息 */
    devinfo = doca_devinfo_get_first();
    if (devinfo == NULL) {
        printf("未找到DOCA设备\n");
        return 1;
    }

    /* 2. 打开设备 */
    rc = doca_dev_open(devinfo, &dev);
    if (rc != DOCA_SUCCESS) {
        printf("打开设备失败: %s\n", doca_error_get_descr(rc));
        return 1;
    }
    printf("设备打开成功\n");

    /* 3. 查询设备能力(示例:检查是否支持Flow) */
    if (doca_devinfo_is_cap_supported(devinfo, DOCA_DEV_CAP_FLOW)) {
        printf("该设备支持 DOCA Flow\n");
    } else {
        printf("该设备不支持 DOCA Flow\n");
    }

    /* 4. 清理 */
    doca_dev_close(dev);
    return 0;
}

编译并运行这个程序,如果输出"设备打开成功"和"该设备支持 DOCA Flow",说明开发环境基本可用。如果打开设备失败,常见原因包括:没有以root权限运行、DPU固件未正确加载、或DOCA驱动未安装。可以用dmesg | grep mlx5查看内核日志中的驱动加载信息。

实践建议:在开始编写数据面逻辑之前,先用doca_caps确认目标DPU支持哪些加速功能。不同型号的BlueField(如BF2、BF3)支持的DOCA库集合不同,提前确认可以避免在编译或运行阶段才发现功能不可用。

从控制面到数据面的典型调用链

一个完整的DOCA数据面应用通常遵循这样的调用链:Arm侧的控制面程序先通过DOCA Core打开设备、创建doca_ctx;然后调用具体功能库(如DOCA Flow)的API,把匹配规则和转发动作下发到硬件流水线;硬件流水线开始对经过DPU的网络流量执行匹配和转发;控制面程序通过进度引擎轮询完成事件,并根据需要更新规则或销毁上下文。

这个调用链的关键在于:控制面的每一次API调用,最终都转化为对硬件寄存器的配置或对硬件队列的提交。开发者不需要直接操作寄存器,但需要理解"API调用是异步的"——提交任务后,必须通过进度引擎等待完成事件,不能假设任务立即生效。