关于 rdma-verbs
面向 Agent 的 RDMA 编程指南,介绍如何使用 libibverbs 配置设备、建立连接并执行数据传输。适合开发低延迟网络应用及排查 RDMA 连接、完成状态和性能问题。
主要功能
- 01libibverbs 设备与队列配置
- 02单边和双边 RDMA 操作
- 03RC、UC、UD 传输类型
- 04RoCE 与 InfiniBand 配置
- 05perftest 基准测试及 Rust 绑定
适用场景
- 01为存储或数据库构建低延迟网络
- 02通过单边 RDMA 访问远程内存
- 03配置以太网上的 RoCE
- 04诊断 RDMA 连接或完成错误
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill rdma-verbs安装后在 Claude Code 中输入/rdma-verbs确认已加载。
详细介绍
RDMA Verbs
用途
指导 Agent 使用 libibverbs 进行 RDMA 编程:单边与双边操作、RC/UC/UD 传输、设备设置(ibv_get_device_list、保护域、内存注册、完成队列、队列对)、工作请求与完成事件、RoCE 与 InfiniBand、使用 perftest 进行基准测试,以及 Rust rdma-sys 绑定。
适用场景
- 构建超低延迟的存储或数据库网络
- 绕过 CPU 进行远程内存访问(单边 RDMA)
- 在以太网网络结构上设置 RoCE
- 使用 perftest 工具对网络结构进行基准测试
- 将 RDMA 集成到 MPI 或自定义 RPC 系统中
- 调试 RDMA 连接和完成事件错误
工作流
1. RDMA 概念
RDMA stack
├── Application (libibverbs)
├── Kernel RDMA driver (mlx5, rdma_rxe)
├── NIC/HCA hardware
└── Fabric (InfiniBand or RoCE/Ethernet)
Operation types
├── Two-sided: Send/Recv (both sides participate)
└── One-sided: RDMA Read/Write (remote CPU not involved)
传输类型:
| 类型 | 可靠 | 连接方式 | 用途 |
|---|---|---|---|
| RC(可靠连接) | 是 | 1:1 QP 对 | 通用 |
| UC(不可靠连接) | 否 | 1:1 | 类似多播 |
| UD(不可靠数据报) | 否 | 多对多 | MPI、发现 |
2. 设备发现
# List RDMA devices
ibv_devices
ibv_devinfo
# RoCE link status
rdma link show
ibstat
# Perftest prerequisites
modprobe ib_umad
3. 最简 libibverbs 设置
#include <infiniband/verbs.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int num_devices;
struct ibv_device **dev_list = ibv_get_device_list(&num_devices);
if (!dev_list || num_devices == 0) {
fprintf(stderr, "No RDMA devices\n");
return 1;
}
struct ibv_context *ctx = ibv_open_device(dev_list[0]);
struct ibv_pd *pd = ibv_alloc_pd(ctx);
char buf[4096];
struct ibv_mr *mr = ibv_reg_mr(pd, buf, sizeof(buf),
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);
struct ibv_cq *cq = ibv_create_cq(ctx, 10, NULL, NULL, 0);
struct ibv_qp_init_attr qp_attr = {
.send_cq = cq,
.recv_cq = cq,
.cap = { .max_send_wr = 10, .max_recv_wr = 10,
.max_send_sge = 1, .max_recv_sge = 1 },
.qp_type = IBV_QPT_RC,
};
struct ibv_qp *qp = ibv_create_qp(pd, &qp_attr);
printf("QP num %u, MR lkey %u rkey %u\n",
qp->qp_num, mr->lkey, mr->rkey);
ibv_destroy_qp(qp);
ibv_dereg_mr(mr);
ibv_destroy_cq(cq);
ibv_dealloc_pd(pd);
ibv_close_device(ctx);
ibv_free_device_list(dev_list);
return 0;
}
gcc -o rdma_setup rdma_setup.c -libverbs
4. 连接设置(RC)
RC 需要通过带外方式交换 QP 信息(lid、gid、qp_num、psn):
// Simplified: exchange via TCP socket before RDMA
struct qp_info {
uint16_t lid;
uint32_t qpn;
uint32_t psn;
union ibv_gid gid;
};
// Modify QP to INIT → RTR → RTS states
struct ibv_qp_attr attr = { .qp_state = IBV_QPS_INIT, ... };
ibv_modify_qp(qp, &attr, IBV_QP_STATE | IBV_QP_PKEY_INDEX | ...);
// RTR: set path_mtu, dest_qp_num, rq_psn, ah_attr
// RTS: set sq_psn, timeout, retry_cnt
使用 rdmacm(librdmacm)简化连接管理:
#include <rdma/rdma_cma.h>
// rdma_create_event_channel, rdma_connect, rdma_accept
5. 发送/接收(双边)
// Post receive
struct ibv_recv_wr recv_wr = {}, *bad_wr;
struct ibv_sge recv_sge = { .addr = (uint64_t)recv_buf, .length = 4096, .lkey = mr->lkey };
recv_wr.wr_id = 1;
recv_wr.sg_list = &recv_sge;
recv_wr.num_sge = 1;
ibv_post_recv(qp, &recv_wr, &bad_wr);
// Post send
struct ibv_send_wr send_wr = {}, *bad_send;
struct ibv_sge send_sge = { .addr = (uint64_t)send_buf, .length = msg_len, .lkey = mr->lkey };
send_wr.wr_id = 2;
send_wr.opcode = IBV_WR_SEND;
send_wr.sg_list = &send_sge;
send_wr.num_sge = 1;
ibv_post_send(qp, &send_wr, &bad_send);
// Poll completion
struct ibv_wc wc;
while (ibv_poll_cq(cq, 1, &wc) == 0);
if (wc.status != IBV_WC_SUCCESS)
fprintf(stderr, "WC error: %s\n", ibv_wc_status_str(wc.status));
6. RDMA 写入(单边)
struct ibv_send_wr wr = {}, *bad;
struct ibv_sge sge = { .addr = (uint64_t)local_buf, .length = len, .lkey = local_mr->lkey };
wr.wr_id = 3;
wr.opcode = IBV_WR_RDMA_WRITE;
wr.send_flags = IBV_SEND_SIGNALED;
wr.sg_list = &sge;
wr.num_sge = 1;
wr.wr.rdma.remote_addr = remote_addr; // from peer exchange
wr.wr.rdma.rkey = remote_rkey;
ibv_post_send(qp, &wr, &bad);
不会中断远程 CPU——数据会直接出现在远程内存中。
7. RoCE 与 InfiniBand
| InfiniBand | RoCE | |
|---|---|---|
| 物理网络 | 专用 IB 网络结构 | 以太网(无损 DCB/PFC) |
| LID/GID | 两者都有 | 主要使用 GID(类似 IPv6) |
| 设置 | 子网管理器 | DCB 配置、PFC、ECN |
# RoCEv2 GID
cat /sys/class/infiniband/mlx5_0/ports/1/gids/3
8. 使用 perftest 进行基准测试
# Server
ib_send_bw -d mlx5_0 -x 3
# Client
ib_send_bw -d mlx5_0 -x 3 <server_ip>
# Latency
ib_send_lat -d mlx5_0 <server_ip>
# RDMA write bandwidth
ib_write_bw -d mlx5_0 <server_ip>
9. Rust rdma-sys
# Cargo.toml
rdma-sys = "0.1"
使用安全抽象封装 libibverbs,或使用 async-rdma crate 获取更高级别的 API。
常见问题
| 现象 | 原因 | 解决方法 |
|---|---|---|
ibv_reg_mr 失败 | 内存限制或权限错误 | 检查 ulimit -l;设置访问标志 |
WC 状态为 rem_inv_req | rkey/addr 错误 | 重新连接后重新交换 MR 信息 |
| QP 进入 RTS 状态失败 | PSN 或路径错误 | 确认 lid/gid 匹配;检查子网管理器 |
| RoCE 丢包 | 交换机未启用 PFC | 启用无损以太网;配置 DCQCN |
| 带宽低 | 消息尺寸过小 | 增大 MTU;使用更大的 WR |
| 找不到设备 | 驱动未加载 | modprobe mlx5_ib;检查 ibv_devices |
相关技能
skills/hpc/mpi— MPI 通常通过 UCX/IB verbs 使用 RDMAskills/async-io/dpdk— 另一种用户态网络方案skills/allocators/numa-programming— NUMA 本地 MR 注册skills/profilers/linux-perf— CPU 侧 RDMA 完成事件轮询skills/kernel/device-drivers— RDMA 驱动内部机制skills/virtualization/qemu-kvm— 用于 RDMA 的 SR-IOV VF 直通
评论
支持 Markdown