3. DPAA2对象模型入门
DPAA2(Data Path Acceleration Architecture 2)与传统的“寄存器 + 描述符环”网络驱动有本质区别:它把硬件资源抽象成一组可被内核和用户态共同管理的对象(Object),每个对象由 MC(Management Complex)固件创建、配置和销毁,软件通过命令接口操作对象,通过对象之间的连接关系组织数据面。理解 DPAA2,第一步不是写驱动,而是搞清楚“有哪些对象、各自负责什么、谁依赖谁、怎么发现它们”。
一、对象模型的核心思想
DPAA2 中的对象不是 C 语言结构体,而是 MC 固件内部维护的实体,软件侧只持有一个 32 位对象 ID(Object ID)。对象 ID 的高位标识对象类型,低位标识实例编号。软件通过 dprc 容器对象向 MC 发送命令,完成对象的创建、查询、连接和销毁。这种设计带来两个直接后果:一是资源生命周期由 MC 统一管理,驱动崩溃不会直接破坏硬件状态;二是对象可以跨内核态与用户态共享,用户态通过 UIO/VFIO 映射对象后可直接操作数据面队列。
可以把 DPAA2 对象模型类比为“硬件资源版的面向对象系统”:DPRC 是容器/命名空间,DPNI 是网络接口,DPBP 是缓冲区池,DPIO 是 I/O 门户,DPCON 是消息上下文,DPMCP 是管理命令门户。它们之间通过“连接”建立引用关系,而不是通过全局变量或硬编码地址。
二、主要对象职责
| 对象 | 全称 | 核心职责 | 典型数量 |
|---|---|---|---|
| DPRC | Data Path Resource Container | 资源容器,管理其他对象的创建、查询、连接与销毁,是访问 MC 的入口 | 1 个根容器 + 若干子容器 |
| DPNI | Data Path Network Interface | 网络接口对象,对应一个 MAC/PHY 端口,承载收发队列、分流规则、VLAN 等配置 | 每端口 1 个 |
| DPBP | Data Path Buffer Pool | 缓冲区池,管理帧缓冲区的分配与回收,供 DPNI 收发使用 | 每接口 1~2 个 |
| DPIO | Data Path I/O Portal | I/O 门户,软件与数据面队列交互的入口,包含 QMan 与 BMan 门户 | 每 CPU 核 1 个 |
| DPCON | Data Path Concentrator | 消息上下文,把多个 DPIO 的通知聚合到一个中断,减少中断风暴 | 按需创建 |
| DPMCP | Data Path Management Command Portal | 管理命令门户,软件向 MC 发送管理命令的通道 | 每容器若干 |
其中 DPNI 是最贴近业务的“网卡对象”。它内部包含 RX/TX 队列、分流表、MAC 地址表、VLAN 过滤表等。DPBP 为 DPNI 提供帧缓冲区,DPIO 为软件提供访问这些队列的门户。DPRC 则像“资源管理器”,所有对象都挂在某个 DPRC 下,通过 DPRC 的命令接口进行发现和连接。
三、对象发现流程
系统启动后,软件不能假设对象已经存在,必须通过 DPRC 逐层发现。典型流程如下:
- 打开根 DPRC,获取容器句柄。
- 查询 DPRC 属性,得到该容器内对象数量、类型分布、可用门户数等。
- 遍历对象列表,按类型筛选出 DPNI、DPBP、DPIO、DPCON、DPMCP。
- 对每个对象查询其属性,例如 DPNI 的 MAC 地址、队列数,DPBP 的缓冲区大小。
- 建立连接:把 DPNI 与 DPBP、DPIO 关联,把 DPIO 与 DPCON 关联。
- 将对象映射到软件地址空间,准备数据面收发。
下面这张图展示了对象之间的依赖与发现路径。注意箭头方向表示“发现/连接”的方向,而不是数据流方向。
四、对象 ID 与命令接口
每个对象都有一个唯一的对象 ID,格式为 type:instance。例如 dpni.0 表示第一个 DPNI 对象。软件通过 dprc 的 get_obj 命令获取对象句柄,再通过 get_attributes 读取属性。以下是一个典型的发现命令序列(示意):
# 打开根 DPRC
dprc_open("/dev/dprc.0", &root);
# 查询容器内对象数量
dprc_get_attributes(root, &attr);
printf("objects: %d\n", attr.num_objects);
# 遍历对象,筛选 DPNI
for (i = 0; i < attr.num_objects; i++) {
dprc_get_obj(root, i, &obj);
if (obj.type == DPRC_OBJ_DPNI) {
dprc_get_obj_region(root, i, "dpni", ®ion);
}
}
这段代码展示了发现流程的核心:先打开容器,再遍历对象列表,按类型筛选,最后获取对象区域信息用于地址映射。实际驱动中还会进一步查询 DPNI 的队列数、MAC 地址、DPBP 的缓冲区大小等,以便初始化数据面。
五、连接关系与数据面组织
对象之间的连接不是“自动”的,需要软件显式建立。例如,DPNI 的 RX 队列需要绑定到某个 DPIO 门户,才能被软件轮询或中断处理;DPNI 的 TX 队列需要从 DPBP 获取缓冲区,才能发送帧。DPIO 与 DPCON 的连接则用于把多个门户的通知聚合到一个中断上,减少 CPU 中断负载。
一个典型的单端口配置可能包含:1 个 DPNI、1 个 DPBP、每 CPU 核 1 个 DPIO、1 个 DPCON、若干 DPMCP。软件发现这些对象后,按“DPNI → DPBP”“DPNI → DPIO”“DPIO → DPCON”的顺序建立连接,最后把 DPNI 的队列映射到用户态或内核态,开始收发。
dprc_open,然后才是遍历和连接。
dpni.0 在单端口场景可能侥幸工作,但在多端口、多容器或热插拔场景下会直接失败。
六、小结与检查要点
掌握 DPAA2 对象模型,关键不是记住每个对象的全称,而是理解“容器—对象—连接”三层结构:DPRC 是容器,DPNI/DPBP/DPIO/DPCON/DPMCP 是对象,连接关系决定数据面如何组织。发现流程则是从 DPRC 出发,逐层查询、筛选、连接、映射。实际调试时,可以用 ls /dev/dprc.* 查看容器设备节点,用 restool 工具查询对象列表和属性,验证发现结果是否符合预期。
检查要点:DPRC 是否成功打开;对象数量与类型是否与硬件配置一致;DPNI 是否绑定到正确的 DPBP 和 DPIO;DPIO 是否与 DPCON 连接;对象区域是否成功映射。任何一步失败,都会导致数据面无法启动或收发异常。