
简介《Mellanox Adapters Programmers Reference Manual (PRM) - 3》是面向网络驱动开发与高性能计算运维人员的官方编程指南。文档重点讲解RDMA远程直接内存访问技术以及NVConfig模块中NV_SW_OFFLOAD_CAP结构体的位级定义涵盖VXLAN协议支持、基于名称的内存密钥mkey_by_name、PCI原子操作模式等关键特性。手册通过表346、表347逐位说明硬件与固件配置能力帮助读者精确控制适配器卸载功能降低CPU开销。资源包为单个PDF文件大小8.65MB内容为Mellanox官方技术文档适合作为底层网络编程的权威参考。目前已有73人学习下载。掌握这些细节可直接用于数据中心、HPC及云环境中适配器调优对需要高吞吐、低延迟的应用场景尤其具有实用价值。1. 这份 PRM 第三卷不是给你通读的NVConfig 位域才是 RDMA 调优的最终解释权拿到这份 PRM 第三卷的工程师通常不是来通读的而是带着具体问题翻页的RoCE 拥塞控制算法选 HPCC 还是 DC2QCN某个支持位明明是 TRUE为什么我配的字段不生效手册里那几十张 NVConfig 表Layout 上每个 bit 都写着 When set但没人告诉你哪些能写、哪些只是固件能力声明。这份手册的技术价值恰恰在于此——它把 RDMA 网卡侧的非易失配置NVConfig按 TLV 结构拆到了位级是“寄存器位叫什么、在哪个偏移、对应配置工具参数叫什么、能力位和配置位怎么配对”这条链路的最终解释权。适合三类人调 RoCE/RDMA 性能的运维工程师、做驱动或固件适配的开发、需要写自动化配置脚本的 SRE。新手靠它建立查表习惯熟手靠它把模糊认知变成可交付的配置项。2. 读 NVConfig 表的正确姿势Layout、位域类型与 Cap/Conf 配对很多人第一次翻这份 PRM目光直接跳到具体参数却不知道 NVConfig 每一张表背后有一套固定的表达语法。如果不懂这套语法照着字段名抄进配置文件大概率会在重启后收获一台行为诡异的网卡。这一章先把表读明白再讲固件里最常见的“能力位 配置位”双结构设计。2.1 Layout 和 Field Descriptions位号、偏移与类型先看 Table 346 这类 Layout 表。表头只有一行 31 到 0 的数字表示一个 32bit 寄存器的位序从高位到低位排列。注意这里不是字段编号而是“位号”。真正有用的信息在随后的 Field Descriptions 表里Offset 表示从结构体起始地址开始的偏移Bits 表示字段占据的位范围Name 是字段名Type 分 BOOL、ENUM、UNSIGNED、BINARY、BYTES 几类Description 才是决定你该怎么用它的关键。以 NV_SW_OFFLOAD_CAP 的字段表为例我摘几个有代表性的OffsetBitsNameTypeDescription 要点00h31ip_over_vxlan_supportedBOOL置 1 时NV_SW_OFFLOAD_CONFIG 里的 ip_over_vxlan_en 和 ip_over_vxlan_port 才可配置00h30mkey_by_name_supportedBOOL置 1 时NV_HCA_CONF 的 mkey_by_name 可配置00h28pci_atomic_ics_enabled_ext_atomics_enabledBOOL置 1 时PCI 原子操作支持扩展原子使能模式00h22tunnel_ecn_copy_offload_disable_supportedBOOL置 1 时卸载配置里对应的 ECN 复制禁用开关才可用00h20max_outstanding_wqe_supportedBOOL置 1 时单个发送队列的 outstanding WQE 上限可配置00h17tx_psn_win_supportedBOOL置 1 时log_tx_psn_win 可配置00h7prio_tag_required_supportedBOOL置 1 时prio_tag_required_en 可用这类字段有个共同点名字以 _supported 结尾Description 里反复出现 “When set to TRUE ... is configurable”。它们描述的是“固件能不能干这件事”而不是“现在要干这件事”。我见过不止一个同事把 ip_over_vxlan_supported 直接改成 TRUE然后配置了一个 IP over VXLAN 的端口结果网卡既不报错也不生效——因为真正要动的开关在另一个结构里。所以读表的第一原则是先分清字段名后缀_supported 结尾是只读能力声明_enable 结尾才是可写配置位。Type 列的 BOOL 也容易误导人。它表示这个位是布尔语义但不代表你可以在任意地址写一个 1。在 NVConfig 的二进制视图里这些位都封装在固定 TLV 里靠工具或驱动接口写入。手动改偏移之前必须确认对应位没有被标记为保留。保留位在这个手册里通常是空行或者描述里写 reserved别去碰碰了轻则配置被忽略重则整段 TLV 校验失败。2.2 Cap 与 Conf 成对出现先读支持位再写配置位顺着刚才的思路你会发现NVConfig 的结构命名存在明显配对规律。手册里经常是一个 NV_XXX_CAP 结构配一个 NV_XXX_CONFIG 或 NV_XXX_CONF 结构。CAP 是能力描述CONF 是实际配置。常见的有三组NV_SW_OFFLOAD_CAP 对应 NV_SW_OFFLOAD_CONFIGNV_HPCC_INT_CAP 对应 NV_HPCC_INTNV_PERFORMANCE_TUNING_CAP 对应 NV_PERFORMANCE_TUNING_CONF为什么固件设计要拆成两个结构因为同一份手册面向多个固件版本A 版本支持 HPCC 拥塞控制B 版本可能只支持 DC2QCN。如果手册只写一套配置结构B 版本的工程师把字段写下去固件只能静默吞掉。有了 CAP 结构之后软件可以先读能力位再决定要不要暴露某个配置项。这本质上是设备侧的 feature discovery 机制。所以我判断一个 NVConfig 字段能不能用的标准动作是四步找到该配置所属的 CAP 结构比如要动 NV_HPCC_INT先翻 NV_HPCC_INT_CAP。在 CAP 表里找对应的 _supported 位确认它是 TRUE。回到 CONF 结构确认目标字段满足 Description 里写的 Valid only if 条件。最后才去搜索这个字段的 mlxconfig_name用配置工具写入。顺序反了就会出现典型翻车配置写进去了query 也能看到值但实际硬件行为完全没变。原因就是第 2 步没做支持位本身就是 FALSE固件根本不认这个配置字段。另外要注意CAP 和 CONF 的字段名不是完全镜像关系。比如 NV_SW_OFFLOAD_CAP 里的 max_outstanding_wqe_supported对应配置可能叫 max_outstanding_wqe 而不是 max_outstanding_wqe_enable。NV_HPCC_INT_CAP 里的 np_rtt_int_data_mode_last_hop对应配置字段叫 np_rtt_int_data_mode取值 0x0 表示 LAST_HOP。命名带不带后缀只能靠 Description 里的引用关系判断别凭名字猜。3. 把手册字段翻译成 mlxconfig 参数HPCC、RoCE 算法选择与 ZTT读懂了位域之后下一个现实问题是手册里这些 TLV 结构怎么落到实际配置命令里该厂商网卡的配置工具统一走 mlxconfigPRM 每个可配置字段下面有一行小字标注 mlxconfig_name这就是工具暴露出来的参数名。这一章直接从三组高频配置展开看完就能照着敲命令。3.1 通过 mlxconfig_name 找参数PRM 里每个配置字段的 Description 最后一行通常写着 mlxconfig_name: XXX。这句话是手册和命令行之间的桥。比如 NV_HPCC_INT 的 hpcc_int_en 字段标注 mlxconfig_name: HPCC_INT_EN意味着你在 mlxconfig 里写的参数名就是 HPCC_INT_EN和 README 里的缩写一致np_rtt_response_dscp 字段对应的参数名是 HPCC_INT_NP_RTT_DSCP跟表里的字段名几乎一一对应。拿到一个新设备后的常规动作是先枚举当前参数# 查询当前设备所有 NVConfig 参数 mlxconfig query /dev/mst/card0 # 只查某个参数以 HPCC_INT_EN 为例 mlxconfig query /dev/mst/card0 --query HPCC_INT_EN参数说明/dev/mst/card0 是 mst 工具暴露的设备节点实际名称通过 mst status 获取不同服务器上可能是 card0、card1 或带总线号的名字。query 输出里会直接打印参数名、当前值和默认值。注意参数名区分大小写HPCC_INT_EN 写成 hpcc_int_en 会提示找不到参数。我一般会先跑一次不带任何过滤条件的完整 query把输出存成基线文本后续改坏了可以直接对照。3.2 NV_HPCC_INTINT 数据模式、DSCP 与 system_rtt 的取舍NV_HPCC_INT 是 HPCC 拥塞控制算法在网卡侧的核心配置。最该关注四个字段HPCC_INT_EN总开关。HPCC_INT_NP_RTT_DATA_MODE表示 RTT 响应数据怎么取0x0 表示 LAST_HOP取报文的最后一个遥测条目0x1 表示 MOST_CONGESTED取路径上拥塞最严重的遥测条目。HPCC_INT_NP_RTT_DSCP_EN 与 HPCC_INT_NP_RTT_DSCP是否用指定 DSCP 生成 RTT 响应以及 DSCP 取值。HPCC_INT_SYSTEM_RTT系统 RTT 估计值单位纳秒0x0 表示用设备默认值。实际配置命令mlxconfig set /dev/mst/card0 \ HPCC_INT_ENTRUE \ HPCC_INT_NP_RTT_DATA_MODEMOST_CONGESTED \ HPCC_INT_NP_RTT_DSCP_ENTRUE \ HPCC_INT_NP_RTT_DSCP26 \ HPCC_INT_SYSTEM_RTT2000逻辑说明MOST_CONGESTED 适合长路径、多拥塞点的场景交换机在 INT 报文里逐跳叠加拥塞信息通知点取最拥塞的那一跳LAST_HOP 适合单点瓶颈明确的场景比如一跳接入交换机。把 DSCP_EN 置 TRUE 后通知点生成的 RTT 响应会使用固定 DSCP便于抓包时快速识别响应报文如果保持 FALSE响应报文的 DSCP 直接从请求报文拷贝两端不一致时很容易在抓包里认错流。参数说明DSCP 是 6 bit 字段取值范围 0 到 6326 对应 AF31 的常见标记实际用多少要和交换机 QoS 策略一致。system_rtt 如果设太小HPCC 的拥塞窗口计算会激进如果设太大收敛变慢。拿不准就用默认值让设备根据实际 RTT 自学习PRM 里 0x0 的语义就是使用设备默认。3.3 NV_GLOBAL_ROCE_CC_CONF算法选择不是一锤子买卖RoCE 拥塞控制的算法协商在连接建立时发生mlxconfig 只是把“本端愿意参与哪些算法、偏好哪个算法”写进固件。对应 PRM 的 NV_GLOBAL_ROCE_CC_CONF 结构四个位段决定行为ROCE_CC_ALGO_SELECT_VALID总开关FALSE 时一切算法配置位都无效固件用出厂默认算法。preferred_algo枚举值0x0 是 TIMELY0x1 是 HPCC0x2 是 DC2QCN0x6 是用户自定义算法。各个算法使能位algo_timely_enable、algo_hpcc_enable、algo_dc2qcn_enable、algo_user0_enable。命令示例mlxconfig set /dev/mst/card0 \ ROCE_CC_ALGO_SELECT_VALIDTRUE \ ROCE_CC_HPCC_ALGO_ENABLETRUE \ ROCE_CC_DC2QCN_ALGO_ENABLETRUE \ ROCE_CC_PREFERRED_ALGOHPCC逻辑说明这里把 HPCC 和 DC2QCN 同时使能再把 HPCC 设为首选这样对端只支持 DC2QCN 时协商能落到 DC2QCN对端也支持 HPCC 时优先跑 HPCC。ROCE_CC_ALGO_SELECT_VALID 是总闸后面的使能位全部带 Valid only if 条件只改使能位不改总闸等于白写。参数说明PREFERRED_ALGO 的取值在 mlxconfig 里可以直接写 HPCC 或 DC2QCN 字符串也可以写枚举数字 1 或 2。文本形式可读性好但在脚本里我习惯写数字避免不同固件版本对字符串解析的差异。算法协商过程对驱动和交换机是个半透明过程失败时网卡不会报错只会默默用默认算法这是最典型的黑匣子行为——你只能靠两端配置一致性来保证结果不能靠网卡日志。4. 查询、修改与持久化mlxconfig 全流程和配置文件优先级参数说明部分已经能看出 mlxconfig 的操作套路这章把完整流程串一遍从 mst 启动到设备节点确认从 set 写入到验证生效再加上 NVConfig 分区里文件优先级导致的“配置被覆盖”问题。前两步是日常高频操作第三步是重启后配置失踪的根因。4.1 先启 mst再拿到设备节点mlxconfig 操作的对象不是网卡 PCI 设备本身而是 mst 暴露出来的配置通道。所以第一步永远是启动 mst 驱动并确认设备列表mst start mst status执行 mst status 后输出里会列出若干设备找到带 pciconf 字样的条目比如 /dev/mst/card0_pciconf0。这里有个常见误区有的人直接拿 /dev/infiniband/rdma0 去执行 mlxconfig会得到设备不支持的报错。mlxconfig 只认 mst 的 pciconf 节点。说明mst start 把底层固件访问通道打开mst status 展示当前机器的适配器列表。如果列表为空先检查驱动是否加载、网卡是否被系统识别不要直接怀疑工具坏了。4.2 query 与 set改之前留基线改之后立刻复核我习惯按“先备份、再修改、后复核”三步走。备份不是指文件备份而是把当前完整参数快照留下来mlxconfig query /dev/mst/card0_pciconf0 nvconfig_baseline.txt然后执行修改mlxconfig set /dev/mst/card0_pciconf0 \ HPCC_INT_ENTRUE \ HPCC_INT_SYSTEM_RTT2000最后再 query 一次确认参数值确实写进去了。注意 set 命令的输出会提示 Apply 或 Reboot 要求部分 NVConfig 参数写入 flash 后要等下次固件启动才加载另外一部分尤其是性能和卸载相关可能需要重启网卡驱动。判断标准很简单set 完成后立刻 query看到的值如果还是旧值别慌等重启后再看如果已经是新值但不生效大概率是 Cap 位问题。4.3 NV_FILE_ID 与配置优先级为什么重启后配置会“蒸发”PRM 第 11.6.36 和 11.6.37 两个 TLV 专门描述配置文件本身NV_FILE_ID_MLNX 和 NV_FILE_ID_VENDOR。它们的字段包括 file_version32bit 版本号、eraser_low_priority 标志以及 year/month/day/hour/minutes/seconds 时间戳。关键在 eraser_low_priority 的语义字段含义实际影响erase_low_priority安装该文件时擦除所有更低优先级的 NVCONFIG 参数高优先级文件一装低优先级配置全被清file priority MLNX安装时不从当前 NVDAT 分区拷贝任何 TLV原配置不会迁移到新文件file priority VENDOR_NVCONF安装时只拷贝 MLNX 级 TLV厂商级配置被保留自定义配置被覆盖这解释了重启后配置“蒸发”的根因你直接通过 mlxconfig set 写的参数属于默认优先级而固件更新或别人安装了一个高优先级配置文件后低优先级参数被整体擦除。时间戳字段用 4 位 BCD 编码固件在拷贝文件时会顺带写入签名时间所以发现配置异常时先看这个日期能判断是什么时候被覆盖的。我现在的习惯是每次设备上线前把 mlxconfig query 快照和 PRM 字段表放一起git 提交一份固件升级后立刻 diff 一次。配置漂移能在几分钟内定位而不是等业务报障后再去翻黑匣子。5. 避坑NVConfig 参数改错后的五个翻车现场这一章写几件我真实调过的踩坑案例。每条都按现象、原因、解决三个环节拆开方便新手对照排查。老手可以直接把它当排查清单用。5.1 HPCC_INT_EN 置 TRUE但拥塞控制没生效现象mlxconfig query 里 HPCC_INT_EN 已经是 TRUERTT 抓包也能看到 INT 报文但交换机的拥塞反馈行为没有任何变化流量还是持续丢包。原因漏了 NV_HPCC_INT_CAP 的能力检查。部分固件版本的 hpcc_int_en 写入会被接受但内部不使能因为对应的 np_rtt_int_data_mode 能力位为 FALSE固件只能忽略这个配置。解决先跑mlxconfig query /dev/mst/card0 --query HPCC_INT_EN确认写入再翻 PRM 的 NV_HPCC_INT_CAP 表确认 np_rtt_int_data_mode_last_hop 或 np_rtt_int_data_mode_most_congested 是 TRUE。如果能力位为 FALSE换一种拥塞算法别在 HPCC 上死磕。5.2 把“位 28”当字段编号脚本配置到无关参数现象照着 PRM 写自动化脚本想把 pci_atomic_ics_enabled_ext_atomics_enabled 置 1结果网卡出现了意外的 PCIe 原子操作失败日志。原因Layout 表里 31 到 0 是位序不是字段编号。有人直接用位号当字段 ID 去脚本里做偏移位 28 偏移算错写到了别的字段上。PCI 原子操作模式的字段是枚举组合不是单 bit 开关用位号直接算偏移必然翻车。解决改配置一律用字段名让 mlxconfig 或驱动接口去解析偏移不要自行按位号写寄存器。脚本里把字段名写成映射表从 PRM 文本里抽出来维护减少手算偏移的机会。5.3 重启后参数归零回到出厂默认现象昨天 mlxconfig set 的 ZTT 调优参数今天重启后全部丢失query 输出和出厂基线一致。原因配置写入的优先级低于某个高优先级配置文件。按 PRM 的优先级语义高优先级文件安装时会擦除低优先级 NVCONFIG 参数。最常见场景是固件升级脚本顺手装了一个 VENDOR_NVCONF 优先级的配置把手工参数清掉了。解决确认设备当前生效的配置文件优先级看 NV_FILE_ID_MLNX 或 NV_FILE_ID_VENDOR 的日期。如果是固件升级触发升级后必须重放一次配置脚本。我现在所有配置都写成幂等脚本重启或升级后跑一遍而不是手工 set。5.4 DSCP 值写进去了但 RTT 响应报文的 DSCP 依然不对现象HPCC_INT_NP_RTT_DSCP 设成 46抓包发现 RTT 响应报文的 DSCP 还是原来的值。原因漏了 HPCC_INT_NP_RTT_DSCP_EN。这个字段是独立开关只有把它置 TRUEDSCP 字段才生效否则固件按 Description 里的规则直接拷贝 RTT 请求报文的 DSCP 值。另一个原因是 DSCP 在 6 bit 字段里的编码46 写成二进制是 101110如果误当成 8 bit 值写进去固件只取低 6 位值就变成 14。解决先确认 VIP 字段是 TRUE再确认 DSCP 取值在 0 到 63 之间。如果不确定当前值是几进制先 query 看原始输出再对着 PRM 算一遍位宽。5.5 ZTT 相关参数改了性能没有变化现象NV_PERFORMANCE_TUNING_CONF 的 ztt_enable 设为 TRUE运行同样的测试吞吐和延迟完全没有变化。原因ZTTZero Touch Tuning是设备自动调优流程不是手动调优开关。ztt_enable 只是允许固件在后台跑自动优化优化依赖运行时状态和负载特征不是设了立刻改参数。NV_PERFORMANCE_TUNING_CAP.ztt_supported 为 FALSE 时这个开关本身就是摆设。解决先查能力位确认支持。再理解 ZTT 的触发条件它通常在设备空载或特定训练流程里生效跑业务时改它不会立即变化。想要确定性调优改对应的显式性能参数比如队列深度、中断聚合时间而不是依赖 ZTT。6. 进阶从 PRM 文本自动提取 mlxconfig_name生成固件参数对照表到这里手册已经能读、配置已经能写、坑已经知道在哪。剩下的效率问题是如何批量建立“PRM 字段 ↔ mlxconfig 参数 ↔ 当前固件实际暴露参数”的对照关系。手工翻几百个 TLV 不现实这一章给一个我常用的半自动流程。6.1 提取所有 mlxconfig_namePRM 第三卷如果导出成 txt每个可配置字段的 Description 末尾都有 mlxconfig_name 标记。写个小脚本就能抓全import re from pathlib import Path raw Path(prm3.txt).read_text(encodingutf-8, errorsignore) # 先合并被 PDF 分行拆开的行再抽 mlxconfig_name merged re.sub(r\n\s*, , raw) names re.findall(rmlxconfig_name:\s*([A-Z][A-Z0-9_]), merged) names list(dict.fromkeys(names)) # 去重且保留顺序 for name in names: print(name)逻辑说明PDF 转文本后长字段名经常被断行拆开比如 NV_HCA_CONF 和后面的 pci_atomic_mode 之间可能夹了换行所以先用正则把所有换行替换成空格再统一抽取。正则里的[A-Z][A-Z0-9_]匹配以大写字母开头的参数名能盖住绝大多数 mlxconfig_name。参数说明抽取结果是一份参数清单建议直接存成文本文件作为后续和 query 输出做 diff 的基准。如果 PRM 版本更新重新导出一遍再跑一次git diff 能看到新增和废弃的参数名。6.2 和 mlxconfig query 输出做差集拿到参数清单后把它和真实设备的 query 输出对一下就能知道哪些参数在当前固件里可见、哪些不存在mlxconfig query /dev/mst/card0_pciconf0 | grep -oP ^\s*\K[A-Z0-9_](?|:) | sort -u query_params.txt这里 grep 提取每行开头的参数名按实际 query 输出格式调整分隔符。然后本地做 diffdiff prm_params.txt query_params.txt逻辑说明PRM 里有的参数在当前固件中看不到原因基本是 Cap 能力位为 FALSE固件把不支持的配置项隐藏了query 里多出来的参数也可能是厂商自定义的非公开项。做完 diff 才知道哪些配置能放心改哪些只是在手册里存在。从那以后我每次拿到新固件都强制走一遍“PRM 抽参—query 对照—改后再查 Cap”的流程低级的位域翻车基本绝迹了。这份 PRM 第三卷适合放在手边当字典而不是从头读到尾的教材。希望帮到你。本文还有配套的精品资源点击获取