一套最精简、能直接落地的 RDMA / RoCE v2 工程资料包,包含:关系再梳理、报文结构、FPGA 实现框架、x86 侧最简可用 C 代码、测试命令。
一、RDMA ↔ RoCE v2 关系(最终版)
- RDMA :一套远程直接内存访问技术标准(API + 语义)
- 零拷贝、内核旁路、CPU 不参与数据搬运
- RoCE :RDMA over Converged Ethernet,以太网承载 RDMA
- RoCE v1:L2 以太网,不可路由
- RoCE v2:L3 UDP/IP 封装,可路由,现在唯一实用版本
可以记成:
RDMA = 能力 RoCE v2 = 以太网环境下跑 RDMA 的报文格式
二、RoCE v2 报文封装结构
plaintext
以太网头 + IP头 + UDP头 + GRH + BTH + RDE + 载荷
- GRH:Global Routing Header(RoCE v2 特有,用于路由)
- BTH:Base Transport Header
- RDE:RDMA 扩展头(Send/Read/Write/Atomic)
特点:
- 就是一个标准 UDP 报文 ,端口默认 4791
- 普通交换机可转发,支持三层路由
- 无损网络建议开启 PFC / ECN(不强制,但延迟更稳)
三、FPGA 实现 RoCE v2 最小结构
你用 FPGA 做 RNIC(RDMA 网卡),核心就这几部分:
- PCIe DMA 引擎
- 与 x86 主机内存交互(QP 队列、WQE、CQE)
- QP 管理模块(Queue Pair)
- SQ + RQ:发送 / 接收队列
- CQ:完成队列
- RoCE v2 协议栈
- 封装 / 解封装 GRH/BTH/UDP/IP
- 校验和卸载
- 以太网 MAC/PCS
- 25G/100G 以太网时序处理
- 可靠传输控制(可选)
- ACK、重传、滑动窗口(RC 模式)
数据流:
plaintext
x86 提交 WQE → FPGA QP → 封装 RoCE v2 → 以太网发送
四、x86 侧 RDMA (ibverbs) 最简发送代码
依赖:libibverbs
c
运行
#include <infiniband/verbs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 1024
int main() {
struct ibv_device **dev_list;
struct ibv_context *ctx;
struct ibv_pd *pd;
struct ibv_mr *mr;
struct ibv_cq *cq;
struct ibv_qp *qp;
struct ibv_qp_init_attr qp_attr = {};
char *buf = malloc(BUF_SIZE);
struct ibv_wc wc;
int ret;
// 1. 打开 RDMA 设备
dev_list = ibv_get_device_list(NULL);
ctx = ibv_open_device(dev_list[0]);
ibv_free_device_list(dev_list);
// 2. 保护域 + 注册内存
pd = ibv_alloc_pd(ctx);
mr = ibv_reg_mr(pd, buf, BUF_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);
// 3. 创建 CQ + QP
cq = ibv_create_cq(ctx, 128, NULL, NULL, 0);
qp_attr.send_cq = cq;
qp_attr.recv_cq = cq;
qp_attr.qp_type = IBV_QPT_RC; // RC = 可靠连接
qp = ibv_create_qp(pd, &qp_attr);
// 4. QP 状态切换 (INIT->RTR->RTS)
// 略(需要对方 QP 信息,实际代码需交换 GID/QP 号)
// 5. 发送数据
memset(buf, 0x5a, BUF_SIZE);
struct ibv_sge sge = {
.addr = (uint64_t)buf,
.length = BUF_SIZE,
.lkey = mr->lkey
};
struct ibv_send_wr wr = {
.wr_id = 0x1234,
.sg_list = &sge,
.num_sge = 1,
.opcode = IBV_WR_SEND,
.send_flags = IBV_SEND_SIGNALED
};
struct ibv_send_wr *bad_wr;
ret = ibv_post_send(qp, &wr, &bad_wr);
// 6. 等待完成
while (ibv_poll_cq(cq, 1, &wc) < 1);
printf("RDMA Send 完成, status=%d\n", wc.status);
return 0;
}
编译:
bash
运行
gcc rdma_test.c -o rdma_test -libverbs
五、RDMA 常用操作(你和 FPGA 通信最常用)
- IBV_WR_SEND
- 主动发消息,对方需提前 posted recv
- IBV_WR_WRITE
- 直接写对方内存,对方 CPU 完全无感知
- 最适合 FPGA → x86 低延迟上行
- IBV_WR_READ
- 直接读对方内存
- Atomic
- 原子加 / 比较交换,用于同步
实时通信首选:WRITE + 少量 SEND 同步
六、测试 RDMA 延迟 / 带宽命令
安装:perftest
bash
运行
# 服务端(FPGA 或另一台机器)
ib_write_bw -d rdma0 -R # RoCE v2
ib_write_lat -d rdma0 -R
# 客户端
ib_write_bw -d rdma0 -R 192.168.1.100
ib_write_lat -d rdma0 -R 192.168.1.100
典型结果:
- 写延迟:1us 左右
- 抖动:< 100ns
- 100G 带宽可跑满
七、你接下来最该做的三件事
- 在 FPGA 上实现 RoCE v2 + QP + DMA
- x86 用
ibverbs跑 RDMA_WRITE 上行 - 配合之前的系统优化(isolcpus、关闭节能、巨页)