尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于verilog-ethernet的FPGA 100G UDP协议栈移植与上板测试

基于verilog-ethernet的FPGA 100G UDP协议栈移植与上板测试 1. 为什么自己折腾100G UDP需求背景与方案选型这事儿得从一次测试需求说起。当时实验室里有个高速数据采集项目前端ADC采出来的数据流带宽到了80Gbps左右后端需要把这些数据实时丢给服务器去做处理。最开始考虑的是PCIe方案但服务器的PCIE通道数量有限而且采集端和服务器之间还有几十米的物理距离PCIe线缆的成本实在劝退。于是目光很自然就落到了以太网这条路线上——万兆已经跑习惯了能不能再往上跳一跳直接上100G答案是可以但坑比想象中多得多。1.1 为什么选择UDP而不是TCP做高速传输的人应该都有感触在FPGA里写TCP协议栈是一件非常痛苦的事。TCP有状态机、滑动窗口、重传机制、拥塞控制逻辑资源消耗大不说时序收敛也容易出问题。而UDP足够轻量没有连接状态只要把MAC帧头和IP/UDP头填对数据就能直接上线路。对于高带宽、弱可靠的数据采集场景来说UDP丢几个包完全可以通过应用层处理实在不行重传一轮就行。所以选UDP不是因为它完美而是因为在这个场景下它是性价比最高的方案。100G的线速率下UDP协议栈的开销是可以接受的剩下的带宽几乎全给数据用。1.2 商业IP和开源方案对比商业方案像Xilinx的XGE MAC、Ethernet MAC IP核功能完善、支持好但价格不菲而且授权方式对开源项目不友好。最后把目光投向了开源社区尤其是我一直在关注的Alex Forencich维护的verilog-ethernet项目这个项目从10G到100G都有完整的实现代码风格干净接口规范社区活跃度也高。做一个简单的选型对比方案成本灵活性技术支持成熟度商业IP核高低受限于IP核的功能边界官方支持很高开源verilog-ethernet免费高可自由裁剪修改社区自行阅读代码高自研协议栈中最高自己就是客服低综合来看verilog-ethernet是性价比最优的选择这也是本文移植上板测试的主角。2. 100G UDP协议栈的架构拆解不看懂代码就开始移植等于盲人摸象拿到开源代码第一件事别急着综合跑仿真先把它的架构搞清楚。verilog-ethernet项目的100G UDP部分核心是eth_udp_100g这个模块它的内部结构比10G版本要复杂不少因为100G的数据位宽和处理逻辑完全不同。2.1 从10G到100G的变化位宽、Clock域和总线协议10G版本的数据位宽通常是64bit工作在156.25MHz。100G版本直接用512bit数据位宽工作在322.265625MHz这是由100G以太网的PCS层决定的。512bit的位宽意味着每个时钟周期要处理64个字节任何一个逻辑的小失误都可能让时序直接崩掉。接口方面verilog-ethernet的100G版本用的是AXI4-Stream接口TUSER信号里塞了很多有用的信息比如帧起始偏移、帧结束偏移、错误标记等。这些信号在oncatenate的时候特别容易搞混我在后面的移植过程中就在这个字段上踩了大坑。2.2 UDP发送数据通路分段和组包流程从用户侧看发送数据就是往一个512bit的AXI接口上写数据。但注意这里面的核心是eth_udp_100g_tx模块内部的axis_arb_mux和axis_async_fifo的配合以及UDP校验和的计算逻辑。100G UDP的发送流程大致如下用户逻辑把要发送的数据净荷写入TX FIFO以太网帧组装模块自动加上TCP/UDP校验和逻辑UDP头、IP头、MAC头依次填充完成后按序输出到MAC层值得关注的是校验和逻辑。verilog-ethernet项目实现的是伪头部校验和它会把源IP、目的IP、UDP长度、协议号等信息一并参与校验和计算。这个如果自己写很容易避开直接调用它的模块就能省下大量时间。2.3 UDP接收数据通路解析和过滤的关键点接收方向的核心逻辑是eth_udp_100g_rx它要做的事情是从输入的网络流中识别出合法的UDP报文然后把净荷部分送给用户逻辑。接收通路里最重要的几个功能点MAC层地址过滤只接收目标MAC地址匹配本机的帧这个在测试时要特别注意因为如果FPGA侧设置了严格过滤上位机发包前必须把目的MAC改对IP层版本校验IPv4/IPv6处理IP/UDP校验和校验接收方向如果校验和错误报文是会被直接丢弃的净荷对齐因为UDP数据部分不一定对齐到512bit位宽所以接收侧有专门的逻辑处理非对齐数据的拼接这一堆逻辑逻辑之间是通过AXI-Stream接口串起来的理解每个接口的握手信号和字段定义是利用好这个开源项目的关键。3. 移植适配的完整过程从更换PHY到时序收敛代码架构看完接下来就是实际操作了。我的目标是把它跑在一颗Xilinx UltraScale系列FPGA上PHY用的是集成在片上的高速串行收发器(GTY Transceiver)速率是100GBase-R的4路25G。3.1 适配自己的FPGA型号与PHY配置先看工程的依赖关系。verilog-ethernet项目里针对不同的FPGA厂家和PHY配置提供了多个example design但很多是基于VCU118、VCU128这些开发板做的。我的板卡虽然也是UltraScale但引脚分配、时钟资源、参考时钟频率都不同所以直接用到自己的板卡上不可能跑起来。我的做法是这样做把rtl目录下的所有代码完整保留单独建了一个board_adapt目录把自己板卡相关的底层文件放进去在顶层文件中例化GTY Transceiver IP核把GTY的接口连接到eth_eth_100g模块的物理层接口上这里有一个容易出错的地方GTY在100G模式下需要对参考时钟的频率和锁相环配置非常敏感如果参考时钟不是156.25MHz需要对GTY的配置参数做相应修改。我的板卡上恰好只有一个161.1328125MHz的参考时钟这个频率无法直接用于是专门加了一个时钟管理模块把频率转换到GTY需要的参考时钟范围。3.2 时钟方案的落实REF_CLK、GTY_REFCLK和USER_CLK100G以太网的时钟是整个系统最容易出问题的环节。verilog-ethernet的example design里有明确的时钟要求时钟名称频率要求用途gt_ref_clk155.52MHz或156.25MHzGTY参考时钟gt_rx_clk恢复时钟接收侧数据时钟gt_tx_clk发送侧时钟发送侧数据时钟user_clk322.265625MHz用户逻辑时钟我的板卡参考时钟频率无法直接满足要求所以在时钟树里加了一级PLL做频率变换。另外要注意的是GTY的RX恢复时钟和USER_CLK之间是异步关系它们之间如果有数据交互必须加异步FIFO做时钟域转换。verilog-ethernet模块内部自带了异步FIFO但要确保在综合时不把这些FIFO优化掉否则会出现数据错乱。3.3 引脚约束与时序约束对于100G设计来说时序约束是重头戏。因为数据位宽512bit时钟频率322MHz组合逻辑如果在几个模块之间传递延迟太大时序很难收敛。我的约束文件里重点处理了三块所有GTY相关的引脚约束——包括参考时钟、复位、状态信号等时钟约束——给GTY恢复时钟、user_clk等时钟域创建对应的create_clock跨时钟域约束——对异步FIFO输出的路径设置适当的false_path或max_delay实际综合后时序结果大概是这样WNS最差负时序裕量能跑到-0.05ns左右虽然看起来是负的一点但对100G这种高速设计来说只要通过调整布局布线策略就能修回来。后来我开了-retiming选项并且对关键路径的寄存器做了复制WNS就转正了。这里分享一个个人经验如果时序收敛差是因为FIFO的读写指针逻辑太长可以尝试把FIFO的深度改小一点减少地址比较的级联逻辑深度。verilog-ethernet项目里FIFO的深度参数默认是512如果你的设计只有少量包需要缓冲可以安全地改成128或256时序会改善很多。4. 上板测试的全流程方法论打流、抓包、定位瓶颈代码移植完成、时序也收敛了接下来就是上板实测。上板测试是一套系统工程不是简单地把bit文件烧进去然后看着链路灯亮就算完事。我的测试方法分三步走每一步都能发现新问题。4.1 硬件链路搭建FPGA板卡、光模块与测试主机先说说我的测试环境这个比较有代表性FPGA板卡Xilinx UltraScale系列板载4路25G光模块接口光模块QSFP284x25G模式测试主机一台带100G网卡的服务器网卡型号是Mellanox ConnectX-5连接方式通过一条MPO光纤直连注意100G支持多种分拆模式比如4x25G拆分成四个独立的25G通道或者2x50G等。我的设计采用4x25G模式所以网卡端也要配置成对应的模式否则物理层握手就过不去。上电前检查这几件事光模块的供电和I2C地址是否正常很多板卡的光模块供电需要额外的GPIO使能光模块的复位引脚是否释放QSFP28的时钟是否正常(每个通道都有独立的参考时钟信号)4.2 用iperf3进行UDP打流测试测试主机上先装好iperf3在服务器上开一个接收端iperf3 -s -p 5001然后在另一端打流iperf3 -c 192.168.1.10 -u -b 80G -t 30 -l 8192这里几个参数要解释一下-uUDP模式-b 80G目标带宽80Gbps-t 30持续30秒-l 8192UDP包payload大小设置为8KB需要注意的是iperf3单线程可能撑不满100G带宽所以实际测试时我开了多线程iperf3 -c 192.168.1.10 -u -b 80G -t 30 -P 4实测结果比较理想发送端能稳定跑在80-90Gbps接收端基本能跟上丢包率在万分之一以下对于首版移植来说已经是超出预期了。4.3 Wireshark抓包验证协议字段的正确性跑通了iperf3只能说明带宽没问题但协议细节还得靠抓包来验证。在接收端用tcpdump抓包tcpdump -i enp175s0f0 -s 0 -w udp_100g.pcap保存成pcap后用Wireshark打开重点看这几个字段MAC地址源MAC是否是FPGA侧的MACIP地址源IP是否是FPGA侧配置的IPUDP源端口是否与FPGA侧配置的端口一致UDP长度字段是否和实际payload长度匹配如果这些字段都正确说明协议栈的打包逻辑没有问题。我在测试过程中抓到过一次UDP checksum全零的情况仔细一查发现是verilog-ethernet工程的参数里有个开关可以控制是否计算校验和默认是关闭的打开后校验和就对了。4.4 用ILA在线调试定位内部信号异常有些问题靠外部工具是查不出来的比如FPGA内部某个模块死锁了、状态机卡住了、FIFO溢出等。这时候就要靠Xilinx的ILA集成逻辑分析仪来抓内部信号。我在设计中加入了ILA核抓的信号有三个关键组eth_udp_100g_tx模块的AXI接口握手信号eth_udp_100g_rx模块的AXI接口握手信号eth_eth_100g模块的MAC层状态机状态调试过程中有一次发现发送通道的TLEN一直为0导致数据发不出去查了代码后发现是用户逻辑在给TLAST信号打拍子时多打了一拍和TUSER里携带的长度信息错位了。这种问题如果不用ILA靠猜是猜不出来的。5. 测试中踩过的5个最深的坑每个都是花了一两天才爬出来5.1 GTY参考时钟频率不对导致链路起不来开始的板卡参考时钟频率是161.13MHz当时觉得差一点应该没事但实际GTY对参考时钟范围有严格要求不在范围内就无法锁定。后来在时钟管理模块里加了一级PLL把161.13MHz转换成GTY需要的频率范围链路就正常起来了。5.2 AXI-Stream的TLAST信号没对齐导致丢包这个问题最隐蔽。verilog-ethernet的发送接口要求TLAST与最后一个数据拍对齐但接收端的上位机逻辑在拼接数据时把TLAST的时序理解错了。数据其实发出去了但接收端组装的时候少了一个周期导致整个包的数据错位。排查方法是在ILA里同时抓TLAST和TDATA发现TLAST比有效数据早了一拍。修正对齐之后收发就完全正常了。5.3 链路聚合设置导致的性能瓶颈测试过程中发现主机端iperf3单线程只能跑到30Gbps左右远低于100G。查了半天发现是主机网卡的RSS(接收端扩展)没有使能所有流量都跑到同一个CPU核心上去了严重限制了接收吞吐。在网卡上开启RSS后多队列并行处理接收带宽立刻上来了。命令大致是这样ethtool -L enp175s0f0 combined 8把接收队列扩展到8个让多个CPU核分担收包负载。5.4 FPGA侧DDR带宽不是瓶颈但FIFO深度差点成瓶颈理论上100G从FPGA到主机数据要经过一个较大的缓冲因为主机CPU处理速度和网络到达速率之间是突发的。我把verilog-ethernet的默认FIFO深度从512加到了2048吸收突发能力显著增强丢包率从千分之一降到了万分之一以下。不过FIFO深度加大会占用BRAM资源实测在UltraScale上2048深度的FIFO大约消耗2-3个BRAM36K这个代价完全可以接受。5.5 不要忽视上位机操作系统的UDP接收缓冲区Linux系统的UDP接收缓冲区默认值比较保守如果上位机应用程序读取速度跟不上内核的接收缓冲区会溢出就出现内核丢包的现象。做高带宽测试前一定要调大缓冲区sysctl -w net.core.rmem_max134217728 sysctl -w net.core.rmem_default134217728实测把这个值调到128MB后UDP接收端的稳定性好了一个量级。6. 性能实测数据与后续优化方向6.1 同一套逻辑下10G和100G的实测数据对比我在测试过程中同时保留了10G版本的测试数据方便对比指标10G版本100G版本线速率10Gbps100Gbps实际吞吐(单向)9.4Gbps89Gbps丢包率(80G下)0.001%0.01%时延(FIFO深度512)约2us约0.5us逻辑资源(LUT)约45K约320KFIFO BRAM消耗约10个约28个100G的吞吐跑不满100Gbps主要瓶颈在GTY发送端的调度逻辑和主机网卡的接收能力。FPGA侧纯硬件处理到95Gbps是没问题的但当上位机参与收包时受限于PCIe带宽和CPU处理能力实际到不了线速。6.2 进一步优化的三个方向三个方向是我接下来打算做的方向一开启GTY的自动协商机制。目前是强制模式直接固定到100G。如果开启自动协商可以和不同链路速率的设备互通但会增加不少握手逻辑。方向二深度调优DDR缓存策略。当前FIFO是纯BRAM实现如果换成DDR4做缓存理论上FIFO深度可以做到几十万级别能更好地吸收主机侧的突发压力。方向三上完整TCP协议栈。虽然UDP够用但有些业务场景要求TCP的可靠性保障。可以在verilog-ethernet的tx/rx基础上叠加一个轻量级TCP引擎形成完整的TCP/IP协议栈。这个工程量较大但对工程应用价值很高。7. 对开源以太网IP核的一些个人思考如果你也想自己搞一套100G UDP链路我的建议是先别急着上板把项目里的example design看懂、跑通仿真再根据自己板卡的实际情况做适配。verilog-ethernet的代码注释很详细接口定义也规范细心读一遍能节省后面调试的大量时间。另外有一点我想强调开源IP核不代表烧进去就能用。它给你的是可综合的RTL代码但真正上板之后时序、复位、时钟、PHY配置这些外围工程问题都要自己解决。这些经验恰恰是商业IP核给不了你的部分——因为商业IP核把这些问题全封装好了你反而失去了理解底层的机会。这次整个移植周期大概花了三周时间其中最耗时的反而是最初的环境准备和板卡适配。只要板卡适配好、参考时钟搞定后续调试就是按部就班地验证每一个层的正确性。测试方法建议遵循自底向上的原则先验证GTY物理层再验证MAC层最后验证IP/UDP层这样定位问题会快很多。
返回列表