3. 内存注册与注销
任务目标
编写一个最小可运行的RDMA内存注册程序,调用ibv_reg_mr注册一块内存缓冲区,打印返回的lkey、rkey及访问权限,随后调用ibv_dereg_mr注销并验证返回值,以确认注册/注销流程正确。
环境依赖
- Linux系统,已安装
libibverbs-dev(或等价RDMA用户态库) - 具备RDMA网卡(或使用软RoCE环境,如
rdma_rxe内核模块) - 编译命令:
gcc -o mr_demo mr_demo.c -libverbs
关键完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <infiniband/verbs.h>
#define BUFFER_SIZE 4096
#define ACCESS_FLAGS (IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE)
int main() {
struct ibv_device **dev_list;
struct ibv_context *ctx = NULL;
struct ibv_pd *pd = NULL;
struct ibv_mr *mr = NULL;
char *buf = NULL;
int num_devices, ret = 0;
// 1. 获取设备列表
dev_list = ibv_get_device_list(&num_devices);
if (!dev_list || num_devices < 1) {
fprintf(stderr, "未找到RDMA设备\n");
return 1;
}
// 2. 打开第一个可用设备
ctx = ibv_open_device(dev_list[0]);
if (!ctx) {
fprintf(stderr, "打开设备失败\n");
ibv_free_device_list(dev_list);
return 1;
}
ibv_free_device_list(dev_list);
// 3. 分配保护域
pd = ibv_alloc_pd(ctx);
if (!pd) {
fprintf(stderr, "分配保护域失败\n");
ibv_close_device(ctx);
return 1;
}
// 4. 分配并填充内存缓冲区
buf = malloc(BUFFER_SIZE);
if (!buf) {
fprintf(stderr, "内存分配失败\n");
ibv_dealloc_pd(pd);
ibv_close_device(ctx);
return 1;
}
memset(buf, 0xAB, BUFFER_SIZE);
// 5. 注册内存区域
mr = ibv_reg_mr(pd, buf, BUFFER_SIZE, ACCESS_FLAGS);
if (!mr) {
fprintf(stderr, "内存注册失败\n");
free(buf);
ibv_dealloc_pd(pd);
ibv_close_device(ctx);
return 1;
}
// 6. 打印注册结果
printf("内存注册成功:\n");
printf(" 缓冲区地址: %p\n", buf);
printf(" 缓冲区长度: %d 字节\n", BUFFER_SIZE);
printf(" lkey: 0x%x\n", mr->lkey);
printf(" rkey: 0x%x\n", mr->rkey);
printf(" 访问权限: 0x%x (LOCAL_WRITE=%s, REMOTE_READ=%s, REMOTE_WRITE=%s)\n",
ACCESS_FLAGS,
(ACCESS_FLAGS & IBV_ACCESS_LOCAL_WRITE) ? "是" : "否",
(ACCESS_FLAGS & IBV_ACCESS_REMOTE_READ) ? "是" : "否",
(ACCESS_FLAGS & IBV_ACCESS_REMOTE_WRITE) ? "是" : "否");
// 7. 注销内存区域
ret = ibv_dereg_mr(mr);
if (ret != 0) {
fprintf(stderr, "内存注销失败, 返回值: %d\n", ret);
free(buf);
ibv_dealloc_pd(pd);
ibv_close_device(ctx);
return 1;
}
printf("内存注销成功\n");
// 8. 清理资源
free(buf);
ibv_dealloc_pd(pd);
ibv_close_device(ctx);
return 0;
}
运行与验证
- 编译:
gcc -o mr_demo mr_demo.c -libverbs - 运行:
./mr_demo - 预期输出(示例,实际值因设备而异):
内存注册成功:
缓冲区地址: 0x55f3a2c1a260
缓冲区长度: 4096 字节
lkey: 0x3e1
rkey: 0x3e1
访问权限: 0x7 (LOCAL_WRITE=是, REMOTE_READ=是, REMOTE_WRITE=是)
内存注销成功
通过判定标准:
- 程序退出码为0,且依次打印“内存注册成功”和“内存注销成功”;
lkey与rkey均为非零值(若为零表示注册异常);- 访问权限值等于
0x7(即三个标志位全部置位),与代码中设置的ACCESS_FLAGS一致; - 注销后无错误输出,资源正常释放。
常见问题
- 未找到RDMA设备:确认内核已加载
rdma_rxe或硬件驱动,可用ibv_devices命令检查。 - 注册失败:检查缓冲区指针是否有效、长度是否为正、保护域是否有效;若使用软RoCE,确认
rdma_rxe模块已正确绑定网络接口。 - lkey/rkey为0:说明注册未成功或设备不支持,检查
ibv_reg_mr返回值是否为NULL。