
干这行久了你会发现100G RDMA 这个词几乎已经和高性能网络绑定了。不管你是做存储加速、AI 训练集群还是搞数据中心网络卸载最终都要面对同一个问题怎么把 100G RDMA 这条链路真正跑起来。对 FPGA 工程师来说这既是机会也是挑战——机会在于 FPGA 可以把协议栈彻底打开按你的需求改挑战在于 RDMA 涉及 PCIe、DMA、队列管理、无损网络一堆东西任何一个环节掉链子整个环境就起不来。这篇文章就围绕“用 Xilinx FPGA 搭建 100G RDMA 测试环境”这条主线从 Vivado 里的 IP 配置开始讲一直到 PC 端通过 RDMA 网卡和 FPGA 真正互通、跑出带宽数据为止。适合手里有 UltraScale 系列板卡、想快速拥有一套可控的 100G RDMA 验证平台的开发者也适合准备做 RoCE v2 协议学习、FPGA 网络卸载设计的同学。整个过程我不会只贴配置截图而是把每一步背后的原理、踩过的坑、排查的思路一起写清楚。1. 先想明白这套环境到底在做什么1.1 RDMA 的三种形态为什么 FPGA 盯上了 RoCE v2RDMA 的全称是 Remote Direct Memory Access核心思想就是让数据从一台机器的内存直接搬到另一台机器的内存过程中 CPU 只负责下发命令不参与数据搬运。这个能力在高性能计算、分布式存储里极其值钱因为 CPU 介入越少延迟越低、带宽越容易打满。RDMA 的物理实现有三种主流路线InfiniBand、RoCERDMA over Converged Ethernet和 iWARP。InfiniBand 是专用网络性能最好但交换机、网卡都贵得离谱而且和普通以太网生态不互通。iWARP 走 TCP/IP 协议栈兼容性最好但 TCP 的重传和确认机制拖累了极致性能。RoCE v2 是一种让 RDMA 直接跑在以太网协议栈上的方案它把 RDMA 报文封装进 UDP/IP 里既能享受以太网的普及度又能拿到接近 InfiniBand 的性能。对 FPGA 来说RoCE v2 是唯一能自己动手把协议栈完全打开的路线因为报文格式、队列管理、重传逻辑都是你在 RTL 里面写的可控性在三种方案里是最高的。1.2 搭建这个测试环境的真实价值很多人会问测试 100G RDMA直接买一张 Mellanox 网卡插上不就完了为什么非要折腾 FPGA答案不是性能问题而是可控性和可定制性。商用 RDMA 网卡是一颗封闭的黑盒你能操作的只有驱动和配置接口协议细节、拥塞控制、流控策略都是厂商固件说了算。FPGA 方案把这些全打开了你可以插入自己的拥塞控制算法、修改重传策略、观测每一层协议的时序统计甚至把 RDMA 引擎和你的业务逻辑集成到同一个芯片里。这套测试环境真正解决的是下面这些实际需求一是验证你自己写的 RoCE v2 协议栈功能对不对、性能能达到什么水平二是在没有完整 InfiniBand 交换机的情况下用最普通的以太网线缆和设备互通三是给存储或者 AI 加速项目提供一个可以压测的 RDMA 数据通路。整个系统可以拆成两个大块FPGA 板卡负责把 RDMA 报文从 PCIe 搬到光口PC 端用支持 RoCE 的 100G 网卡作为对端两边通过光模块直连或者经过一层交换机互相对打。1.3 FPGA 方案和专用网卡的取舍在动手之前有必要把 FPGA 和专用网卡的差异摊开看这样才能理解后面每一步配置的出发点。维度商用 RDMA 网卡FPGA 方案协议栈固件固定无法修改RTL 完全开放可深度定制延迟极低但受固件处理路径限制可自行优化通常 1~3 微秒量级开发周期即插即用只需软件配置数月到一年不等取决于经验功耗与成本单卡功耗压力小但功能锁定单板功耗高但功能可无限扩展适用范围标准的存储、计算集群协议研究、网络卸载、异构加速我个人的建议是如果你只想要一个“能用的 RDMA 网络”直接上商用卡如果你想研究协议、做定制化网络设备或者把 RDMA 能力嵌入自己的加速卡中FPGA 路径值得投入。下面的实操内容全部基于 FPGA 路径。2. 硬件平台与 Vivado 工程搭建的关键选择2.1 板卡、光模块、线缆怎么选FPGA 板卡要跑 100G RDMA芯片至少要到 UltraScale 这一代因为 100G 需要的 GTY/GTM 高速收发器、PCIe Gen3x16 硬核、和足够规模的逻辑资源在 7 系列上会比较吃力。我这边测试用到的是 VCU118核心芯片是 VU9P正好覆盖 PCIe Gen3x16 和 100G 光口是很多原型验证板的选择。如果你手头是 Alveo U200/U250 这类自带 PCIe 和 QSFP28 的加速卡也可以走通同样的流程只是 Alveo 卡已经有成熟的 XDMA 骨架你只需要加 RDMA 引擎和以太网 MAC 部分。光模块选择上最常见的组合是 QSFP28 SR4 光模块加 MPO 光纤或者直接上 QSFP28 DAC 高速铜缆。这里有个非常实际的建议如果两台设备在同一个机柜里、距离不超过三米优先用 DAC 铜缆而不是光模块。DAC 少了一对光电转换环节出现光功率问题的概率低很多调试阶段能省下大量时间。如果非要用光模块一定注意发射端和接收端的标签方向QSFP28 里面四个通道的 Tx/Rx 方向不能搞反否则链路状态会一直在 Training 状态里转圈。2.2 时钟与复位规划的完整思路高速链路设计时钟是最容易翻车的地方。100G 以太网的线速率是对应四个 25.78125Gbps 的通道所以 GT reference clock 必须给 156.25MHz这个时钟源通常来自板上的可编程时钟芯片在 Vivado 工程里通过 IBUFDS_GTE4 原语进来。PCIe 部分则是单独一路 100MHz 参考时钟由主板 PCIe 插槽提供。我见过很多人把这两路时钟混为一谈结果 100G 链路 Ping 不通折腾半天发现是 GT 参考时钟频率不对。复位时序这里值得多说两句。CMAC IP 的复位顺序有严格要求一般是先复位 GT 和 PCS等 rx_pma_ready、tx_pma_ready 拉高之后再释放 MAC 主复位最后释放应用侧复位。在代码里我习惯把复位做成异步复位同步释放避免复位信号撤掉那一刻出现亚稳态这也是 FPGA 开发里“对 reg 打几拍”这个经典做法的重要场景。RDMA 引擎和 DMA 部分的复位则建议和 PCIe 的 perst# 信号关联起来保证主机上下电、驱动重载时 FPGA 侧能跟着做一次干净的重置。2.3 时钟与复位规划速查表时钟/复位来源频率/极性用途关键注意事项GT 参考时钟板上可编程时钟156.25MHz 差分100G 收发器必须干净抖动超标会直接导致误码PCIe 参考时钟主板 PCIe 槽100MHz 差分PCIe 硬核与 DMA通常由主板提供无需额外生成系统时钟板上晶振100MHz 单端应用逻辑、寄存器与 GT参考时钟分开避免干扰PCIe perst#主板复位信号低有效全链路复位连接 FPGA 全局复位逻辑3. 100G MAC 与 PCIe IP 配置最容易踩坑的两个 IP3.1 100G CMAC IP 配置要点Vivado 里用于 100G 以太网的 IP 是 CMAC100G Ethernet Subsystem它的核心角色是完成 MAC 层和 PCS/PMA 层的工作对外连接 GTY 收发器对内提供 AXI4-Stream 接口给上层协议。配置这个 IP 有几个关键点需要注意。线速率默认是 103.125Gbps对应四个通道各 25.78125Gbps。接口宽度如果选 512-bit 的 AXI4-Stream用户时钟是 322.265625MHz如果选 256-bit用户时钟是 644.53125MHz。这个用户时钟会直接影响后面 RDMA 引擎的时序收敛建议根据你 FPGA 上逻辑的紧张程度来选。我这边用 512-bit 接口时序压力小逻辑频率要求低对设计的稳定性更有帮助。Flow Control 选项在测试阶段建议先关闭。RoCE v2 在实际数据中心环境里依赖 PFCPriority Flow Control实现无损网络但那是整个网络交换机都要配合的事情。如果只是两台设备直连测试先在 IP 内部关掉 flow control后面有需要再手动配置 PFC。还有一个重点是“Include Shared Logic”选项。CMAC 的 GT 参考时钟、复位逻辑可以选择放在 IP 内部还是外部。我的习惯是如果整个工程只用一个 100G MAC直接勾选在 core 内部配置简单如果工程里未来会加第二个 100G MAC或者要和别的 GT 共享参考时钟选 external 并把 shared logic 放在顶层这样多个 core 能共用一套 GT 参考时钟和复位控制。3.2 PCIe IP 与地址空间规划PCIe 侧我用的是 XDMADMA/Bridge Subsystem for PCIe它同时提供了 PCIe 硬核和 DMA 引擎RDMA 引擎的寄存器可以通过 AXI-Lite 接口映射到主机地址空间数据通路则走 AXI4 接口。XDMA 配置里最关键的是 DMA 接口的选择有两种模式AXI Memory Mapped 和 AXI Streaming。AXI Memory Mapped 模式对 RDMA 来说更直接主机侧送出来的是一个带地址的读请求或者写请求FPGA 内部可以通过地址译码判断这是发给 QP 上下文、CQ 还是一个普通的数据缓冲。AXI Streaming 模式则适合数据流式的场景但 RDMA 本质上需要随机访问内存地址所以 Memory Mapped 更合适。BAR 空间方面我通常把 BAR0 定义为 64KB 的 AXI-Lite 寄存器空间用于 RDMA 状态机控制BAR2 作为大块的数据缓冲映射用于 DMA 访问。中断用 MSI-XRDMA 的完成事件通过 MSI-X 上报给主机驱动中断数量按队列对数来分配。3.3 从 bit 文件到链路 UP 的关键步骤配置好两个 IP 之后完整的流程是综合、布局布线、生成 bit 文件、下载到板卡、验证链路状态。这里面最容易出问题的环节是链路状态检查。bit 文件下载完成后先不要急着跑协议先在 Vivado 里把 CMAC 的状态信号拉出来看rx_pcs_ready、tx_pcs_ready 必须是高电平rx_pma_ready_done 也要置位。如果这些信号不齐问题基本锁定在光模块、线缆或者 GT 参考时钟上。这时候可以用 IBERT 做一次高速收发器的完整性测试验证 GT 通道的误码率。IBERT 是 Xilinx 自带的高速串行链路测试工具它能绕过 MAC 和所有上层逻辑直接在 GT 通道里打伪随机码并统计误码。我每次换光模块或者新板卡到货后的第一件事就是跑 IBERT链路干净了再进上层调试这个顺序能帮你把“物理层问题”和“协议层问题”彻底分开。4. RDMA 协议栈与数据通路联调4.1 QP 状态机与握手过程RDMA 的核心抽象是 QPQueue Pair一个 QP 由一条发送队列和一条接收队列组成。在 RoCE v2 实现里QP 的状态机有四个主要状态RESET、INIT、RTRReady to Receive和 RTSReady to Send。连接的建立过程就是在两端之间交换 QP 编号、GID、LID 等连接信息然后让两端各自把状态推进到 RTS。FPGA 作为 RDMA 设备时必须处理一个角色问题FPGA 侧是主动发起连接还是被动接受连接。测试阶段我更推荐让 PC 端作为主动方用 perftest 工具发起连接请求FPGA 侧作为被动方监听。原因很简单perftest 的握手逻辑是现成的FPGA 只需要正确响应这样能减少 FPGA 侧的协议代码复杂度。等到基本流程跑通再反过来让 FPGA 主动发起连接验证你的协议栈在主动路径上也没问题。QP 切换到 RTR 和 RTS 状态时FPGA 侧需要完成几件事初始化发送和接收队列、配置好 DMA 描述符、把指向接收缓冲区的地址写入相关寄存器。任何一步漏掉都会表现为对方发数据发不过来或者收到数据但没人接手。4.2 回环自测内部回环与外部回环在正式和 PC 对接之前一定要做回环自测。回环有两种内部回环和外部回环。内部回环是直接在 CMAC IP 内部把发送数据引回接收通路不经过物理光口用来验证 MAC 和上层协议逻辑。外部回环是插一个 QSFP28 环回模块或者在 DAC 线缆另一头接一个光模块环回环让数据真正走一遍收发器。实际操作时我的习惯是分两级验证先让 RDMA 引擎在内部回环模式下发送数据确认 DMA 描述符、QP 状态、报文封装这几层逻辑正确然后再用外部回环验证 GT 收发器和光模块链路。这里有个经验之谈如果内部回环能通但外部回环不通优先怀疑 GT 通道的极性、参考时钟的分配而不是怀疑上层协议如果外部回环能通但接 PC 不通那问题就在 PC 端配置或者线缆连接上。回环测试通过之后才能保证整个数据流从主机内存到 FPGA、再从 FPGA 光口出去的路径是完整的。4.3 Go-Back-N 重传机制的现实影响FPGA 实现 RoCE v2 时重传机制大多是 Go-Back-N原因很简单实现复杂度低不需要像选择性重传那样维护复杂的缓存管理和按序重排逻辑。Go-Back-N 的代价是丢一个包发送端会把从这个包之后的所有包全部重传一遍瞬时带宽会掉得很明显。这套行为放到测试环境里意味着你必须控制两条硬条件一是物理层的误码率要足够低二是网络不能有拥塞丢包。直连场景下只要光模块和线缆没问题满足这两条基本没压力。但如果你后续接入了交换机或者开启了 PFC 却没有正确配置优先级映射丢包事件引爆 Go-Back-N 重传之后你看到的带宽数字会非常难看。所以我建议在测试日志里把重传计数加进去一旦出现带宽异常先看重传次数这是定位问题最快的手段。5. PC 端互联配置与带宽测试5.1 Linux 侧配置 100G 网卡与 IP 地址PC 端我用的是 Mellanox ConnectX-5 双口 100G 网卡驱动是 mlx5_core。系统起来之后先用 lspci 确认网卡被识别然后加载驱动接着配置 IP。直连拓扑比较推荐FPGA 和 PC 网卡各自配一个静态 IP 地址放在同一个子网里。比如 FPGA 侧配 10.0.0.1/24PC 侧配 10.0.0.2/24。具体在 Linux 下的操作是下面几条命令# 确认网卡接口名通常是 enp3s0f0 或类似 ip link show # 配置 IP 并启动接口 ip addr add 10.0.0.2/24 dev enp3s0f0 ip link set enp3s0f0 up # 确认 RDMA 设备已经注册 rdma link show有一个细节值得注意RoCE v2 是承载在 UDP/IP 上的先用普通 ping 验证基本的 IP 连通性能省掉后面一大部分排查时间。但 ping 之前要把 MTU 调整好100G 网络建议把 MTU 改成 9000避免在 1500 字节默认 MTU 下出现分片问问题。分片问题在 RDMA 里尤其麻烦RDMA 报文通常很大一旦触发 IP 分片不少网卡和 FPGA 实现并不支持分片重组直接丢包。5.2 RDMA 子网与 GID 配置检查RoCE v2 报文的寻址依赖 GID而 GID 是从网卡的 IP 地址派生出来的。Mellanox 网卡驱动加载之后会自动给每个端口生成 GID但 GID index 不一定是 0你需要确认实际使用的 GID index 是多少。检查方法# 查看当前端口所有 GID show_gids # 或者用 rdma 命令 rdma link show mlx5_0FPGA 侧也要配置相应的 IP 地址和 GID index。这里最常见的坑是PC 网卡配置了多个 IP驱动自动生成多个 GID但 RDMA 客户端工具默认用了错误的 GID index导致 QP 握手失败。解决办法是显式指定 GID index比如 perftest 里的 -x 参数。FPGA 侧的 GID 同样要和你写入的源 IP 对应起来两边 GID 对不上连 QP 状态都推进不到 RTS。5.3 跑通 perftest 并解读结果perftest 是 RDMA 开发中最常用的带宽/延迟测试工具包它提供 ib_write_bw、ib_read_bw、ib_send_bw 等一系列命令。测试之前PC 端先启动服务端通常用 -s 参数监听再在另一台机器启动客户端发起流量。由于这里是 PC 和 FPGA 互联服务端和客户端的角色都只有 PC 这一侧FPGA 扮演的角色由你写的协议栈决定。# 服务端等待连接 ib_write_bw -d mlx5_0 -x 3 --report_gbits # 客户端连到 FPGA 侧假设 FPG A 的 IP 是 10.0.0.1 ib_write_bw -d mlx5_0 -x 3 --report_gbits 10.0.0.1输出结果里重点看两个数字BW带宽和 Latency延迟。直连 100G 网络的预期带宽应该在 90Gbps 以上因为 Ethernet 帧头、前导码、流控开销会吃掉一部分理论带宽。延迟方面小包比如 2 字节的写操作延迟应该在几微秒量级如果延迟飙升到几百微秒大概率是某个中间环节在做软件轮询或者 DMA 描述符回收不及时。我也遇到过一种情况ib_write_bw 显示带宽只有 20Gbps不是网络链路问题而是 PCIe 链路没跑满。检查 PC 端的 lspci -vvv确认当前 PCIe 链路工作在 Gen3 x16 还是 Gen3 x8。FPGA 板卡插在 x16 插槽里不等于实际协商出 x16我见过板卡插进 x8 插槽物理接口看着是 x16 的实际协商结果却大打折扣。6. 常见问题与排错实录6.1 链路起不来的五个原因100G 链路起不来是出现频率最高的故障也是最耗费时间的。我遇到的绝大多数情况可以归纳为五类GT 参考时钟没给对、光模块方向插反、DAC 线缆与模块速率不匹配、CMAC 的复位时序不满足、PCIe 链路未协商成功。参考时钟问题最常见的表现是 GT 的 txpma_ready 一直拉不高用 ILA 抓信号会发现 PLL 处于 unlock 状态。光模块方向问题在 MPO 光纤连接时特别常见MPO 光纤带极性换一根或者翻一个方向往往就解决了。DAC 线缆的问题出现在早期 25G 和 100G 混用的场景注意看线缆标签上的 rate 标识。PCIe 链路未协商成功的排查要去 BIOS 和 Linux 层确认FPGA 侧则检查 perst# 复位是否正常释放。强烈建议每排查一步都做记录把信号名、状态值、时间点写下来。高速链路问题经常互相嵌套有记录才能回溯。6.2 PCIe 枚举失败的排查FPGA 作为 PCIe 设备时如果主机 BIOS 里根本枚举不到设备先别急着怀疑 PCIe IP 配置。最应该查的是复位信号perst# 有没有拉高、FPGA 的 PCIe 硬核有没有成功初始化。Xilinx 的 PCIe IP 初始化需要几个条件参考时钟稳定、perst# 释放、配置逻辑加载完毕任何一个条件不满足都会让枚举失败。另一个容易被忽视的点是 PCIe 差分对极性。在布局布线时如果原理图把差分对的 P/N 接反了PCIe 链路也能协商成功但稳定性很差容易在高负载时掉链路。Xilinx 的 PCIe IP 内部自带极性检测和反转功能但有时候需要手动打开相关选项。遇到高负载掉链路的诡异问题先怀疑极性。6.3 常见问题速查表现象优先检查项处理思路link 一直 TrainingGT 参考时钟、光模块方向先查 156.25MHz 是否上板再换 DAC 或换光纤方向MAC 能 up 但 ping 不通MAC 地址配置、ARP 处理确认 FPGA 侧 MAC 和 IP 匹配PC 侧 arp 表是否有响应QP 连接失败GID index、QP 信息交换用 -x 指定 GID index核对交换的 QPN、LID 字段RDMA 带宽远低于预期PCIe 链路速率、描述符深度lspci -vvv 检查 PCIe 协商状态加大 DMA 描述符深度传输过程中大量重传PFC 配置、物理层误码直连不需 PFC先跑 IBERT 排除物理层误码RDMA 握手失败时PC 端 dmesg 里会出现 mlx5 相关的报错信息大部分时候错误信息会直接告诉你是 QP 状态不匹配还是 GID 配置不对。FPGA 侧则要靠逻辑分析仪抓 QP 状态机的跳转条件定位是哪个字段没对上。这个联动排查的过程很锻炼人但逻辑清晰的话半天内能解决大部分问题。6.4 一个小技巧用 10G 网卡做预联调再分享一个很实用的技巧。如果你觉得第一次就把 100G 物理链路调到干净状态有压力可以先在 PC 端插一张 10G 网卡配合 FPGA 板卡上的 SFP 口做预联调。用 10G 链路把 RDMA 协议栈的 QP 建立、报文封装、DMA 通路全部验证一遍再切换到 100G。10G 链路的物理层问题少很多调试速度会快得多。协议栈逻辑是共用的切换成 100G 之后只剩 GT 通道和时序需要重新验证。这个思路在某些项目里能省下整周的调试时间。这套环境的下一步扩展把上面这套基础环境完整跑通之后你会发现一个可用的 100G RDMA 测试平台已经立住了。我最后想说的是这个平台的价值不止于“能 ping 通”或者“能跑出带宽”它本质上是一个可编程的高性能网络研究底座。后续可以扩展的方向包括往 RDMA 引擎里加入自定义的拥塞控制算法对比默认策略在不同流量模型下的表现把 DMA 路径从单队列扩展成多队列验证 QoS 优先级调度的效果甚至可以把 FPGA 的 100G 网络接口和自研存储控制器集成起来做一个真正的 NVMe over RDMA 卸载方案。我个人在实际操作中的体会是搭建这套环境的过程比结果更有价值。你会被迫把 PCIe、DMA、以太网 MAC、RDMA 协议、Linux 网络栈这些知识彻底串起来很多之前只看文档不理解的点都会在一次次的合不上时序、链路起不来、带宽上不去中被真正想明白。如果这篇文章能帮你少跑几次实验室、少熬几个通宵那就值了。