常用命令
bash
# 临时方式(重启失效)
sudo ip addr add 192.168.0.101/24 dev enp33s0f1np1
# 或持久方式(NetworkManager)
EN0=enp33s0f1np1
sudo nmcli con add con-name hololink-$EN0 ifname $EN0 type ethernet ip4 192.168.0.101/24
sudo nmcli connection modify hololink-$EN0 +ipv4.routes 192.168.0.2/32
sudo ip addr add 192.168.0.101/24 dev enp33s0f1np1
sudo ip addr add 192.168.0.102/24 dev enp33s0f0np0
ping -c 100 192.168.0.2
ping -s 64/512/1400/4000
ping -c 100 -i 0.7 192.168.0.2
hololink-read -H 192.168.0.2 0x02000084
ethtool -S enp33s0f1np1 | grep rx_crc
ethtool -S enp33s0f1np1 | grep -i FCS
sudo tcpdump -i enp33s0f1np1 -nn -e -v arp or icmp
ibdev2netdev
编译 HSB:
bash
# ---------- 1) 从源码构建 fmt 11.0.2 ----------
git clone --depth 1 --branch 11.0.2 https://github.com/fmtlib/fmt $PWD/hsb-deps/src/fmt
cmake -S $PWD/hsb-deps/src/fmt -B $PWD/hsb-deps/build-fmt -G Ninja \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_INSTALL_PREFIX=$PWD/hsb-deps/local \
-D CMAKE_POSITION_INDEPENDENT_CODE=ON \
-D FMT_TEST=OFF -D FMT_DOC=OFF \
-D CMAKE_POLICY_VERSION_MINIMUM=3.5
cmake --build $PWD/hsb-deps/build-fmt -j
cmake --install $PWD/hsb-deps/build-fmt
# ---------- 2) 从源码构建 yaml-cpp 0.8.0 ----------
git clone --depth 1 --branch 0.8.0 https://github.com/jbeder/yaml-cpp $PWD/hsb-deps/src/yaml-cpp
cmake -S $PWD/hsb-deps/src/yaml-cpp -B $PWD/hsb-deps/build-yaml-cpp -G Ninja \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_INSTALL_PREFIX=$PWD/hsb-deps/local \
-D CMAKE_POSITION_INDEPENDENT_CODE=ON \
-D YAML_CPP_BUILD_TESTS=OFF -D YAML_CPP_BUILD_TOOLS=OFF -D YAML_CPP_BUILD_CONTRIB=OFF \
-D CMAKE_POLICY_VERSION_MINIMUM=3.5
cmake --build $PWD/hsb-deps/build-yaml-cpp -j
cmake --install $PWD/hsb-deps/build-yaml-cpp
# ---------- 3) 配置并编译 holoscan-sensor-bridge ----------
cmake -S holoscan-sensor-bridge -B build -G Ninja \
-D CMAKE_BUILD_TYPE=Release \
-D HOLOLINK_BUILD_ONLY_NATIVE=ON \
-D HOLOLINK_BUILD_TESTS=OFF \
-D CMAKE_PREFIX_PATH=$PWD/hsb-deps/local \
-D CMAKE_POLICY_VERSION_MINIMUM=3.5
cmake --build build -j
# ---------- 4) 安装 ----------
cmake --install build --prefix $PWD/hsb-deps/local
或者指定目录:
cmake --install build --prefix <安装目录>
# 产物:<安装目录>/bin 下为全部工具;lib/ 下为静态库与 HololinkConfig.cmake;
# include/hololink/ 下为公共头文件
vitis 工程 ping FPGA 丢包(~50% 随机)问题分析
日期:2026-09-16
对象项目:fpga/vitis/rk-xcku5p(RK-XCKU5P-F V1.2, XCKU5P-2FFVB676I)
对照项目:fpga/pynq/rfsoc-pynq(xczu48dr,无此问题)
背景
从主机光口 ping FPGA(默认 IP 192.168.0.2)时,vitis 工程存在随机约 50% 的丢包;
pynq 工程在相同主机环境下无丢包。两个项目共享同一份 nv_hsb_ip RTL。
分析方法
- 对两个工程的
rtl/、build/constraints/constraints.xdc、build/ip/bd_gen.tcl、
build/build.tcl、build/build.sh逐一 diff; - 通读 ping/ARP 数据通路全部相关 RTL:
nv_hsb_ip/rx_parser/rx_parser.sv、rx_ls_parser.sv、arp_ping_pkt_proc.sv、
nv_hsb_ip/eth_pkt/eth_pkt.sv、nv_hsb_ip/lib_axis/axis_reg.sv、
nv_hsb_ip/reg_map/regmap_pkg.sv; - 核对时钟/复位/约束/CMAC 配置的所有移植差异点。
一、已排除的部分(两项目完全一致,不可能是差异来源)
| 项目 | 状态 |
|---|---|
ping/ARP 通路全部 RTL(rx_parser → arp_ping_pkt_proc → rx_ls_parser → eth_pkt → CMAC TX) |
逐字节相同,同属 nv_hsb_ip |
ICMP 校验和逻辑(arp_ping_pkt_proc.sv:193-196,+0x0800 回卷) |
相同,算法本身验证无误 |
MAC 地址 48'hCAFEC0FFEE00、默认 IP 192.168.0.2 |
相同 |
| CMAC 配置(CAUI4 / LPM / INS_LOSS_NYQ / 关流控 / AXIS 接口) | 相同 |
drp_clk 绑常量 0、core_drp 绑死 |
两边一样(pynq 正常,可排除) |
usr_clk = gt_txusrclk2 = 322.265625MHz;apb 50M / ptp 100M 时钟方案 |
相同 |
HOLOLINK_def.svh(HIF_CLK_FREQ / MTU / 接口位宽等) |
相同 |
二、嫌疑点排序
★ 1. 322MHz txoutclk(usr_clk)域时序未收敛 ------ 最大嫌疑,有书面证据
vitis/rk-xcku5p/build/build.tcl 注释自述:
The default strategies left WNS=-0.170ns / TNS=-29.987ns (596 endpoints)
on the 322.266 MHz CMAC txoutclk_out0 domain.
impl_phys_opt_fanout_post.tcl 指明失败网络是 512-bit AXIS regslice 的高扇出
load/CE 网络(gen_eth_pkt[0].u_eth_pkt/u_axis_reg) ------ 即 ping 应答发往 CMAC
的必经之路(axis_reg.sv 中 load 信号驱动全部 512+ 位数据寄存器)。
git HEAD 提交 SWLIB-3948 add opt propeties to improve WNS 即为修复该问题的尝试。
机制:ping 请求/应答均为 64B 单拍(512bit 总线一个 beat)。322MHz 下任一 failing
endpoint 采样错 1 bit 即可导致:
- 请求方向:FPGA 内 IPv4 校验失败 / 解析失败 → 丢包不应答;
- 应答方向:应答内容损坏(CMAC 自行计算 FCS,主机收到的是"FCS 正确但内容错"
的包,被静默丢弃)。
每包独立随机出错 → 正好呈 ~50% 随机丢包。pynq 所用 ZU48DR 器件规模大、拥塞小,
同样 RTL 下时序通过,故无此现象。
验证(最关键一步) :对实际烧片的那次构建查看布线后时序报告,而不是假设
directives 已修好:
tcl
open_checkpoint <routed>.dcp
report_timing_summary # 重点看 txoutclk / clk_wiz 各域 WNS 是否 >= 0
同时确认所烧 bit 文件是用带新 directives 的 build.tcl(HEAD 提交)构建的。
★ 2. 新板卡链路信号完整性(SI)
RK-XCKU5P-F 是新板:GTY Quad 225、新 PCB 走线、QSFP 笼,而 CMAC 均衡配置
(RX_EQ_MODE=LPM、INS_LOSS_NYQ=1,bd_gen.tcl:170-171)是从 pynq 板直接照搬的,
未必匹配新通道。RX 随机误码 → CMAC FCS 错 → rx_parser.sv:416
(fcs_err_data = i_axis_rx_tuser || buf_rls_afull)直接丢帧。
验证:
- 观察 LED1(aligned)是否闪烁、LED3(gt_powergoodout)是否稳定;
- 主机
ethtool -S <iface>查看 rx_crc / FCS 错误计数; - 与 pynq 环境互换线缆 / 光模块;
- 必要时改 DFE 均衡重新试验。
★ 3. 测试环境:两块板同 MAC + 同默认 IP
两板均为 CAFEC0FFEE00 / 192.168.0.2。若测试时 pynq 板与 vitis 板同时上电
并接在同一 L2 网络/交换机 ,交换机 MAC 表抖动会造成教科书式的"随机一半丢包"。
确认测 vitis 时 pynq 板断电 / 拔纤。
4. 次要项(大概率可排除,但需核对构建 log)
set_clock_groups中gen_channel_container[3](constraints.xdc:120-121):
若层级路径未匹配,Vivado 仅报 warning,clk_wiz ↔ TXOUTCLK 异步组将缺失 →
布线恶化 + 时序报告失真。在 vivado log 中搜set_clock_groups相关
critical warning 确认约束真正生效。- init_clk 200MHz vs 100MHz:仅影响复位保持时间(20.5µs vs 41µs),
rst_all由gt_powergoodout把关,基本可排除。 QSFP_LPMODE=0 / RESETL=1 / MODSELL=1:常量驱动且 link 已 up,可排除。GT_DRP_CLK=200(vitis 新增):因drp_clk两板均绑常量 0,该参数无实际作用。
三、可立即执行的定位手段(按投入排序)
- 主机侧定方向 :
tcpdump -i <iface> -nn arp or icmp+ethtool -S <iface>- 请求发出但无应答 → 包在 FPGA 内丢(嫌疑 1 / 2);
- 有应答但 ping 仍报丢 → 应答内容坏(时序问题实锤)。
- 读 FPGA 内部计数器 :
rx_parser的ipv4_chksum_err_cnt
(inst_dec 状态寄存器,offset 0x84,经 ECB/APB 可读)。- ping 期间递增 → 帧过了 MAC FCS 但 IP 校验错 = MAC 之后内部数据损坏 =
时序问题; - 不动 → 帧在 MAC/链路层即丢 = SI 问题。
- ping 期间递增 → 帧过了 MAC FCS 但 IP 校验错 = MAC 之后内部数据损坏 =
- 缓解性试验 :注释掉
FPGA_top.sv中两个s_apb_ila
(16384×256bit + 8192×585bit,写使能常开,是 usr_clk 域很大的拥塞源)
重新实现。若丢包消失 → 进一步印证时序/拥塞。 - 深度调试手段 :将 CMAC
drp_clk接真实时钟、core_drp接出,
读stat_rx_fcs_err等计数器;或在hif_rx上加 ILA 抓 CMAC 的
tuser(FCS error),可一锤定音区分 SI 与内部逻辑。
结论
按现有证据链,"vitis 工程 322MHz usr_clk 域时序未收敛导致 512bit 数据通路随机
采样错误" 是最可能的根因(有 WNS=-0.170ns / 596 endpoints 的历史记录,且失败
网络恰在 ping 应答通路上)。建议先做第三节第 1、2 项(零成本)并核对布线后时序
报告;若时序干净,再转向新板 SI(换 DFE / 查线缆 / 互换光模块)与同 MAC 冲突
两项排查。
四、诊断记录
2026-09-16 记录 1:主机 NIC 收方向 CRC 计数
测试命令与结果:
$ ethtool -S enp33s0f1np1 | grep rx_crc
rx_crc_errors_phy: 45
rx_crc_errors_phy 增长速度远不及 ping 丢包数量。
解读
- "FPGA → 主机" 光纤方向链路 SI 基本可排除 :若该方向链路有误码,主机收到的
FCS 错帧会被 NIC 计入rx_crc_errors_phy,其增速应与丢包率同量级。实测远低,
说明主机收到的帧 FCS 基本都正确。 - 但该结果无法排除 FPGA 内部损坏 :CMAC TX 是在数据离开 FPGA 用户逻辑之后
才计算并附加 FCS 的。若应答包在 FPGA 内部(usr_clk 域,时序)已被损坏,主机
收到的是 "FCS 正确、内容错误" 的帧 ------ 不计入rx_crc_errors_phy,只会
被协议栈(IP/ICMP 校验)静默丢弃。 - 同理,请求方向的丢失(host→FPGA 链路误码被 CMAC 丢弃、或 FPGA RX 内部损坏)
也不会使主机侧 rx_crc 增长。 - 需确认 45 个计数的产生时机:若为 link-up 瞬间产生则无诊断意义;记录现值,
跑一段时间后取差值判断是否持续增长。
剩余三种可能性
| 编号 | 位置 | 机制 | 主机 rx_crc |
|---|---|---|---|
| ① | host→FPGA 光纤链路 | 请求帧 FCS 错,被 CMAC RX 丢弃,无应答 | 不增长 |
| ② | FPGA RX 内部(MAC 之后,usr_clk 域时序) | 请求内容损坏,IPv4 校验失败或解析失败,无应答 | 不增长 |
| ③ | FPGA TX 内部(CMAC 之前,usr_clk 域时序) | 应答内容损坏但 FCS 由 CMAC 重算,主机收到"FCS 好/内容坏"帧后丢弃 | 不增长 |
下一步鉴别实验(按顺序)
- tcpdump 抓包(决定性) :
sudo tcpdump -i enp33s0f1np1 -nn -e -v arp or icmp,同时 ping。- 丢的包有应答回来 → ③(检查 tcpdump 是否报 bad cksum / 核对 ICMP
id/seq / 源 MAC 是否为 CAFEC0FFEE00)。 - 丢的包无应答 → ① 或 ②,转实验 2 区分。
- 顺便观察丢包时刻是否伴随 ARP 重解析且无应答(同一 arp_ping 模块损坏,
机制相同)。
- 丢的包有应答回来 → ③(检查 tcpdump 是否报 bad cksum / 核对 ICMP
- 读 FPGA 内部 IPv4 校验错误计数器 (inst_dec 状态寄存器,
地址 = 0x0200_0000 + 33*4 = 0x02000084 ,主机 APIhololink.read_uint32):
ping 前后各读一次取差值。- 随丢包递增 → ② = FPGA RX 内部损坏(MAC 之后)= 时序问题实锤。
- 不动 → ① = 请求在 CMAC/链路层即丢 = SI 问题(需 CMAC RX 统计确认;
当前设计 drp_clk/core_drp 被绑死读不到,属调试盲区)。
- 包长扫描 :
ping -s 64 / 512 / 1400 / 4000。
64B 在 512bit 总线上为 1 拍,1400B 约 3 拍。丢包率随拍数上升 → 逐拍随机
损坏(时序/SI)特征;恒定 ~50% → 转向结构性/ARP 方向。 - 速率扫描 :
ping -i 0.2vs-i 1.0。丢包率随速率明显变化 → ARP/表项
相关;恒定 → 逐包随机损坏。
2026-09-16 记录 2:tcpdump + 包长/速率扫描(决定性进展)
实测数据
ping -i 0.197 -c 10(默认 64B):40% 丢包。tcpdump 显示丢掉的包完全没有
应答帧 (非"应答损坏",是 FPGA 未产生应答);回来的应答全部完好
(MAC/id/seq/校验全对,零坏帧);全程无 ARP 交互(ARP 稳定,排除 ARP 因素)。- 包长扫描:
-s 64→ 40% 丢;-s 512→ 80~90% 丢;-s 1400→ 100% 丢;
-s 4000→ 100% 丢。 - 速率无关:
-i 0.197 / 0.43 / 默认丢包率一致。 - 45 个 rx_crc 为 link-up 后一小时内缓慢增长、之后稳定 → 初期瞬态,
FPGA→主机方向链路良好。
分析结论
-
丢失发生在请求方向(FPGA 产生应答之前)。剩余两种可能:
- ① host→FPGA 光纤误码,请求帧被 CMAC RX FCS 检查丢弃;
- ② FPGA RX 内部(CMAC 之后,usr_clk 域)损坏,解析/校验失败丢弃。
-
FPGA TX 路径(内部+光纤)干净 :若 TX 内部也有同级损坏率,tcpdump 应看到
大量"FCS 好/内容坏"的应答帧,实测为零。→ 若根因是时序,违规集中在
RX 路径 (CMAC RX AXIS →
gen_rx_parser第一级寄存 / 512→8 宽度转换级)。 -
逐拍随机损坏模型精确拟合 :512bit 总线 64B/拍,每拍损坏率约 23%:
帧长 拍数 实测存活 模型 s^n (s≈0.775) 98B 2 60% 60% ✓ 540B 9 10~20% 10% ✓ 1428B 23 0% 0.3% ✓ 4028B 63 0% ~0% ✓ 速率无关 + 包长强相关 → 随机物理性损坏(时序或误码),非协议/结构性问题。
下一步鉴别实验(① vs ②,按成本排序)
- 读 FPGA
ipv4_chksum_err_cnt(0x02000084) ,ping 前后取差:- 递增 → ②(帧过了 MAC FCS 但在内部损坏);
- 不动 → 偏向 ①(帧在 CMAC/链路层即丢)。注意该测试是单侧决定性的:
若损坏打碎了 ethertype/IP 头导致误分类,可能不计数。
- 换用 pynq 验证过的同一主机端口 + 同一根线 + 同一光模块测 vitis 板
(零成本、决定性):若丢包依旧 → 问题锁定在 vitis 板/FPGA 本身;
若丢包消失 → 链路/光模块问题(①)。 - 核对当前 bitstream 布线后时序报告 :这次重点看 RX 路径端点
(gen_rx_parser、u_axis_*512→8 宽度转换级、CMAC RX AXIS 到 HOLOLINK
第一级触发器的路径)。注意 CMAC RX AXIS → HOLOLINK 之间没有任何
register slice ,322MHz 下从 CMAC 硬核到第一级触发器的长走线是典型
failing-path 候选;若确认是该路径,修法之一是在hif_rx边界插入
AXIS register slice 把长路径切成两段。 - 调试 build 暴露 CMAC RX 统计 :
drp_clk接真实时钟 +core_drp接出
读stat_rx_fcs_err;或在hif_rx_axis_tuser(CMAC FCS 错误标志)上加
ILA。若 CMAC 自身报 FCS 错 → ①实锤;若 CMAC 干净而包在内部消失 → ②实锤。
2026-09-16 记录 3:主机 rx_crc 缓慢持续增长(45 → 47)
解读(定量)
- 两次观察之间主机收帧量级约 10²(ping 应答 + FPGA 周期 BOOTP 广播),
rx_crc +2 → FPGA→主机方向帧级误码率 ≲10⁻²。 - 与主体丢包的关系:tcpdump 已证明主体丢包是"请求未产生应答"。若丢失都是应答
在线路上损坏,rx_crc 应与丢包数 1:1 增长;实测增速差 1~2 个数量级 →
线路误码最多解释百分之几的丢包,解释不了 40%→100% 的主体丢包。 - FCS 坏帧被 NIC 硬件丢弃、到不了 tcpdump ------ 与"tcpdump 里应答全完好"自洽。
- 反推 ①(host→FPGA 方向线路误码导致 CMAC FCS 丢帧)所需的 BER:
23%/拍 ÷ 512bit ≈ 4.5e-4 ,比反向观测值(~3e-6 量级)差约 150 倍。
两根纤芯不对称劣化(接头脏污、一端激光器偏弱、FPGA 板端 RX 前端/LPM 均衡
裕量不足)可能形成这种不对称 → ① 不能排除,且嫌疑权重上升;
②(FPGA RX 内部时序)仍为最大嫌疑。
新增待确认项:介质与 FEC
- 需确认 pynq / vitis 两次测试介质是否一致:DAC 铜缆 / AOC / SR4 光模块+跳纤?
- 本设计 CMAC 未开 RS-FEC (bd_gen.tcl 无相关配置)。100G-SR4 规范要求
RS-FEC;若主机端同样关 FEC 且用 SR4,原始误码会直接表现为随机丢包。 - 主机侧查询:
ethtool --show-fec enp33s0f1np1;
ethtool -S enp33s0f1np1 | grep -iE "fec|ber|symbol|corrected"(Mellanox
PHY 层计数)。
新增实验:主机两端口自环(零成本、无 FPGA 依赖)
将现接 FPGA 的同一根线 + 同一光模块插到主机两个 QSFP 口互连
(enp33s0f0np0 ↔ enp33s0f1np1),各配 IP,大包高速率 ping / iperf3 数分钟:
- 自环也出现丢包 / rx_crc 增长 → 介质 / 主机端口问题(①家族);
- 自环干净 → 问题在 FPGA 板端(② 或板端 RX 前端),回到布线后时序报告
(重点 RX 路径)与板内排查。
2026-09-16 记录 4:介质/FEC 事实 + 自环方法论修正
新事实
- pynq 当时用的是 DAC 铜缆 (在外地实验室,无法拿到本实验室更换);
vitis 这里用的是光口(模块/跳纤)→ 两次测试介质不同。 ethtool --show-fec enp33s0f1np1:Configured = Auto,Active = Off
→ 链路双端均无 FEC(FPGA 侧 CMAC 也未开 RS-FEC)。
DAC 无 FEC 很健壮;光模块(尤其 SR4,规范要求 RS-FEC)无 FEC 时存在非零
原始误码 ------ 与观测到的背景 rx_crc(47 个)自洽。- 待确认:本端介质是 AOC 还是 SR4+跳纤、长度;
ethtool -m看光功率;
ethtool -S | grep -iE "symbol|ber|corrected"看 PHY 层计数;
清洁 LC 接头(单芯脏污 → 非对称劣化,可解释两方向误码率差 ~150 倍)。
自环方法论修正(重要)
记录 3 中建议的"主机两端口自环 ping"在单台主机上不成立 :
本机两个本地 IP 之间的 ping 永远走内核 local 路由(lo),流量不上线 。
用户实测印证:ping 192.168.0.101(本机地址)0% 丢包纯属内核回环,无信息量;
ping 192.168.0.102 报 From 192.168.0.101 Destination Host Unreachable,
说明 .102 未被本地投递、ARP 无应答(第二口很可能 link down / 未直连)。
正确做法(netns 强制流量上线):
bash
# 拔下 FPGA 光纤,用同一根线+同一光模块直连主机两个 QSFP 口
ethtool enp33s0f0np0 | grep "Link detected" # 确认两口 link up
ethtool enp33s0f1np1 | grep "Link detected"
sudo ip netns add looptest
sudo ip link set enp33s0f0np0 netns looptest
sudo ip netns exec looptest ip link set enp33s0f0np0 up
sudo ip netns exec looptest ip addr add 10.99.0.2/24 dev enp33s0f0np0
sudo ip addr flush dev enp33s0f1np1
sudo ip addr add 10.99.0.1/24 dev enp33s0f1np1
sudo ip link set enp33s0f1np1 up
sudo ip netns exec looptest ping 10.99.0.1 -s 1400 -i 0.1 -c 1000
# 同时两端 ethtool -S 观察 rx_crc;测完 sudo ip netns del looptest 并恢复配置
验证流量确实上线的方法:同时在两个口上 tcpdump,能看到 ICMP 报文才算数。
当前嫌疑排序
- ② FPGA RX 内部时序(每拍 ~23% 损坏、仅 RX 方向、速率无关 ------ 最大嫌疑;
决定性验证:读 0x02000084ipv4_chksum_err_cnt+ 布线后时序报告 RX 路径)。 - ① host→FPGA 方向链路/板端 RX 前端(介质不同、无 FEC、背景 rx_crc 非零、
可能存在单芯非对称劣化;验证:netns 自环、清洁接头、查光功率、
必要时 DFE 均衡或 ILA 抓hif_rx_axis_tuser)。