rdma data flow问题
1 SQ_doorbell如何产生? --RDMA网卡doorbell寄存器触发;
SQ_doorbell: SQ Doorbell是由主机驱动通过PCIe Memory Write触发,目标地址是网卡映射的Doorbell寄存器。
网卡作为PCIe Target接收写入后,解析出QPN和PID,拉取WQE执行操作;
Doorbell:是一种主机通知网卡的机制,通过写入网卡的特定寄存器(doorbell register),告知网卡SQ中有新的WR待处理;
SQ(Send Queue) Doorbell 是主机通过PCIe向网卡通知新工作请求(Work Request, WR)的关键机制。其产生和触发过程涉及主机驱动、PCIe事务和网卡;
产生流程:
1.主机驱动准备WR–work request;
–1.填充WQE:主机驱动在内存中填充WQE,用来描述WR的详细信息(操作类型、数据地址和长度等);
WQE位于SQ的环形缓冲区内,由驱动维护生产者指针–来指示下一个可用的WQE位置;
–2.更新生产者指针:驱动更新SQ的本地生产者指针;
2. 触发Doorbell写入
–1.驱动生成PCIE TLP write req;
Doorbell写入是一个PCIE Memory Write(TLP),目标地址是网卡bar空间中的Doorbell寄存器地址;
–2.驱动通过写入网卡的doorbell寄存器(映射到PCIe BAR空间),通知网卡有新的WQE存在;
该寄存器包含信息;
-1.QP编号:标志目标队列; -2.生产者指针:告诉网卡从哪个位置开始读取WQE;
3.网卡处理Doorbell
–1.PCIE target接受写请求
-1.网卡的PCIE EP接受Memory TLP write,解析出写入的Doorbell寄存器地址和数据(生产者指针);
–网卡可能通过MSI-X中断或者RR轮询机制感知Doorbell寄存器配置;
-2.读取WQE并执行
–网卡根据生产者指针从主机内存中读取新的WQE(通过DMA);
–执行WR–比如RDMA读写;
Doorbell寄存器存在RDMA网卡中,但是需要通过PCIE BAR空间暴露给主机CPU访问;
完整流程示例(RDMA网卡Doorbell触发):
主机驱动:
将WQE(Work Queue Entry)写入主机内存中的SQ环形缓冲区。
更新生产者指针(Producer Index)。
通过MMIO写入网卡BAR空间中的Doorbell寄存器地址(如BAR0 + 0x1000),携带QP编号和生产者指针。
PCIe传输:
主机生成PCIe Memory Write TLP(事务层包),目标地址为BAR映射的Doorbell寄存器物理地址。
网卡作为PCIe Endpoint接收该TLP。
网卡硬件:
解码TLP地址,确认是Doorbell寄存器写入。
根据生产者指针,发起DMA读取主机内存中的WQE。
执行WR(如发送数据包)。
一般该doorbell寄存器内信息是:qp_id 和生产者指针PID(WQE位置);
2 CPU如何访问网卡的Doorbell寄存器?
• 物理位置:Doorbell寄存器位于RDMA网卡的硬件逻辑中,是网卡控制器的一部分。
• 访问方式:主机(CPU)不能直接访问网卡内部的寄存器,因此需要通过PCIe的BAR(Base Address Register)空间将网卡中的寄存器映射到主机的内存地址空间(MMIO,Memory-Mapped I/O),使得主机可以通过内存读写指令(如mov或writel)间接操作这些寄存器。
1.什么是PCIE设备寄存器映射到PCIE bar空间?
–1.PCIE bar:
PCIe设备(如RDMA网卡)通过BAR向主机报告其需要的内存或I/O空间大小,并请求一段主机物理地址空间的映射。每个PCIe设备最多有6个BAR(BAR0~BAR5),每个BAR可以映射一段连续的地址空间。BAR空间可以配置为内存映射(MMIO)或I/O端口映射(现代设备通常使用MMIO)。
–2.RDMA网卡映射到CPU PCIE bar空间流程
–1.设备初始化:网卡硬件/固件 在PCIE枚举阶段声明其需要的bar空间大小和类型;
示例:一个RDMA网卡可能声明BAR0为64KB的MMIO空间,用于映射控制寄存器和Doorbell寄存器。
–2. 操作系统分配物理地址
操作系统为bar分配一段物理地址范围: (如0x1FA00000~0x1FA0FFFF),并将其映射到内核的虚拟地址空间。届时主机驱动程序通过ioremap()或pci_iomap()访问这段地址。
3.驱动访问网卡寄存器
–网卡设计文档定义doorbell寄存器在bar空间中的偏移量;驱动通过写入bar地址+偏移量来出发doorbell;
3.sq_doorbell_handle是解析doorbell寄存器获取QPN和PID,再通过dma_read拉取主机内存中具体的WQE;
PID:软件驱动通过doorbell下发的;
CID:QPC硬件维护更新;
3 为什么需要roce_qid_convert把local_qid转换成global_qid;
在sq_doorbell中解析到的qp_id(实质是local_qp_id)转成global_qp_id;–是为了实现支持虚拟化支持(多个虚拟机VF,每个VF的locla_qp_id可能会重复)、硬件资源隔离(网卡内部队列资源唯一标识可以按照global_qp_id来划分来做优先级调度等)、流控QoS等;
struct qid_map_entry {
uint16_t vf_id; // 虚拟机或功能标识(SR-IOV场景)
uint16_t local_qid;
uint32_t global_qid;
};
网卡硬件解析Doorbell,提取vf_id和local_qid,查询映射表得到global_qid。
4.WQE的format是什么?
WQE(Work Queue Entry,) 是RDMA(如Mellanox ConnectX、Intel E810)中主机软件(驱动/应用)与网卡硬件的关键交互媒介。它描述了需要硬件执行的操作(如数据传输、原子操作),由软件填充、硬件解析并执行。
• 1.WQE的典型格式;
–1.通用WQE头部
```c
struct mlx5_wqe_ctrl_seg {
__le32 opcode; // 操作类型(如RDMA_WRITE、SEND、ATOMIC)
__le32 qp_ds; // QP号(低24位) + WQE长度(高8位)
__le32 signature; // 可选,用于校验
__le32 fm_ce_se; // Flow Match、Completion Event等标志位
};
```
• 2.数据端–SQE;–描述待传输的数据地址和长度
struct mlx5_wqe_data_seg {
__le32 byte_count; // 数据长度
__le32 lkey; // 本地内存密钥(Memory Key,保护DMA访问)
__le64 addr; // 数据物理地址
};
3.rdma操作专用段
根据opcode不同,WQE可能包含额外字段(比如rmda_write/read):
struct mlx5_wqe_raddr_seg {
__le64 remote_addr; // 远程内存地址
__le32 rkey; // 远程内存密钥(Remote Key)
__le32 reserved;
};
5.WQE在网卡硬件中的处理流程?
1.软件/驱动填充WQE;
• 驱动在主机内存的SQ环形缓冲区中填充WQE,更新生产者指针-Pid;
struct mlx5_wqe *wqe = get_next_wqe(sq);
wqe->ctrl.opcode = MLX5_OPCODE_RDMA_WRITE;
wqe->data.addr = cpu_to_le64(data_phys_addr);
wqe->data.lkey = cpu_to_le32(mr->lkey);
2.触发doorbell
• 驱动通过PCIE TLP MemWR TLP来写入doorbell寄存器,通知网卡有新WQE;
• Doorbell信息:QP_id 和 Producer_id;
3.网卡DMA读取WQE
网卡通过PCIE MemRD TLP从主机内存读取WQE(地址:SQ_BASE + Offset(PI * WQE_SIZE))
4.网卡解析WQE执行RDMA操作
网卡解析WQE,执行发起RDMA packet操作;
完成后生成CQE(Completion Queue Entry)通知主机;
6.网卡读Host 内存–dma_read
当网卡需要从主机内存读取数据(如WQE)时,它会发起一个**PCIe Memory Read TLP(MemRd)请求,主机收到该请求后,通过CplD(Completion with Data)**返回数据。
• DMA Read是抽象概念,而MemRd/CplD是PCIe协议的具体实现形式。
• 在硬件描述中,工程师可能直接说“DMA Read”,但实际硬件行为是通过PCIe TLP完成的。
示例:网卡如何读取WQE
–1.网卡发起DMA Read;
网卡硬件解析Doorbell后,确定需要读取的WQE地址(主机内存地址);
网卡生成PCIE Memory Read TLP,包含:
• 目标地址:主机内存的物理地址:SQ_base + offset;
• 数据长度:(Pid-Cid) * WQE_SIZE; --Pid代表生产者指针;Cid代表消耗者指针;
–2.主机响应
1.主机PCIE Root Complex接收到MemRd请求,转发到内存控制器;
2.内存控制器读取主机内存中的数据,生成CPLD TLP,将WQE数据返回给网卡;
–3.网卡接收数据
• 网卡通过PCIE接口接收CPLD TLP,提取WQE数据并存入片上缓存,供后续硬件流水线来处理;
7.rdma网卡解析sq_wqe,再从主机拉取payload进行组装RoCE包发送出去;
大致整理流程如下;
整体流程概览:
主机驱动填充 WQE(描述RDMA操作) → 触发 Doorbell(通知网卡)。
网卡 DMA 读取 WQE(PCIe MemRd)→ 解析 WQE(操作类型、地址、长度等)。
网卡 DMA 读取 Payload(若数据未内联在WQE中)→ 封装 RDMA 报文(如RoCEv2)。
发送报文到网络(通过以太网接口)
详细分布流程(以rdma_write为示例)
S1:主机驱动准备WQE和payload;
WQE内容示例:
```c
struct mlx5_wqe_ctrl_seg {
__le32 opcode; // 操作码(如RDMA_WRITE)
__le32 qp_num; // QP号(低24位)
__le32 signature; // 校验字段
};
struct mlx5_wqe_raddr_seg {
__le64 remote_addr; // 远程内存地址
__le32 rkey; // 远程密钥(Remote Key)
};
struct mlx5_wqe_data_seg {
__le32 byte_count; // 数据长度
__le32 lkey; // 本地内存密钥(Local Key)
__le64 addr; // 本地数据物理地址
};
```
S2: 驱动触发Doorbell
驱动写入Doorbell寄存器(MemWR TLP),通知网卡有新WQE处理;
S3:网卡DMA读取WQE
• 网卡解析doorbell,提取QPN和PID; 通过QP Context来获取SQ的基地址和WQE size;
• 发起PCIE MemRD TLP: 从主机内存读取WQE(地址和长度:PID-CID);主机通过CPLD tlp返回数据;
S4:网卡解析WQE字段和拉取Payload
网卡发起第二次PCIE MemRD TLP,从主机内存读取payload(sge里字段);数据通过CPLD TLP返回网卡--payload.
S5: 封装RDMA报文(RoCE v2)
根据协议类型生成报文--RoCE v2(基于UDP/IP):
```c
| Ethernet | IP | UDP | InfiniBand BTH | RETH(RDMA Extended Transport Header) | Payload |
```
S6:发送报文到网络;
以RDMA Write为示例:
```c
主机驱动:
1. 填充 WQE(SQ中) → 2. 写 Doorbell → 3. 等待完成事件(CQE)。
网卡硬件:
1. 检测 Doorbell → 2. DMA 读 WQE → 3. DMA 读 Payload → 4. 封装报文 → 5. 发送。
```