RoCE V2 Read Request 数据包全解剖ACK、NAK 与握手流程一文讲透做 RDMA 绕不开 RoCE V2做 RoCE V2 绕不开 Read Request。本文从数据包结构出发把 Read Request、ACK、NAK 三种包的字段逐一拆解再结合 FPGA 硬件实现讲清楚通信握手全流程。读完这篇你应该能对着 Wireshark 抓包或 RTL 波形独立排查 RoCE Read 事务的每一个细节。一、先搞清楚角色Requester 与 ResponderRoCE V2 的 RDMA Read 操作涉及两端角色职责类比Requester发起方发送 Read Request等待数据回填像 HTTP 客户端发 GET 请求Responder响应方收到 Read Request从本地内存读数据分包回传像 HTTP 服务器返回响应体关键点Read 操作的数据流向是Responder → Requester但控制流的发起者是 Requester。这一点和 Write 操作正好相反。二、Read Request 数据包结构Read Request 是 RoCE V2 中最重的控制包之一它携带了 Responder 执行读操作所需的全部信息。2.1 包格式总览┌─────────┬─────────┬─────────┬─────────┬─────────┐ │ BTH │ RETH │ ICRC │ │ │ │ (12B) │ (16B) │ (4B) │ │ │ └─────────┴─────────┴─────────┴─────────┴─────────┘ Word0 Word3 Word6 Word1 Word4 Word2 Word52.2 BTHBase Transport Header— 12 字节BTH 是所有 RoCE V2 包的公共头部Read Request 也不例外。Word位域字段含义Word 0[31:24]Opcode0x0C— RDMA Read Request[23]SSolicited Event通常为 0[22:20]Mig迁移标志通常为 0[19:16]Pad尾部填充字节数[15:10]TVer传输版本号通常为 0[9:0]Partition Key分区键常用0x8001Word 1[31]F/R保留位[30:28]保留—[27:24]保留—[23:0]QP Number目标 QP 号Responder 据此匹配连接Word 2[31]AAcknowledge Request 位Read 必须为 1[30:24]保留—[23:0]PSN起始包序列号整个 Read 事务的锚点重点字段Opcode 0x0C唯一标识这是 Read RequestQP Number决定哪个 Responder 连接处理此请求PSN后续所有响应包的序列号起点2.3 RETHRDMA Extended Transport Header— 16 字节RETH 是 Read Request 特有的扩展头部告诉 Responder “从哪里读、读多少”。Word位域字段含义Word 3[63:0]Virtual Address目标虚拟地址Responder 的内存偏移Word 4[31:8]R_Key远程内存注册键用于权限验证[7:0]保留—Word 5[31:0]DMA Length请求读取的字节数Word 6[31:0]保留Read Request 中未使用重点字段Virtual AddressResponder 根据此地址计算 DMA 读取的起始位置R_Key安全机制防止越权访问轻量级 FPGA 实现中可能省略验证DMA Length决定了 Responder 需要回传多少数据三、ACK 与 NAK 数据包Read 事务完成后Requester 需要确认收到数据。确认机制通过 ACK 或 NAK 包实现。3.1 ACK/NAK 共用 Opcode冷知识ACK 和 NAK 使用相同的 Opcode——0x11Acknowledge。这意味着你不能仅凭 BTH Word 0 的 opcode 字段来区分 ACK 和 NAK。3.2 AETH 头部 — 区分 ACK/NAK 的关键ACK/NAK 包在 BTH 之后紧跟一个AETHAcknowledge Extended Transport Header4 字节Word 3: { Syndrome[7:0], Reserved[7:0], MSN[15:0] }字段位宽含义Syndrome8 bitACK/NAK 标志 语义值Reserved8 bit保留MSN16 bitMessage Sequence Number3.3 Syndrome 字段解码规则Syndrome 最高位bit 7是 ACK/NAK 的分水岭Syndrome[7]Syndrome 范围类型值的含义00x00~0x7FACK值 接收方返回的credits 数量10x80~0xFFNAK值 NAK 原因代码常见 NAK 原因代码代码含义0x80RNRReceiver Not Ready— 接收方资源不足0x81远程访问错误 — 地址或权限问题0x82远程无效请求3.4 PSN 的位置无论是 ACK 还是 NAKPSN 始终位于 BTH Word 2 的低 24 位ACK 的 PSN表示我已成功收到 PSN 及之前的所有包NAK 的 PSN表示请从 PSN 指定的包开始重传3.5 ACK/NAK 包完整格式ACK 包: ┌─────────┬─────────┬─────────┬─────────┬─────────┐ │ BTH │ BTH │ BTH │ AETH │ ICRC │ │ Word 0 │ Word 1 │ Word 2 │ Word 3 │ Word 4 │ │ 0x11 │ QP Num │ PSN │ Syndrome│ │ └─────────┴─────────┴─────────┴─────────┴─────────┘ NAK 包: 结构完全相同仅 Syndrome[7]1四、通信握手全流程Read 事务的完整握手流程涉及多个来回下面从时序角度逐步拆解。4.1 正常流程无 NAKRequester Responder │ │ │─── Read Request (0x0C) ───►│ ① 发起请求 │ [VA, R_Key, DMA_Len] │ │ │── 解析 RETH │ │── 计算 DMA 地址 │ │── 从本地内存读数据 │ │── 分包每包 ≤ 4096B │ │ │◄── Read Response (0x0D) ───│ ② 第一包数据 │ [PSN起始PSN] │ │◄── Read Response (0x0D) ───│ ③ 第二包数据 │ [PSN起始PSN1] │ │◄── ... │ │◄── Read Response (Last) ───│ ④ 最后一包 │ │ │─── ACK (0x11) ────────────►│ ⑤ 确认收到 │ [Syndromecredits] │ │ │── resp_done │ │4.2 带 NAK 的重传流程Requester Responder │ │ │─── Read Request ──────────►│ ① 发起请求 │ │── DMA 读 分包发送 │◄── Read Response #0 ───────│ ② 第一包 │◄── Read Response #1 ───────│ ③ 第二包传输错误/丢包 │ │ │─── NAK (0x11) ────────────►│ ④ 请求重传 │ [Syndrome0x80, │ │ PSN重传起始PSN] │ │ │── 收到 NAK │ │── 重新 DMA 读 │ │── 重新发包头 数据 │◄── Read Response #1 ───────│ ⑤ 重传第二包 │◄── Read Response #2 ───────│ ⑥ 继续后续包 │ │ │─── ACK ───────────────────►│ ⑦ 确认 │ │4.3 FPGA 硬件状态机实现在实际 FPGA 实现中Responder 端的握手由状态机驱动。以下是典型的五状态设计┌──────────┐ ┌────────►│ S_IDLE │◄──────────────┐ │ │ 等待输入 │ │ │ └────┬─────┘ │ │ │ Read Request/NAK │ │ │ fifo_space_ok │ │ ▼ │ │ ┌──────────┐ │ │ │ S_DMA │ │ │ │ 发起DMA读 │ │ │ └────┬─────┘ │ │ │ rctrl_done │ │ ▼ │ │ ┌──────────┐ │ │ │ S_HDR │ │ │ │ 发包头5W │ │ │ └────┬─────┘ │ │ │ hdr 全发完 │ │ ▼ │ │ ┌──────────┐ │ │ │ S_NEXT │── 还有包 ──────┘ │ │ 检查下一包│ │ └────┬─────┘ │ │ 全部发完 │ ▼ │ ┌──────────┐ │ │S_WAIT_ACK│── NAK ──► 回到 S_DMA 重传 │ │ 等确认/超时│ │ └────┬─────┘ │ │ 超时 / ACK └──────────────┘ resp_done各状态职责状态动作退出条件S_IDLE等待输入 FIFO 命令检查fifo_space_ok收到 Read Request 或 NAK且 FIFO 有空间S_DMA发起 DDR 读命令传输大小 min(4096, 剩余长度)rctrl_done脉冲S_HDR发送 5 个 WordPayload_Size BTH(3W) AETH(1W)hdr_tlast握手完成S_NEXT包索引 1判断是否还有后续包有包→S_DMA无包→S_WAIT_ACKS_WAIT_ACK启动超时计时器等待 ACK 或 NAK超时→resp_doneNAK→S_DMA 重传4.4 握手关键细节1. inp_ready 的流控逻辑assign inp_ready (state S_IDLE) fifo_space_ok;只有 S_IDLE 且 FIFO 有空间时才拉高inp_readyNAK 也受背压约束FIFO 满时NAK 保留在输入 FIFO 中不消费这避免了在 DDR 数据尚未读出时误接收新命令2. DMA 传输大小计算// 非最后一包: 4096 字节 // 最后一包: total_len % 4096 (若为 0 则仍为 4096) wire [12:0] dma_xfer_size (next_pkt_idx r_num_pkts - 1) ? (r_total_len[12:0] 0 ? 4096 : r_total_len[12:0]) : 4096;单包事务num_pkts1时首包即末包需特殊处理硬编码 4096 会在数据不足时发送错误内容3. PSN 递增规则Read Response 的 PSN 起始 PSN 包索引每发一包PSN 自增 1NAK 重传时PSN 回退到指定值重新发送4. 超时机制localparam ACK_TIMEOUT_CYCLES 125000; // 1ms 125MHzS_WAIT_ACK 状态启动计数器超时未收到 ACK/NAK → 认为事务完成拉高resp_done超时值需根据网络 RTT 合理设置五、包大小与分包策略5.1 为什么是 4096 字节RoCE V2 Read Response 的单包最大 Payload 通常为4096 字节4KB原因与内存页大小对齐方便 DMA 对齐访问以太网 MTU1500B限制下4KB 数据需要 IP 分片但 RDMA 网卡/硬件会自动处理4KB 是 FPGA 内部 FIFO 和 AXI Burst 的自然边界5.2 分包数量计算num_pkts ceil(DMA_Length / 4096)例如DMA_Length 8192 → 2 包DMA_Length 10000 → 3 包前两包 4096B末包 1808BDMA_Length 4096 → 1 包5.3 包头结构FPGA 实现每包响应前需发送 20 字节包头5 个 32-bit WordWord内容说明Word 0{19d0, pkt_payload}本包 Payload 大小Word 1BTH Word 0Opcode 0x0DRead ResponseWord 2BTH Word 1QP NumberWord 3BTH Word 2PSNWord 4AETHSyndrome MSNhdr_tlast六、实战调试要点6.1 用 Wireshark 抓包看什么Opcode 字段确认0x0CRead Request和0x0DRead ResponsePSN 连续性Response 的 PSN 应逐包递增若出现跳跃说明有丢包AETH Syndrome0x00~0x7F→ 正常 ACK0x80→ NAK关注原因码DMA Length与预期传输大小对比不一致说明 RETH 解析有误6.2 FPGA 波形调试检查清单inp_valid inp_ready同拍有效确认握手成功rctrl_start只拉高 1 拍rctrl_done在预期时间内返回hdr_tvalid hdr_tready每拍握手5 个 Word 连续发出tx_fifo_empty在最后一包发出后拉高resp_done脉冲宽度 1 个时钟周期NAK 到达时若state ! S_IDLEinp_ready应为 06.3 常见坑问题根因解决首包数据错误DMA 大小硬编码 4096实际不足动态计算min(4096, remaining)NAK 后状态混乱NAK 在 FIFO 满时被误消费inp_ready必须包含fifo_space_okPSN 不连续包索引计算错误PSN start_psn pkt_idx超时不触发计数器位宽不够或条件错误确认ACK_TIMEOUT_CYCLES与时钟频率匹配七、总结RoCE V2 Read 事务的核心可以用三句话概括Read Request 是订单告诉 Responder 从哪读、读多少、用哪个 QPRead Response 是发货按 4KB 分包每包带独立 PSN包头含 BTH AETHACK/NAK 是签收/拒收共用 Opcode0x11靠 Syndrome 最高位区分NAK 触发重传在 FPGA 硬件实现中状态机的核心设计原则是先 DMA 读数据到 FIFO再发包头通知下游整个流程受fifo_space_ok流控保护确保不丢命令、不发错数据。作者FPGA 工程师实战笔记 | 基于安路 PH1 FPGA 验证参考工程gitee.com/mstar_ypc/mstar-collect-fpga技术博客CSDN - 幻智星
阅读完成 · 觉得有帮助?