BCM57810 iSCSI 读不如写?
BCM57810 iSCSI 读不如写?
购入了一台华垃圾 Dell OptiPlex XE2 SFF 用来打一些古早游戏,CPU 和内存都好说,但由于最近硬盘涨价实在太厉害已经到了离谱的程度,我也不愿意当冤大头,就考虑给这台机器做无盘工作站。主板自带的 NIC 是 1Gbps 的,明显不能满足磁盘需求,只能翻出家中的垃圾 Lenovo OEM Intel 82599,但是这卡不能 iSCSI boot 只能 PXE,便又花费 ¥120 购入了一块华垃圾 Dell OEM BCM57810S CNA。在经历了一系列同 NIC 和 Windows 的斗争之后,终于成功安装了 Windows 7。这卡好得很,FCoE、iSCSI 全都支持,可以当 hardware iSCSI HBA 用。target 则是家中的存储服务器,Windows iSCSI Target 导出了一块 Storage Spaces 的 VHDX。这个 10Gbps 的卡通过 QSA 连接到 40Gbps 的 SX6012 核心交换机上(是的我淘汰了 QFX5100,节电中)。
按理说这套配置不该有什么问题。10G 的 iSCSI 跑一个 SSD VHDX,就算不到 1 GB/s,读速度起码也不至于如此差劲:
写能过 500 MB/s,链路显然不是 1GbE;但 seq read 只有两三百 MB/s,Q1 更是惨不忍睹。这种排障最为痛苦,光纤、SSD、驱动、PCIe、iSCSI 参数,每个都有可能,只能逐个排除。
在 Windows 7 上运行:
> iscsicli SessionList
Initiator Node Name : iqn.1995-05.com.qlogic.iscsiboot
> iscsicli ReportTargetMappings
Initiator : EBDRV\L4SC&PCI_168E14E4...
Initiator Scsi Device : \\.\Scsi0:L4SC 是 QLogic/Broadcom 的 iSCSI offload miniport。也就是说,C: 盘不是 Microsoft software initiator 走 Windows TCP stack 连出去的,而是直接采用了 iSCSI HBA offload。
这张卡的普通 NDIS interface 和 HBA 自己的 iSCSI IP 是不同的。它的 iSCSI HBA mode 有一套完整的 iSCSI/TCP 实现,而且没有暴露给 Windows,所以 RSS、TCP Chimney、netsh int tcp、NDIS receive buffer 这些全都调不到这条 boot session 头上。它们只能影响后面拿 NDIS 路径跑的 iperf。
PCIe
一度以为这张卡插在 x1 slot(GPT 说 XE2 SFF 是 x1)里——要真是这样便不用再看了。结果一查实际 negotiated link:5.0 GT/s ×4,PCIe 2.0 x4,跑满一个 10GbE port 还是足够的,不是 PCIe link 的问题。
CPU
跑 iperf 时,结果同 CrystalDiskMark 基本一致,Rx 速度很慢,Tx 没有任何问题。运行时整机 CPU 加起来也就一个 core 的量。DPC 确实有,但没有任何一个 core 长期 100%,processor queue length 也基本躺在 0–1。CPU 够用,不是它的问题。
SSD 或 VHDX
在存储服务器上同步看 PerfMon:顺序读期间,后端 read latency 大约 0.27–0.32 ms,disk queue 基本为零,可以 meet 一切读取需求。不是存储的问题。
光纤、MTU
看了一眼 switch counter,CRC/FCS/symbol error 都很少,队列也没有长期堆积。MTU 1500 确实没有 jumbo 省 packet,但一张正常的 10G offload NIC 不会仅仅因为 MTU 1500 就稳定在 300 MB/s,不是它们的问题。
BCM iSCSI
后来另开了一个 test LUN,用同一张 BCM 的 NDIS interface 走 Microsoft iSCSI initiator。它的 queued read 大约 273 MB/s,hardware HBA 那边约 240 MB/s,Q1 read 也基本接近。

这当然证明不了 software initiator 和 L4SC 完全等价,但至少说明问题不太可能单独出现在 L4SC 的 iSCSI 参数或 firmware 里。两条路径共用 BCM 的 physical port、同一根纤、同一台 SX6012、同一个 target,还需继续努力。
测一下纯 TCP iperf:
Workstation -> Storage,iperf3 -P 4:约 8.66 Gbit/s
Storage -> Workstation,iperf3 -P 4 -R:一开始约 1.86 Gbit/s,随后掉到 400–600 Mbit/s,最后甚至 abortTopology 里确实有不对称之处:
写是 10G 进、40G 出;读是 40G 一把倒进 switch,然后从 10G 口慢慢流给 Workstation,倒是也能说明一部分问题,然而好的交换机应该能够处理这种情况。
Retransmission
顺序读的时候,Storage 上 \TCPv4\Segments Retransmitted/sec 涨到约 800–1420/s;测试一停又归零了。那就只能抓包了,抓 Storage 和 Workstation HBA portal 之间这一段:

可以看到,Workstation 在反复回同一个 cumulative ACK —— 后面的 TCP segment 都收到了,但前面缺一个,只能一遍遍确认最后连续收到的位置。Storage 随后 fast retransmit,congestion window 被打断,吞吐急剧下降。经过 GPT 分析,丢的 segment 并不随机:大量集中在 server 端一个 LSO batch 的第 15、16 个 MTU-sized segment 附近。
Storage 使用的是一张洋垃圾 ConnectX-3 网卡并启用了 LSO,所以抓包能看到一些几 KB 到二十几 KB 的大包,这是 host 在 NIC 分段之前看到的 LSO superpacket,不是交换机真的在转发 24KB 的 Ethernet frame。反过来,Workstation 回过来的 60-byte duplicate ACK 是正常的 wire-level 小包。
所以实际发生的事情更像这样:
- ConnectX host stack 交给 NIC 一个约 22–25KB 的 LSO buffer;
- ConnectX 在 40G 线上把它切成 15–17 个普通 frame;
- SX6012 buffer 这段 burst,从 Eth1/8 (Workstation对应口) 的 10G 慢慢发出;
- 一个 frame 在队列尾部被丢掉;
- Workstation 发出 duplicate ACK,Storage 随后 fast retransmit,TCP 收缩 cwnd。
拿一个 24,820 bytes 的 batch 计算一下:40G 进入 switch 只要约 5 µs,10G 吐完要约 20 µs,中间 egress queue 得额外吸收接近 19KB。19KB 本身不算什么,但叠在 lossy traffic class、已有队列占用和 ConnectX 的 burst pattern 上,足够造成 tail drop 了。
当然也没有厂商文档写着 SX6012 必在第十六个包掉包。所以更严谨的说法是:40G 到 10G 的 mixed-speed egress buffering,叠上 LSO 造成的 microburst,是一个和观测对得上的假说。
Lossless 尝试
既然怀疑 switch 有丢包,那就打开 PFC 吧。现有的 SMB Direct/RoCE 已经占了 PCP 3,iSCSI 就单独用 PCP 4:
PCP 3:TCP 445 / UDP 4791
PCP 4:TCP 3260(iSCSI)SX6012 上的关键配置:
configure terminal
dcb application-priority tcp iscsi 4
dcb priority-flow-control priority 4 enable
interface ethernet 1/1
switchport mode access-dcb
switchport access vlan 1000
dcb priority-flow-control mode on force
exit
interface ethernet 1/2
switchport mode access-dcb
switchport access vlan 1000
dcb priority-flow-control mode on force
exitpriority 4 落到 lossless-capable 的 TC2。
在 Storage 上,用 Windows QoS 给 iSCSI traffic 打上 PCP 4,再给 priority 4 开 PFC:
New-NetQosPolicy `
-Name 'iSCSI Priority 4' `
-iSCSI `
-PriorityValue8021Action 4
Enable-NetQosFlowControl -Priority 4
Enable-NetAdapterQos -Name 'SLOT 7 Port 1'注意这里用的是 -iSCSI,不要只匹配 destination TCP port 3260——target 向 initiator 送数据的时候,3260 是 source port。只写 destination port 的话,正好把我们需要修复的那一半流量漏掉了。
最初的设想是把 Eth1/8 也切成 access-dcb,让 BCM HBA 通过 DCBX 完整参与 PFC。BCM57810 毕竟是 CNA,MBA 配置里也能看到 DCB Protocol: Enabled,Dell 的 hardware iSCSI 部署文档也说 HBA 的 DCB 不依赖 Windows software iSCSI stack——看起来万事俱备。
结果 Eth1/8 一改成 access-dcb,Workstation 连 DHCP 都拿不到了;回滚成普通 access VLAN 1000,DHCP 立刻恢复。
问题不在 PFC pause 本身,而在 SX6012 的 port mode:
access: egress 完全 untagged
access-dcb: ingress 仍接收 untagged,egress 会带 VLAN ID 0 的 priority tagVID 0 并不是说这个包加入了 VLAN 1000,只是给原本长得像 access 的流量捎上一个 PCP。而 Workstation 现在这条 PXE/DHCP boot path 不认 DHCP Offer 上的 VID-0 priority tag,于是 boot 还没走到 iSCSI 就先断了。
这并不能说明 BCM HBA 不支持 PFC。它只是说明,下面三件事不能混为一谈:
BCM CNA silicon 支持 DCB/PFC
BCM iSCSI HBA firmware 能独立处理 DCB
BCM PXE DHCP path 默认能接收 VID-0 priority-tagged frame前两件事没问题,第三件事至少在这套 MBA firmware 和这个 switch port mode 的组合下不成立。
MBA 的 VLAN mode 倒是能让 boot firmware 真的去 tag VLAN 1000,但那样 Eth1/8 就得改成 trunk/hybrid,整个 boot path 就是另一套设计了。不值得多费时间,没有再尝试。
只保护坏链接
好消息是,修这个 read throughput 并不需要 Workstation 变成 DCB endpoint。真正的大流量是 Storage 到 Workstation 这段,需要被 pause 的是 40G sender,不是 10G receiver。
Eth1/8 的 10G egress queue 快满时,SX6012 朝 Eth1/1 的 PCP 4 发 PFC pause;ConnectX 把这一小段 priority-4 traffic 暂停,等 queue drain 之后继续。Workstation 全程不需要见到 PCP tag,Windows 7 也不需要知道那条 offloaded iSCSI connection 的存在。
这算不上严格意义的端到端 lossless iSCSI fabric,Workstation 到 Storage 方向的 command 和 ACK 还是 untagged priority 0。但它们很小,也不是 40G -> 10G microburst 的来源。对这个故障来说,先把大流量方向保护住已经够了。
改完之后,SX6012 的 priority counter 变得很清晰:
Eth1/1(Storage port),priority 4
Rx: 13,758,708 packets / 19,205,116,242 bytes
Tx pause: 3,061,424 packets
Eth1/8(Workstation port),priority 4
Tx: 13,471,933 packets / 19,201,736,904 bytes
Tx pause: 0
Tx discard: 0约 19.2 GB 的 iSCSI 数据包带着 priority 4 从 Storage 进来、从 Workstation 口出去;switch 在这段时间里朝 40G source 发了三百多万个 priority-4 pause frame。以前 queue 不够只能 tail drop,现在它会要求 sender 暂停发送,Eth1/8 的 TX discard 也没再涨。
同一套 CrystalDiskMark,SEQ Q8 read 从原来的约 240–306 MB/s 涨到 约 444 MB/s。没有跑满 10GbE,Windows 7 也没有突然变成现代 NVMe-oF client,但只动了 iSCSI Data-In 的 priority 和 PFC,读吞吐大涨,counter 也呈现出预期的 pause 行为。吼了!
就是这么简单!

