DOCA UROM RDMO 应用程序指南
本指南介绍了在 NVIDIA® BlueField® DPU 上使用统一通信 X (UCX) 实现的 DOCA 远程直接内存操作。
远程直接内存操作 (RDMO) 在概念上是一种活动消息,它在目标进程的上下文之外执行。
RDMO 涉及以下实体
目标 – 建立与服务器的连接,用作控制路径。目标与服务器交互以定义目标端点和内存区域。目标与启动器交换端点和内存区域信息,以促进其连接。
启动器 – 建立与服务器的连接,用作数据路径。RDMO 通过向服务器发送带有可选负载的 RDMO 命令来启动。服务器解析命令并运行关联的 RDMO 处理程序。RDMO 处理程序通过对目标定义的内存区域执行单边内存访问来与目标进程交互。
服务器 – 负责从目标进程异步执行 RDMO。服务器为每个支持的操作实现一个 RDMO 处理程序。RDMO 处理程序可以在服务器内维护状态以进行优化。
DOCA UROM RDMO 应用程序包括上述三个实体,分为以下几个部分
BlueField 端 – RDMO 插件组件的实现,由 DOCA UROM 工作器(即 RDMO 服务器)加载
主机端 – 使用两种模式运行的主机应用程序:目标和启动器

RDMO 旨在利用平台上的额外计算资源。当应用程序进程在主计算资源上运行时,RDMO 服务器可以在同一主机上的空闲资源上运行,或者卸载到单独的设备(即 BlueField)上运行。
该应用程序演示了 RDMO 操作作为 DOCA UROM 工作器插件组件的实现。目标进程将使用 DOCA UROM API 创建一个具有 RDMO 功能的工作器。启动器进程建立与 UROM 工作器的 RDMO 连接。该插件使用 UCX 作为其传输。

引导程序
为了连接 RDMO 启动器和目标,在目标端,UROM 用于检索每个创建的 RDMO 工作器的地址。此地址需要传递到 RDMO 启动器端以建立连接。启动器地址从 RDMO 应用程序显式创建的 UCX 工作器获得。这两个地址都通过带外 (OOB) 网络交换,并用于建立连接
在 RDMO 启动器端,使用 UCX API 创建 UCX 端点
在 RDMO 目标端,启动器的地址使用 UROM 命令通道传递给 RDMO 工作器
内存管理
UROM 为导入到 RDMO 插件组件的每个内存区域返回一个标识符 (ID)。此 ID 用于在 RDMO 请求中引用目标内存区域。它必须与启动器进程 OOB 交换。
RDMO UROM 工作器操作
RDMO 启动器和工作器之间的通信在 UCX 活动消息之上实现。工作器的活动消息处理程序是入口点,它根据 RDMO 请求标头识别 RDMO 操作的类型。然后,请求被转发到相应的 RDMO 操作处理程序,该处理程序通过检查请求中特定于操作的子标头来确定操作参数。
UCX 活动消息支持 eager 和 rendezvous 协议。当使用 rendezvous 协议时,工作器可以选择是将数据拉取到服务器,还是使用 UCX 导入的内存句柄将其直接移动到目标内存。
RDMO 操作处理程序可以执行计算、启动器和目标内存访问、服务器状态更新或响应的任意组合。

RDMO 客户端使用 UROM 实例化 RDMO 工作器,并配置目标端点和内存区域。客户端直接使用 UCX 将端点连接到 RDMO 服务器。客户端使用 UCX 发送格式化的 RDMO 消息。
DOCA 的 UROM RDMO 应用程序实现使用 UCX 来支持端点之间的数据交换。它利用 UCX 基于 sockaddr 的连接建立和 UCX 活动消息 (AM) API 进行通信,UCX 负责所有 RDMO 通信(控制和数据路径)。
RDMO 服务器应用程序通过 DOCA UROM 服务启动 DOCA UROM 工作器 RDMO 组件,并与 DOCA UROM RDMO 客户端应用程序共享 UROM 工作器 UCX EP。RDMO 服务器应用程序将内存区域导入到 UROM 工作器中,以方便 BlueField 从主机内存执行 RDMA 操作。
RDMO 客户端应用程序通过 DOCA UROM 工作器执行 RDMO 操作。在从服务器接收到 UCX EP 地址后,客户端应用程序最初与工作器建立连接。然后,它继续请求工作器执行操作,而服务器应用程序不知情。

UROM RDMO 工作器组件
UROM RDMO 工作器插件组件定义了一小组命令,使目标能够
在客户端和工作器之间建立 UCX 通信通道
创建一个能够接收 RDMO 请求的 UCX 端点
导入可用作工作器启动的 RDMA 的源或目标的内存区域
命令集是
enum
urom_worker_rdmo_cmd_type {
UROM_WORKER_CMD_RDMO_CLIENT_INIT,
UROM_WORKER_CMD_RDMO_RQ_CREATE,
UROM_WORKER_CMD_RDMO_RQ_DESTROY,
UROM_WORKER_CMD_RDMO_MR_REG,
UROM_WORKER_CMD_RDMO_MR_DEREG,
};
关联的通知类型是
enum
urom_worker_rdmo_notify_type {
UROM_WORKER_NOTIFY_RDMO_CLIENT_INIT,
UROM_WORKER_NOTIFY_RDMO_RQ_CREATE,
UROM_WORKER_NOTIFY_RDMO_RQ_DESTROY,
UROM_WORKER_NOTIFY_RDMO_MR_REG,
UROM_WORKER_NOTIFY_RDMO_MR_DEREG,
};
初始化
客户端初始化命令初始化客户端以接收 RDMO。这包括建立工作器和主机之间的连接,以允许 RDMO 工作器访问客户端内存。
命令类型为 UROM_WORKER_CMD_RDMO_CLIENT_INIT
。命令格式
struct urom_worker_rdmo_cmd_client_init {
uint64_t id;
void
*addr;
uint64_t addr_len;
};
id
– 客户端 ID,用于在 RDMO 命令中标识目标进程addr
– 指向客户端的 UCP 工作器地址的指针,用于工作器到主机的连接addr_len
– 地址的长度
此命令返回类型为 UROM_WORKER_NOTIFY_RDMO_CLIENT_INIT
的通知。通知格式
struct urom_worker_rdmo_notify_client_init {
void
*addr;
uint64_t addr_len;
addr
– 指向组件的 UCP 工作器地址的指针,用于启动器到服务器的连接addr_len
– 地址的长度
RQ 创建
此接收队列 (RQ) 创建命令在服务器上创建并连接一个新端点。该端点可能是格式化 RDMO 消息的目标。
此命令的类型为 UROM_WORKER_CMD_RDMO_RQ_CREATE
。命令格式
struct urom_worker_rdmo_cmd_rq_create {
void
*addr;
uint64_t addr_len;
};
addr
– 用于连接新端点的 UCP 工作器地址addr_len
– 地址的长度
该命令返回类型为 UROM_WORKER_NOTIFY_RDMO_RQ_CREATE
的通知。通知格式
struct urom_worker_rdmo_notify_rq_create {
uint64_t rq_id;
};
rq_id
– 用于销毁 RQ 的 RQ ID
RQ 销毁
RQ 销毁命令销毁 RQ。
RQ 销毁命令的类型为 UROM_WORKER_CMD_RDMO_RQ_DESTROY
。命令格式
struct urom_worker_rdmo_cmd_rq_destroy {
uint64_t rq_id;
};
rq_id
– 先前创建的 RQ 的 ID
RQ 销毁命令返回类型为 UROM_WORKER_NOTIFY_RDMO_RQ_DESTROY
的通知。通知格式
struct urom_worker_rdmo_notify_rq_destroy {
uint64_t rq_id;
};
rq_id
– 已销毁的接收队列 ID
MR 注册
内存区域 (MR) 注册命令向 RDMO 组件注册 UCP 内存句柄。MR 必须先向 RDMO 组件注册,然后才能在 RDMO 中使用。
该命令的类型为 UROM_WORKER_CMD_RDMO_MR_REG
。命令格式
struct urom_worker_rdmo_cmd_mr_reg {
uint64_t va;
uint64_t len;
void
*packed_rkey;
uint64_t packed_rkey_len;
void
*packed_memh;
uint64_t packed_memh_len;
};
va
– MR 的虚拟地址len
– MR 的长度packed_rkey
– 指向 MR 的 UCP 打包 R-key 的指针packed_rkey_len
–packed_rkey
的长度packed_mem_h
– 指向 MR 的 UCP 打包内存句柄的指针。内存句柄必须使用标志UCP_MEMH_PACK_FLAG_EXPORT
打包。packed_memh_len
–packed_memh
的长度
该命令返回类型为 UROM_WORKER_NOTIFY_RDMO_MR_REG
的通知。通知格式
struct urom_worker_rdmo_notify_mr_reg {
uint64_t rkey;
};
rkey
– 在 RDMO 中用于引用 MR 的 ID
MR 注销
MR 注销命令从 RDMO 组件注销 MR。
该命令的类型为 UROM_WORKER_CMD_RDMO_MR_DEREG
。命令格式
struct urom_worker_rdmo_cmd_mr_dereg {
uint64_t rkey;
};
rkey
– 先前注册的 MR 的 ID
该命令返回类型为 UROM_WORKER_NOTIFY_RDMO_MR_DEREG
的通知。通知格式
struct urom_worker_rdmo_notify_mr_dereg {
uint64_t rkey;
};
rkey
– 注销的内存区域远程密钥
命令格式
RDMO 通过经由 UCP 活动消息向 UROM RDMO 工作器服务器发送 RDMO 请求来启动。
RDMO 请求格式为

RDMO 标头标识操作类型和标志,从而修改 RDMO 的处理方式。操作 (op) 标头包含特定于操作类型的参数。可选地,操作类型可以包括任意大小的负载。
RDMO 标头格式
struct urom_rdmo_hdr {
uint32_t id;
uint32_t op_id;
uint32_t flags;
};
id
– 客户端 IDop_id
– RDMO 操作类型 IDflags
– 修改服务器如何处理 RDMO 的标志
有效标志值
enum
urom_rdmo_req_flags {
UROM_RDMO_REQ_FLAG_FENCE,
};
UROM_RDMO_REQ_FLAG_FENCE
– 在执行此请求之前,完成连接上的所有未完成 RDMO 请求。此标志是实现刷新操作所必需的,该操作保证远程完成。
可选地,操作可以向启动器返回响应。
响应标头格式
struct urom_rdmo_rsp_hdr {
uint16_t op_id;
};
op_id
– RDMO 响应类型 ID
追加
RDMO 追加原子性地将数据追加到远程内存中的队列。这可以使用单边编程模型来实现,方法是对远程内存中指针的位置执行 Fetching-Add 操作,然后对获取的地址执行 Put 操作。RDMO 追加允许将这些依赖操作卸载到目标。
下图提供了 Append 操作的本机方法和 RDMO 方法的比较

将两个依赖操作组合成单个 RDMO 允许 Append 的非阻塞实现,因为启动器无需在 Fetching Atomic 操作和数据写入操作之间等待。使用 RDMO,启动器可以创建操作管道并实现更高的消息速率。
RDMO 服务器可以对目标内存执行操作的速率预计会成为瓶颈。为了提高速率,可以考虑以下优化
初始追加后 Fetch-and-ADD (FADD) 的结果可以缓存在服务器中。后续追加可以重用缓存值,从而消除原子 FADD 操作。修改后的指针值需要在刷新命令期间同步。
对于小的追加大小,追加数据可以缓存在 RDMO 服务器中并合并为单个 Put。因此,服务器平均需要对目标内存进行单次 Put 访问才能执行多个 RDMO。
为了避免大型追加操作的额外内存使用和带宽损失,RDMO 服务器可以启动从启动器到目标内存的直接传输,绕过加速设备内存。
Append 操作使用类型为 UROM_RDMO_OP_APPEND
的操作。Append 标头格式
struct urom_rdmo_append_hdr {
uint64_t ptr_addr;
uint16_t ptr_rkey;
uint16_t data_rkey;
};
ptr_addr
– 目标内存中队列指针的地址ptr_rkey
– 用于访问ptr_addr
的 R-keydata_rkey
– 用于访问队列数据的 R-key
RDMO 负载是本地数据缓冲区。
刷新
RDMO 刷新用于实现启动器和服务器之间的同步。在执行时,刷新会将响应消息发送回启动器。刷新可用于保证先前发出的 RDMO 的远程完成。
为了实现这一点,启动器发送一个有序的刷新命令,包括 RDMO 标志 UROM_RDMO_REQ_FLAG_FENCE
. 此标志使服务器在执行刷新之前完成所有先前接收到的 RDMO。为了完成先前的操作,服务器必须写入任何缓存的数据,并使其在目标内存中可见。完成后,服务器执行刷新。刷新向启动器发送响应。当启动器收到刷新消息时,保证先前发送的所有 RDMO 的结果在目标内存中可见。
刷新操作使用操作类型 UROM_RDMO_OP_FLUSH
。刷新标头格式
struct urom_rdmo_flush_hdr {
uint64_t flush_id;
};
flush_id
– 用于跟踪完成情况的本地 ID
刷新返回带有以下标头格式的响应
struct urom_rdmo_flush_rsp_hdr {
uint64_t flush_id;
};
flush_id
– 已完成刷新的 ID
刷新请求和响应不包含负载。
分散
RDMO 分散用于支持聚合非连续内存 Put。可以定义一个 RDMO,以使用目标平台上的网络接口将非连续虚拟地址映射到单个内存区域,然后返回此区域的内存密钥。然后,启动器可以对此内存区域执行 Put 操作,这些操作由目标硬件分散。或者,可以定义 RDMO 以发布 IOV 接收。然后,启动器可以发布匹配的发送,以在目标处分散数据。
分散操作使用操作类型 UROM_RDMO_OP_SCATTER
。分散标头格式
struct urom_rdmo_scatter_hdr {
uint64_t count; /* Number of IOVs in the payload */
};
count
– RDMO 负载中 IOV 的数量
IOV 打包到分散请求负载中,描述符后跟数据
struct urom_rdmo_scatter_iov {
uint64_t addr; /* Scattered data address */
uint64_t rkey; /* Data remote key */
uint16_t len; /* Data length */
};
addr
– 分散数据地址rkey
– 数据远程密钥len
– 数据长度
有关如何安装 BlueField 相关软件的详细信息,请参阅DOCA Linux 安装指南。
DOCA 参考应用程序的安装包含应用程序的源代码以及匹配的编译说明。这允许“按原样”编译应用程序,并提供修改源代码然后编译应用程序新版本的能力。
有关应用程序以及开发和编译技巧的更多信息,请参阅DOCA 参考应用程序页面。
应用程序的源代码可以在应用程序的目录下找到: /opt/mellanox/doca/applications/urom_rdmo/
。
编译所有应用程序
所有 DOCA 应用程序都在单个 meson 项目下定义。因此,默认情况下,编译包括所有应用程序。
要一起构建所有应用程序,请运行
cd /opt/mellanox/doca/applications/
meson /tmp/build
ninja -C /tmp/build
在主机上,doca_urom_rdmo
在 /tmp/build/urom_rdmo/host/
下创建。在 BlueField 端,RDMO 工作器插件 worker_rdmo.so
在 /tmp/build/urom_rdmo/dpu/
下创建。
仅编译当前应用程序
要直接仅构建 UROM RDMO 应用程序(主机)或插件 (DPU)
cd /opt/mellanox/doca/applications/
meson /tmp/build -Denable_all_applications=false
-Denable_urom_rdmo=true
ninja -C /tmp/build
在主机上,doca_urom_rdmo
在 /tmp/build/urom_rdmo/host/
下创建。在 BlueField 端,RDMO 工作器插件 worker_rdmo.so
在 /tmp/build/urom_rdmo/dpu/
下创建。
或者,可以在 meson_options.txt
文件中设置所需的标志,而不是在编译命令行中提供它们
编辑
/opt/mellanox/doca/applications/meson_options.txt
中的以下标志将
enable_all_applications
设置为false
将
enable_urom_rdmo
设置为true
运行以下编译命令
cd /opt/mellanox/doca/applications/ meson /tmp/build ninja -C /tmp/build
信息在主机上,
doca_urom_rdmo
在/tmp/build/urom_rdmo/host/
下创建。在 BlueField 端,RDMO 工作器插件worker_rdmo.so
在/tmp/build/urom_rdmo/dpu/
下创建。
故障排除
有关应用程序编译遇到的任何问题,请参阅DOCA 故障排除。
主机应用程序执行
UROM RDMO 应用程序以源代码形式提供;因此,在执行应用程序之前需要进行编译。
应用程序使用说明
Usage: doca_urom_rdmo [DOCA Flags] [Program Flags] DOCA Flags: -h, --help Print a help synopsis -v, --version Print program version information -l, --log-level Set the (numeric) log level
for
the program <10
=DISABLE,20
=CRITICAL,30
=ERROR,40
=WARNING,50
=INFO,60
=DEBUG,70
=TRACE> --sdk-log-level Set the SDK (numeric) log levelfor
the program <10
=DISABLE,20
=CRITICAL,30
=ERROR,40
=WARNING,50
=INFO,60
=DEBUG,70
=TRACE> -j, --json <path> Parse all command flags from an input json file Program Flags: -d, --device <IB device name> IB device name. -s, --server-name <server name> server name. -m, --mode {server, client} Set mode type {server, client}信息此用法打印输出可以使用
-h
(或--help
)选项打印到命令行./doca_urom_rdmo -h
信息有关更多信息,请参阅“命令行标志”部分。
以服务器模式运行应用程序的 CLI 示例
./doca_urom_rdmo -d mlx5_0 -m server
以客户端模式运行应用程序的 CLI 示例
./doca_urom_rdmo -m clinet -s <server_host_name>
该应用程序还支持基于 JSON 的部署模式,其中所有命令行参数都通过 JSON 文件提供
./doca_urom_rdmo --json [json_file]
例如
./doca_urom_rdmo --json ./urom_rdmo_params.json
RDMO DPU 插件组件
UROM RDMO 插件组件以源代码形式提供,因此在执行应用程序之前需要进行编译,以便在生成 UROM 工作器时可以运行时加载插件,并且它被编译为 .so
文件。
该插件公开了以下符号
获取 RDMO 插件的 DOCA 工作器插件接口
doca_error_t urom_plugin_get_iface(struct urom_plugin_iface *iface);
获取 RDMO 插件版本,该版本将用于验证主机和 DPU 插件版本是否兼容
doca_error_t urom_plugin_get_version(uint64_t *version);
命令行标志
标志类型 | 短标志 | 长标志/JSON 键 | 描述 | JSON 内容 |
通用标志 |
|
| 打印帮助概要 | N/A |
|
| 打印程序版本信息 | N/A | |
|
| 设置应用程序的日志级别
|
| |
N/A |
| 设置程序的日志级别
|
| |
|
| 从输入 JSON 文件解析所有命令标志 | N/A | |
程序标志 |
|
| DOCA UROM IB 设备名称 |
|
|
| RDMO 服务器名称 |
| |
|
| RDMO 应用程序模式 [server, client] |
|
有关支持的标志和执行模式的更多信息,请参阅DOCA 参数解析器。
故障排除
有关 DOCA 应用程序的安装或执行遇到的任何问题,请参阅DOCA 故障排除。
解析应用程序参数。
初始化参数解析器资源并注册 DOCA 通用参数。
doca_argp_init();
注册 UROM RDMO 应用程序参数。
register_urom_rdmo_params();
解析参数。
doca_argp_start();
运行主逻辑
如果应用程序模式为服务器
创建 UROM 对象并在 BlueField 上生成 UROM 工作器。
使用以下功能初始化 UCP:
UCP_FEATURE_AM
、UCP_FEATURE_EXPORTED_MEMH
。创建 UCP 工作器并查询工作器地址
使用命令
UROM_WORKER_CMD_RDMO_CLIENT_INIT
初始化 RDMO 工作器客户端。通过 OOB 通道将 UROM RDMO 工作器地址发送给启动器,并接收启动器的 UCP 工作器地址
创建 UCP 内存句柄并使用命令
UROM_WORKER_CMD_RDMO_MR_REG
向 RDMO 服务器注册。接收返回的 R-key。将 RDMO 密钥发送给启动器
通过将启动器的 UCP 工作器地址传递给 UROM 命令
UROM_WORKER_CMD_RDMO_RQ_CREATE
来创建 RDMO RQ。等待 RDMO 追加操作完成,然后验证内存数据。
等待 RDMO 分散操作完成,然后验证内存数据。
销毁 UCP 资源。
销毁 UROM RDMO 工作器和 UROM 对象。
如果应用程序模式为客户端
直接使用 UCX API 创建 UCP 工作器。
通过 OOB 通道接收 UROM RDMO 工作器地址,并发送启动器的 UCP 工作器地址。
使用 RDMO 工作器地址创建 UCP 端点。
在端点上安装活动消息处理程序以接收 RDMO 响应。
通过 UCP 活动消息协议发送 RDMO 请求,标头指向序列化的 RDMO 和 Op 标头,数据指向负载。请求参数标志:
UCP_AM_SEND_FLAG_REPLY
将被设置为允许 RDMO 服务器识别发送者。RDMO 操作完成后,销毁 UCP 资源。
参数解析器销毁。
doca_argp_destroy();
/opt/mellanox/doca/applications/urom_rdmo/
/opt/mellanox/doca/applications/urom_rdmo/urom_rdmo_params.json