news 2026/11/3 19:27:39

RoCE V2 Read Request 数据包全解剖:ACK、NAK 与握手流程一文讲透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RoCE V2 Read Request 数据包全解剖:ACK、NAK 与握手流程一文讲透

RoCE V2 Read Request 数据包全解剖:ACK、NAK 与握手流程一文讲透

做 RDMA 绕不开 RoCE V2,做 RoCE V2 绕不开 Read Request。

本文从数据包结构出发,把 Read Request、ACK、NAK 三种包的字段逐一拆解,再结合 FPGA 硬件实现讲清楚通信握手全流程。读完这篇,你应该能对着 Wireshark 抓包或 RTL 波形,独立排查 RoCE Read 事务的每一个细节。


一、先搞清楚角色:Requester 与 Responder

RoCE 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 Word5

2.2 BTH(Base 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分区键,常用0x8001
Word 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 Request
  • QP Number:决定哪个 Responder 连接处理此请求
  • PSN:后续所有响应包的序列号起点

2.3 RETH(RDMA 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 Address:Responder 根据此地址计算 DMA 读取的起始位置
  • R_Key:安全机制,防止越权访问(轻量级 FPGA 实现中可能省略验证)
  • DMA Length:决定了 Responder 需要回传多少数据

三、ACK 与 NAK 数据包

Read 事务完成后,Requester 需要确认收到数据。确认机制通过 ACK 或 NAK 包实现。

3.1 ACK/NAK 共用 Opcode

冷知识:ACK 和 NAK 使用相同的 Opcode——0x11(Acknowledge)。

这意味着你不能仅凭 BTH Word 0 的 opcode 字段来区分 ACK 和 NAK。

3.2 AETH 头部 — 区分 ACK/NAK 的关键

ACK/NAK 包在 BTH 之后紧跟一个AETH(Acknowledge Extended Transport Header),4 字节:

Word 3: { Syndrome[7:0], Reserved[7:0], MSN[15:0] }
字段位宽含义
Syndrome8 bitACK/NAK 标志 + 语义值
Reserved8 bit保留
MSN16 bitMessage Sequence Number

3.3 Syndrome 字段解码规则

Syndrome 最高位(bit 7)是 ACK/NAK 的分水岭:

Syndrome[7]Syndrome 范围类型值的含义
00x00~0x7FACK值 = 接收方返回的credits 数量
10x80~0xFFNAK值 =NAK 原因代码

常见 NAK 原因代码:

代码含义
0x80RNR(Receiver Not Ready)— 接收方资源不足
0x81远程访问错误 — 地址或权限问题
0x82远程无效请求

3.4 PSN 的位置

无论是 ACK 还是 NAK,PSN 始终位于 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 正常流程(无 NAK)

Requester Responder │ │ │─── Read Request (0x0C) ───►│ ① 发起请求 │ [VA, R_Key, DMA_Len] │ │ │── 解析 RETH │ │── 计算 DMA 地址 │ │── 从本地内存读数据 │ │── 分包:每包 ≤ 4096B │ │ │◄── Read Response (0x0D) ───│ ② 第一包数据 │ [PSN=起始PSN] │ │◄── Read Response (0x0D) ───│ ③ 第二包数据 │ [PSN=起始PSN+1] │ │◄── ... │ │◄── Read Response (Last) ───│ ④ 最后一包 │ │ │─── ACK (0x11) ────────────►│ ⑤ 确认收到 │ [Syndrome=credits] │ │ │── resp_done │ │

4.2 带 NAK 的重传流程

Requester Responder │ │ │─── Read Request ──────────►│ ① 发起请求 │ │── DMA 读 + 分包发送 │◄── Read Response #0 ───────│ ② 第一包 │◄── Read Response #1 ───────│ ③ 第二包(传输错误/丢包) │ │ │─── NAK (0x11) ────────────►│ ④ 请求重传 │ [Syndrome=0x80+, │ │ 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 个 Word:Payload_Size + BTH(3W) + AETH(1W)hdr_tlast握手完成
S_NEXT包索引 +1,判断是否还有后续包有包→S_DMA;无包→S_WAIT_ACK
S_WAIT_ACK启动超时计时器,等待 ACK 或 NAK超时→resp_done;NAK→S_DMA 重传

4.4 握手关键细节

1. inp_ready 的流控逻辑

assign inp_ready = (state == S_IDLE) && fifo_space_ok;
  • 只有 S_IDLE 且 FIFO 有空间时才拉高inp_ready
  • NAK 也受背压约束: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_pkts=1)时,首包即末包,需特殊处理
  • 硬编码 4096 会在数据不足时发送错误内容

3. PSN 递增规则

  • Read Response 的 PSN = 起始 PSN + 包索引
  • 每发一包,PSN 自增 1
  • NAK 重传时,PSN 回退到指定值重新发送

4. 超时机制

localparam ACK_TIMEOUT_CYCLES = 125000; // 1ms @ 125MHz
  • S_WAIT_ACK 状态启动计数器
  • 超时未收到 ACK/NAK → 认为事务完成,拉高resp_done
  • 超时值需根据网络 RTT 合理设置

五、包大小与分包策略

5.1 为什么是 4096 字节?

RoCE V2 Read Response 的单包最大 Payload 通常为4096 字节(4KB),原因:

  • 与内存页大小对齐,方便 DMA 对齐访问
  • 以太网 MTU(1500B)限制下,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,末包 1808B)
  • DMA_Length = 4096 → 1 包

5.3 包头结构(FPGA 实现)

每包响应前需发送 20 字节包头(5 个 32-bit Word):

Word内容说明
Word 0{19'd0, pkt_payload}本包 Payload 大小
Word 1BTH Word 0Opcode =0x0D(Read Response)
Word 2BTH Word 1QP Number
Word 3BTH Word 2PSN
Word 4AETHSyndrome + MSN(hdr_tlast)

六、实战调试要点

6.1 用 Wireshark 抓包看什么

  1. Opcode 字段:确认0x0C(Read Request)和0x0D(Read Response)
  2. PSN 连续性:Response 的 PSN 应逐包递增,若出现跳跃说明有丢包
  3. AETH Syndrome:
    • 0x00~0x7F→ 正常 ACK
    • 0x80+→ NAK,关注原因码
  4. 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_IDLE,inp_ready应为 0

6.3 常见坑

问题根因解决
首包数据错误DMA 大小硬编码 4096,实际不足动态计算min(4096, remaining)
NAK 后状态混乱NAK 在 FIFO 满时被误消费inp_ready必须包含fifo_space_ok
PSN 不连续包索引计算错误PSN = start_psn + pkt_idx
超时不触发计数器位宽不够或条件错误确认ACK_TIMEOUT_CYCLES与时钟频率匹配

七、总结

RoCE V2 Read 事务的核心可以用三句话概括:

  1. Read Request 是"订单":告诉 Responder 从哪读、读多少、用哪个 QP
  2. Read Response 是"发货":按 4KB 分包,每包带独立 PSN,包头含 BTH + AETH
  3. ACK/NAK 是"签收/拒收":共用 Opcode0x11,靠 Syndrome 最高位区分;NAK 触发重传

在 FPGA 硬件实现中,状态机的核心设计原则是:先 DMA 读数据到 FIFO,再发包头通知下游,整个流程受fifo_space_ok流控保护,确保不丢命令、不发错数据。


作者:FPGA 工程师实战笔记 | 基于安路 PH1 FPGA 验证

参考工程:gitee.com/mstar_ypc/mstar-collect-fpga

技术博客:CSDN - 幻智星

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 19:27:12

AdMergeX 获信通院多项认可,市场部负责人受聘铸基计划技术专家

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/3 19:26:14

Docker Image-- 镜像命令详解与使用示例

目录 1. Docker 镜像是什么 2. 镜像命令详解 2.1 docker images 2.2 docker tag 2.3 docker pull 2.4 docker push 2.5 docker rmi 2.6 docker save 2.7 docker load 2.8 docker image inspect 2.9 docker history 2.10 docker image prune 2.11 docker build 2…

作者头像 李华
网站建设 2026/11/3 19:24:42

智能工厂梯度建设中的边缘计算网关架构设计与工程实践

摘要: 智能工厂梯度建设对工业现场数据采集、业务系统互通和边缘应用提出了逐步提高的要求。不同阶段需要解决的问题存在差异,不能简单通过增加工业网关数量或提高通信带宽完成升级。边缘计算网关的部署应基于设备接口、采集负载、数据模型、网络条件和业…

作者头像 李华
网站建设 2026/11/3 19:24:41

〖AI物流落地 03〗强化学习驱动的动态重路由:当港口拥堵时,系统如何完成秒级自救

一、静态路由在中断面前是“盲的”跨境干线和城际运输的路由,传统上依赖静态的路由表或每日一次的离线规划。这套机制在路网稳定时够用,但面对港口拥堵、突发封路、极端天气时,静态路由是“盲的”——它不知道前方已经堵死,仍然把…

作者头像 李华
网站建设 2026/11/3 19:24:39

续篇-播客文字笔记整理工具做成WorkBuddy技能

前言 上篇文章《播客文字笔记整理工具》发出来之后,发现我只用到了转写,整理成笔记还是用的gemini聊天窗口,记笔记用onenote,听播客用浏览器,感觉很割裂。这两个月我把这条链路重新实现了一遍——这次不写桌面应用&am…

作者头像 李华