十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

100G UDP协议栈FPGA移植实战:从RTL修改到上板调通全记录

100G UDP协议栈FPGA移植实战:从RTL修改到上板调通全记录 100G UDP移植上板这件事说起来不算新鲜但真要把一套开源协议栈在自家板卡上跑通、跑到线速中间踩的坑绝对比你想象的多。我前阵子刚完成一轮基于开源代码的100G UDP协议栈移植从RTL修改、时序收敛到上板实测前前后后折腾了小两周。这篇文章就把整个过程中的关键环节和实测记录整理出来给准备入坑或者正在填坑的朋友一个参考。1. 项目整体设计与思路拆解1.1 为什么选开源UDP协议栈而不是自己造轮子做100G网络处理第一道选择题就是协议栈怎么来。自己写一套完整的UDP/IP协议栈光ARP、ICMP、IP校验和、分片重组这些基础模块工作量就是按人月算的而且Debug周期极长。用开源方案的话目前主流选择其实就那么几个各有各的脾气。我用的是GitHub上star比较多的那套verilog-ethernet作者是Alex Forencich。选它主要看中几点一是支持100GXGMII接口和1024位数据总线都齐二是模块划分干净MAC、IP、ARP、UDP各层解耦清晰方便单独替换和测试三是License宽松商用也没问题。提示如果只做40G或者25G也可以考虑其他轻量级方案但100G这个速率档能直接拿来改的成熟开源栈其实不多verilog-ethernet基本是绕不开的选择。1.2 移植的整体架构与数据流设计我在移植前先画清楚了整条数据通路这里也列出来给你参考用户逻辑 → UDP发送FIFO → IP发送 → MAC发送 → 100G PHY → 光模块 用户逻辑 ← UDP接收FIFO ← IP接收 ← MAC接收 ← 100G PHY ← 光模块核心控制模块我分了三块UDP栈配置寄存器组用来设置本地IP、MAC、端口号ARP缓存表用于MAC地址学习和查找用户数据接口我选的是简单的AXI-Stream FIFO接口方便和DDR或者用户逻辑对接。1.3 为什么用户逻辑必须挂在FIFO后面这个问题我一开始没太在意结果在时序收敛阶段吃了大亏。直接把用户逻辑接在UDP栈的接口上组合逻辑路径太长100G下时钟跑到322MHz其实用户逻辑时钟通常是322MHz左右按数据位宽1024位计算线速大约是322MHz * 1024 bit ≈ 330Gbps远高于100G需求实际不需要这么高时钟时序根本收敛不了。后来改成FIFO解耦用户逻辑跑在自己的时钟域UDP栈跑在MAC时钟域中间通过异步FIFO过渡时序问题才彻底解决。这个设计思路务必记住100G下几乎不可能让整条通路都跑同一个时钟域还保持时序收敛。2. 核心细节解析与实操要点2.1 100G MAC层如何处理64B/66B编码这部分属于物理编码子层的内容但直接决定了你在RTL层怎么和PHY对接。100G以太网使用64B/66B编码每64位数据块前增加2位同步头同步头用于区分数据块和控制块。FPGA内部的MAC核通常已经处理了这部分对外接口是XGMII或者XLGMII。我用的Xilinx 100G Ethernet MAC硬核配置成带FEC的RS-FEC模式然后接到光模块。这里有个重要选择FEC开还是不开。FEC前向纠错能显著降低误码率但会增加约2-3纳秒的延迟并且会占用部分带宽约6.7%的开销。我在板卡上实测短距离光纤1米以内不开FEC完全没问题但如果你的光纤链路超过10米强烈建议把FEC打开。注意FEC模式必须在MAC核配置阶段就定好不能运行中动态切换否则链路会直接断掉。2.2 ARP模块的两种用法别搞混了这套开源栈里自带ARP模块支持两种模式一种是主动模式定期发送ARP请求维护邻居表另一种是被动模式只在收到ARP请求时回复同时学习对端MAC。我做的是点对点直连测试用的是被动模式加静态ARP表项把对端的IP和MAC预先写进去省去动态学习的麻烦和等待时间。初始化时往ARP表里写入对端MAC的Verilog代码大致是// 静态ARP表项写入示例 arp_table_entry[0].ip_addr 32hC0A80001; // 192.168.0.1 arp_table_entry[0].mac_addr 48hA088B1880001; arp_table_entry[0].valid 1b1;这种写法在仿真和上板时都稳定适合链路伙伴固定的场景。2.3 UDP校验和到底怎么算才对UDP校验和计算是很容易出问题的地方。协议上规定UDP校验和包含伪头部伪头部含源IP、目的IP、协议号、UDP长度如果校验和计算错误很多网卡会直接丢包。开源代码里通常提供两种选择计算并填充校验和或者置为零IPv4下允许不校验。我实测发现一个问题如果直接把校验和字段置零Linux主机端默认可以接收但Windows主机端大概率会丢包。所以我的建议是老老实实把校验和算对代码库里一般有现成的checksum模块直接用就行不要在这个地方省事。我在仿真时专门写了测试用例验证源IP、目的IP任一变化时校验和都会相应变化避免上板后出现玄学丢包。3. 实操过程与核心环节实现3.1 开发环境与板卡资源清单先交代一下我的环境方便你对照参考FPGA芯片Xilinx UltraScale VU9P100G MACXilinx 100G Ethernet MAC硬核PHY集成在板卡上的100G光模块接口开发工具Vivado 2021.2开源协议栈verilog-ethernet从GitHub拉取的最新commit资源占用情况大致是LUT用了大概45KFF约38KBRAM用了86个主要是FIFO和ARP缓存DSP基本没用到。整体资源占比在VU9P上很轻松即使并两个100G端口也够用。3.2 移植流程的详细步骤记录整个移植过程我拆成了五步每一步都有明确的验证节点不要跳步第一步先仿真后上板。先把代码库里的tb跑通确认MAC、IP、ARP、UDP模块的功能在自己定的参数配置下没问题。这里我推荐把仿真时间拉长一些比如发送100万个包验证长时间运行的稳定性而不是只跑几个包就完事。第二步修改接口宽度和时钟。开源代码默认可能有多种配置100G下数据总线宽度是512位还是1024位要看MAC核配置。我的做法是统一用1024位时钟频率降到322MHz左右实际上是为主逻辑提供宽松的时序余量。这一步不需要改逻辑只改参数但要全局搜索一遍所有宽度定义漏改一个位宽匹配都会导致数据错位。第三步对接MAC硬核。把开源栈的MAC模块替换成Xilinx自己的硬核接口信号做适配。硬核的AXI-Stream接口是tkeep/tvalid/tready/tlast这种标准握手但数据位宽和时钟必须和MAC核完全一致。这里最容易出错的是tuser信号硬核要求tuser标识每个包的起始字节位置配错了整包数据都是乱的。第四步用户逻辑对接。在UDP栈上面封装一层简单的AXI-Stream到FIFO的桥接逻辑把收发数据接入自己的处理模块我这边是一个简单的DDR缓存逻辑用来做大包收发测试。第五步上板调试。用ILA抓关键信号先用回环模式验证PHY和MAC层再逐步打开IP和UDP层。建议调试时先用小包比如64字节把通路打通后再切成大包。3.3 上板测试的完整步骤上板测试我分了三轮第一轮PHY层回环测试。在MAC核里配置近端回环near-end loopback不经过光模块验证FPGA内部发送到接收的链路是否通。此时ILA能看到TX和RX的数据完全一致。第二轮光纤直连回环测试。用一根光纤跳线把光模块的TX和RX直接短接或者通过交换机回环走完整的物理链路。这一步能把PHY、光模块、SFP接口的问题暴露出来。我遇到的问题是光模块的TX_DISABLE引脚没拉低导致光口完全没有光功率输出用光功率计一测才知道。第三轮对接主机实测。把板卡和服务器网卡用光纤连起来配好IP地址板卡设为192.168.0.2网卡设为192.168.0.1掩码255.255.255.0用iperf3或者自定义的UDP工具打流。这一步能验证整条协议栈的真实吞吐和稳定性。3.4 硬件连接和配置细节硬件连接这步看着简单但有几个细节直接影响测试结果光模块的速率必须匹配100G SR4模块配MPO光纤跳线如果是QSFP28接口要注意区分SR4和LR4。板卡上电后先确认光模块的los信号是拉低的代表有光信号输入。服务器网卡如果是双口卡确认插的是哪一口别测了半天发现测试流量根本没进被测链路。4. 常见问题与排查技巧实录4.1 现象收发都不通ILA看不到任何数据这是上板第一天的经典问题。排查路径是从里往外查先看复位信号是否释放再看MAC核是否完成初始化然后看光模块los和tx_fault信号。我在这个环节发现一个坑开源代码的复位逻辑是上电后自动复位一段固定时间但100G MAC硬核需要的复位时间更长导致MAC还没准备好就开始发数据了状态机卡死在初始化。解决办法是改成等待MAC核的tx/tx_ready信号拉高后再释放用户逻辑复位用状态机做一次握手。4.2 现象主机ping不通FPGAPing不通时先抓包看是否有ARP请求进来。如果ILA能看到ARP请求但FPGA没有回复基本就是ARP模块的IP和MAC配置不对或者校验和模块把包丢弃了。我遇到的情况是ARP缓存的初始化文件没写对MAC地址的高低字节顺序反了大端小端问题导致回复的ARP包携带的源MAC是错的。排错心得所有涉及MAC地址的地方先确认字节序。这是以太网协议里最容易出错的隐性规则PowerPC/x86主机和FPGA之间的字节序差异坑了无数人。4.3 现象小包能通大包丢包严重这种情况基本指向FIFO深度不够。小包的时候数据量小FIFO能缓存住大包一来瞬时突发流量超过FIFO容量数据就丢了。100G线速下一个1500字节的包在1024位总线宽度下需要约12个时钟周期才能发完但用户逻辑写入速度如果跟不上FIFO就会被写满。解决办法增加发送FIFO深度我改到了32K字节。用户逻辑侧做反压fifo_prog_full信号拉高时暂停写入。如果是双向收发务必使用独立FIFO避免读写冲突。4.4 100G测试中掉帧和延迟抖动的排查100G网络测试中掉帧和延迟抖动是最让人头疼的。我在测试中发现当发送速率接近满速比如95Gbps以上时偶发掉帧。用ILA抓包发现掉帧时刻恰好是FIFO的prog_full信号拉高瞬间原因是在这个周期用户逻辑还在继续写入造成了一拍竞争。修正方式是把prog_full阈值调低一些比如FIFO深度16K时prog_full设为12K留出足够的反应余量。这招非常有效调完之后打流2小时零掉帧。4.5 常见问题速查表现象可能原因排查方法解决方案完全不通复位时序问题ILA查复位状态等待MAC ready后再释放复位完全不通光模块无光光功率计测TX检查TX_DISABLE引脚小包通大包丢FIFO深度不足看fifo_full计数加深FIFO、加反压ARP不通字节序错误抓包对比MAC修正字节序偶发掉帧FIFO阈值竞争ILA对比时序调低prog_full阈值速度上不去AXIS总线位宽不匹配看数据tkeep统一总线位宽
返回列表