分析对象:
MLNX_OFED_SRC-24.10-5.1.6.1/install.pl(4250 行)+common.pl(832 行公共函数库)安装命令:
sudo perl install.pl --all说明:本文仅做静态分析,未实际执行安装。
bash
wget https://www.mellanox.com/downloads/ofed/MLNX_OFED-24.10-5.1.6.1/MLNX_OFED_SRC-debian-24.10-5.1.6.1.tgz
1. 软件包结构与脚本角色
本包是 Debian/Ubuntu 系的源码分发包(SRC 版),不是预编译二进制包:
MLNX_OFED_SRC-24.10-5.1.6.1/
├── install.pl # 主安装脚本(Perl,4250 行),入口 main() 在 4110-4245 行
├── common.pl # 公共函数库(root 检查、PCIe 检测、os-release 解析、DKMS 清理等)
├── SOURCES/ # 29 个 <name>_<ver>.orig.tar.gz 源码包,每个内含 debian/ 打包目录
├── DEBS/ # 初始为空;构建出的 .deb 输出到 DEBS/<distro>/<arch>/
├── uninstall.sh # 卸载脚本(系统装好后为 /usr/sbin/ofed_uninstall.sh)
├── BUILD_ID # 记录 24.10-5.1.6.1 各组件源码版本/commit
└── LICENSE
构建模型:install.pl 按选择的包列表,逐个解开 SOURCES 下的源码包,用 dpkg-buildpackage 现场编译出 .deb,再用 dpkg -i 安装。即"先构建、后安装"。
退出码约定(install.pl 40-48 行):0 成功;1 通用错误;171 无硬件;172 前置条件不满足(如非 root、缺依赖);173 mst 启动失败;174 有非 OFED 包依赖需先手动移除。
2. 初始化与命令行参数解析
2.1 初始化(install.pl 50-173 行)
-
设置环境:
LANG=C、DEBIAN_FRONTEND=noninteractive(避免 apt/dpkg 交互提问) -
chdir到脚本所在目录,定义工具路径:/usr/bin/dpkg、/usr/bin/dpkg-query、/usr/bin/dpkg-buildpackage、/sbin/modinfo等 -
采集平台信息:
bashuname -m # 架构 $arch uname -r # 内核版本 $kernel # 内核头文件目录:/lib/modules/$(uname -r)/build -
交叉编译检测:若环境变量
ARCH与本机不同则启用交叉编译模式 -
BlueField 检测(167 行):
bashlspci -s 00:00.0 | grep -wq "PCI bridge: Mellanox Technologies"
2.2 参数解析(178-374 行)
--all 的效果(181-183 行):
perl
$install_option = 'all'; # 安装所有可用包
$force_all = 1; # 不允许被 .def_option 或其它选项覆盖
其余支持的参数类别:
| 类别 | 参数 |
|---|---|
| 安装集合 | --all --basic --hpc --msm --bluefield --vma(-vpi/-eth) --xlio --guest --hypervisor --eth-only --dpdk |
| 过滤 | --kernel-only --user-space-only --with-<pkg> --without-<pkg> --fwctl |
| 内核/DKMS | --force-dkms --without-dkms -k <ver> -s <path> --kernel-extra-args --with-memtrack --without-mlx5-ipsec |
| 依赖检查 | --without-depcheck --check-deps-only |
| 行为控制 | --force -b/--build-only(仅限与 --kernel-only 同用)--distro --tmpdir --builddir |
| 配置 | -c <ofed.conf> -n <网络配置> --conf-dir -p/--print-available |
| 钩子 | --pre/post-build-<pkg> <脚本>、--pre/post-install-<pkg> <脚本> |
| 输出 | -q -v -vv -vvv |
参数校验后做 root 权限检查 (372-374 行,common.pl: check_root_user()):非 root 直接退出(码 172)。
3. 发行版识别与包名决策
- DKMS 可用性预检 (449-462 行):若内核头文件目录不是由 deb 包安装的(
dpkg -S /lib/modules/$(uname -r)/build/scripts失败),自动关闭 DKMS(除非--force-dkms)。 - 发行版检测 (464-489 行,
common.pl: os_release()):读取/etc/os-release的ID+VERSION_ID(Debian 改读/etc/debian_version),拼出如ubuntu22.04、debian12;仅支持 debian/ubuntu/uos,否则红字报错退出。uos 强制禁用 DKMS。 - 内核包名决策 (496-524 行):DKMS 模式下内核类包名为
mlnx-ofed-kernel-dkms、kernel-mft-dkms、knem-dkms、xpmem-dkms、iser/isert/srp/mlnx-en/mlnx-nfsrdma/mlnx-nvme/mlnx-rdma-rxe/fwctl-dkms;--without-dkms时换为-modules后缀。 - 发行版相关依赖名适配 (849-929 行):按 distro 确定
libssl3/libssl1.1、libelf1(t64)、kmod、libsystemd-dev、libgfortranN、linux-headers-generic(Debian 用linux-headers-$(dpkg-architecture -qDEB_TARGET_ARCH))、CUDA 12-6 等。 - 创建输出目录:
DEBS/<distro>/<arch>/(837-839 行)。 - 模块与包数据库 :
- 内核模块组(934-944 行):基础组
core mlxfw mlx5 ipoib mlxdevm,ULP 组sdp srp srpt rds iser e_ipoib nfsrdma isert %kernel_modules_info(957-1015 行):模块依赖关系(如mlx5 requires core、ipoib requires core、srp requires core+ipoib)%packages_info(1018-1943 行):每个包记录parent(对应 SOURCES 下哪个源码包)、dist_req_build/dist_req_inst(发行版依赖)、ofa_req_build/ofa_req_inst(OFED 内部依赖)、soft_req
- 内核模块组(934-944 行):基础组
4. main() 主流程逐步分析
main()(4110-4245 行)按以下顺序执行:
步骤 1:解析网络配置文件(仅给 -n/--net 时,4116-4154 行)
读取 IPADDR_ibX=、NETMASK_ibX=、NETWORK_ibX=、BROADCAST_ibX=、ONBOOT_ibX=、LAN_INTERFACE_ibX= 存入 %ifcfg。--all 未带此参数,跳过。
步骤 2:set_availability()(3719-3931 行)------按平台裁剪可用包/模块
-
ARM/aarch64 禁用 dapl 系;fbk 内核/ARM 禁用 sdp
-
检测
cuda-cudart-dev-12-6是否已装(dpkg-query),有则启用 ucx-cuda -
VMA/XLIO 只在特定 OS+架构可用;BlueField 主机上禁用 rshim
-
isert需要内核CONFIG_ISCSI_TARGET=1,iser需要CONFIG_ISCSI_TCP=1(用check_autofconf()实查):bashtac /lib/modules/$(uname -r)/build/include/*/autoconf.h | grep -m1 CONFIG_XXX -
nfsrdma 只对特定内核版本启用(5.x/6.x 等);mlxdevm 要求内核 ≥ 4.15;fwctl 默认关(需
--fwctl) -
处理
--without-/--disable-<pkg>(disable_package()递归禁用依赖它的包)与--with-/--enable-<pkg>
步骤 3:set_cfg()(3379-3393 行)------登记源码包
遍历 SOURCES/*,从文件名解析 <name>_<version>.orig.tar.gz,登记到 %main_packages(名称、版本、tarball 路径)。
步骤 4:select_packages()(2661-2932 行)--------all 的选包逻辑
--all 分支(2730-2744 行):把 @all_packages(580-627 行定义)中 available=1 且有源码 tarball 的包全部选入 @selected_by_user,同时选中全部可用内核模块,并把这些选择写入配置文件 ofed-all.conf(每行 包名=y / 模块名=y)。
@all_packages 完整清单:
- 内核/驱动:
mlnx-ofed-kernel-utils、mlnx-ofed-kernel-dkms、iser-dkms、isert-dkms、srp-dkms、mlnx-nfsrdma-dkms、mlnx-nvme-dkms、mlnx-rdma-rxe-dkms、fwctl-dkms - RDMA 用户态(parent 多为 rdma-core):
libibverbs1、ibverbs-utils、libibverbs-dev、libibverbs1-dbg、ibverbs-providers、libibumad3、libibumad-dev、ibacm、librdmacm1、rdmacm-utils、librdmacm-dev、libibmad5、libibmad-dev、infiniband-diags - 子网管理/诊断:
opensm、libopensm、opensm-doc、libopensm-devel、ibutils2、cc-mgr、ar-mgr、dump-pr、ibsim、ibsim-doc - 固件工具:
mstflint、mft、kernel-mft-dkms - HPC 栈:
ucx、ucx-cuda、sharp、hcoll、openmpi、mpitests、knem+knem-dkms、xpmem+xpmem-dkms、libxpmem0、libxpmem-dev - 加速/其它:
libdapl2、dapl2-utils、libdapl-dev、libvma系、libxlio系、dpcp、sockperf、perftest、srptools - 工具与杂项:
ofed-scripts、mlnx-tools、mlnx-ethtool、mlnx-iproute2、rshim、ibarr
选中的内核模块(@kernel_modules):core mlxfw mlx5 ipoib mlxdevm + 可用的 ULP(srp iser isert nfsrdma 等,sdp/srpt/rds/e_ipoib 默认 available=0)。
步骤 5:set_existing_debs()(3364-3377 行)
扫描 DEBS/<distro>/<arch>/*.deb,登记已有二进制包(-modules 包只认当前内核版本的)。
步骤 6:resolve_dependencies()(3518-3556 行)
select_dependent()递归:按ofa_req_build(构建期)与ofa_req_inst(安装期)把缺失的 OFED 内部依赖补选进@selected_packages(例如ucx需要libibverbs-dev,openmpi需要hcoll/ucx/knem等软依赖)select_dependent_module()递归补齐内核模块依赖(如选了srp自动补core、ipoib)- 若
mlnx-ofed-kernel已有现成 deb,解开检查所选模块是否都在其中(is_module_in_deb(),对 dkms 包解析dkms.conf的BUILT_MODULE_NAME),缺模块则标记重编
一个包都没选中 → 报错退出(4165-4168 行)。
步骤 7:打印选中清单 + 依赖检查 check_linux_dependencies()(2134-2215 行)
检查项:
@required_debs:autotools-dev autoconf automake debhelper chrpath build-essential(383 行)- 内核类包需要
/lib/modules/$(uname -r)/build/scripts存在(即 linux-headers 已装) - 若内核 ≥4.14 且
CONFIG_UNWINDER_ORC=y/CONFIG_STACK_VALIDATION=y,需要libelf-dev - 每个选中包的
dist_req_build(构建依赖,如 cmake、libnl-3-dev、pkg-config...)与dist_req_inst(运行依赖,用dpkg-query -l检查)
有缺失时(2193-2209 行):先清理残留的失败 DKMS 包,再自动补装:
bash
dpkg --purge <失败的*-dkms包> # purge_failed_dkms_packages()
apt-get update
apt-get install -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' <缺失包...>
(--check-deps-only 模式下只打印 apt-get install ... 建议并退出 172。)
步骤 8:卸载旧版本 uninstall()(4028-4105 行)
打印警告:"all other Mellanox, OEM, OFED, RDMA or Distribution IB packages will be removed",然后:
-
若系统已有旧版 OFED(
which ofed_uninstall.sh存在):先运行旧卸载器bashyes | MLNX_OFED_COMPONENTS="kernel user" ofed_uninstall.sh [--force] -
用
@remove_debs(377 行,约 200 个历史/冲突包名:旧 OFED、发行版自带 rdma-core/libibverbs、mlnx-en、mft 等)匹配已安装包:bashdpkg-query -l "*<name>*" -
get_requires()递归找出依赖这些包的其它包(除非--force,发现非 OFED 依赖即退出 174;qemu-system-* 系列免疫不删):bashdpkg --purge --dry-run '<pkg>' | grep "depends on" -
修复 dpkg 数据库:
bashdpkg --configure -a --force-all --force-confdef --force-confold apt-get install -f -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' -
批量卸载并清除残留配置:
bashapt-get remove -y <包列表> apt-get remove --purge -y <处于 config-files 状态的包> -
清理 DKMS 源目录:
bashrm -rf /usr/src/mlnx-ofed-kernel*
步骤 9:构建并安装新包 install_selected()(2964-3327 行)------核心环节
对 @selected_packages 中每个包依次:
-
清理一批环境变量(
DEB_CONFIGURE_EXTRA_FLAGS、KVER、MLX5等,2975-2994 行) -
先在
DEBS/<distro>/<arch>/找匹配版本的现成 .deb(内核包额外匹配kver.<内核版本>并校验模块齐全)------有则直接跳到第 5 步安装 -
构建 (3057-3256 行):
bashrm -rf /var/tmp/<parent> && mkdir -p /var/tmp/<parent> cp SOURCES/<parent>_<ver>.orig.tar.gz /var/tmp/<parent>/ tar xzf <源码包> && cd <parent>-<ver>按包设置构建环境,典型如:
mlnx-ofed-kernel:生成configure_options------按选中模块拼--with-core-mod --with-user_mad-mod --with-user_access-mod --with-addr_trans-mod --with-mlxfw-mod --with-mlx5-mod --with-ipoib-mod --with-srp-mod --with-iser-mod --with-isert-mod --with-mlxdevm-mod --with-nfsrdma-mod等;内核开CONFIG_XFRM_OFFLOAD+ESP offload 时加--with-mlx5-ipsec;--with-memtrack、--with-gds(GPUDirect)- 非 DKMS 模式:设
WITH_DKMS=0、KVER、K_BUILD=<内核头目录>,加-Pmodules,并用debian/control.no_dkms替换debian/control openmpi:--prefix=/usr/mpi/gcc/openmpi-<ver>、Mellanox 优化 platform;mpitests需先设MPI_HOMErdma-core:无 pyverbs 时加nopyverbs构建选项
然后执行构建与收集:
bashdpkg-buildpackage -us -uc [-P...] # 日志:/tmp/OFED.<pid>.logs/<name>.debbuild.log cp ../*.deb DEBS/<distro>/<arch>/构建失败 →
addSetupInfo()收集调试信息后退出 1。支持--pre/post-build-<pkg>钩子脚本。 -
构建后再次 glob 确认 .deb 已产出,没有则报错退出
-
安装 (3259-3269 行):
bashdpkg -i --force-confmiss [--force-breaks] <debs...> # 日志:<name>.debinstall.log(
--force-confmiss恢复缺失配置文件;ubuntu24/debian13+ 的 ibverbs 包加--force-breaks;支持--pre/post-install-<pkg>钩子。) -
内核包安装后验证 (3290-3316 行):
bash/sbin/depmod <内核版本> /sbin/modinfo -k <内核版本> mlx5_core # 以及 mlx5_ib/knem/xpmem/mst_pci/ib_iser/ib_isert/ib_srp/rpcrdma/nvme_rdma/rdma_rxe/fwctl... dpkg -S <模块文件路径> # 确认 .ko 属于新装的包而非内核自带验证失败 → 收集日志并调用
ofed_uninstall.sh --force整体回滚,退出 1。
步骤 10:IPoIB 网络配置(仅给 -n 时,4224-4226 行)
若 ipoib 模块在新装内核包中,ipoib_config()→config_interface() 把各 ibX 的静态地址写入 /etc/network/interfaces(先删旧段落再追加 auto ibX/iface ibX inet static...)。--all 单独使用时跳过。
步骤 11:安装后系统配置
-
set_vma_flags()(3573-3617 行):装 VMA 时改写/etc/modprobe.d/mlnx.conf(写入options mlx4_core fast_drop=1、log_num_mgm_entry_size=-1);改写/etc/infiniband/openib.conf强制SDP_LOAD=no、QIB_LOAD=no(VMA 时另设SET_IPOIB_CM=no) -
set_mlnx_tune()(3933-3959 行):把openib.conf中RUN_MLNX_TUNE=置为 yes/no(默认 no,--enable-mlnx_tune才开) -
set_opensm_service()(3561-3568 行):bashsystemctl disable opensmd # 默认(--all 不带 --enable-opensm 时) # systemctl enable opensmd # 仅 --enable-opensm/--msm 时 -
--umad-dev-rw/-na时(本命令未用):写/etc/udev/rules.d/91-ib-permissions.rules调整 umad 设备权限 -
--copy-ifnames-udev时(本命令未用):拷贝82-net-setup-link.rules与vf-net-link-name.sh
步骤 12:PCIe 链路健康检查与收尾(4240-4244 行)
check_pcie_link()(common.pl 193-222 行)对每块 Mellanox 卡:
bash
lspci -d 15b3: # 列出所有 Mellanox 设备
lspci -s <dev>
setpci -s <dev> <offset>.B/.W # 读 PCIe 能力结构,比较协商链路宽度 vs 最大能力
链路宽度低于设备能力时打印黄色 WARNING(如 Link Width: x4 ( WARNING - device supports x8 )),并打印协商速率(2.5/5/8/16 GT/s)。
最后输出 Installation passed successfully,exit 0。
5. 失败时的日志与调试
所有命令输出汇入 /tmp/OFED.<pid>.logs/:
/tmp/OFED.<pid>.logs/
├── general.log # 全局日志
├── <pkg>.debbuild.log # 每个包的 dpkg-buildpackage 日志
├── <pkg>.debinstall.log # 每个包的 dpkg -i 日志
├── ofed_uninstall.log # 旧版本卸载日志
└── <pkg>.make.log # DKMS 编译失败时拷贝的内核模块 make 日志
任何关键命令失败(ex()/ex_deb_build()/ex_deb_install())都会调用 addSetupInfo()(3975-4013 行)追加收集:uname -r/-m、lsb_release -a、/etc/issue、/proc/version、gcc --version、lspci -n | grep 15b3、状态异常的 dpkg 包列表、完整 dpkg --list,然后退出 1。
6. sudo perl install.pl --all 实际执行的命令序列(汇总速查)
bash
# ① 环境探测
uname -m; uname -r
lspci -s 00:00.0 | grep -wq "PCI bridge: Mellanox Technologies"
dpkg -S /lib/modules/$(uname -r)/build/scripts # 判断 DKMS 是否可用
cat /etc/os-release # 发行版识别
# ② 平台裁剪(按需)
tac /lib/modules/$(uname -r)/build/include/*/autoconf.h | grep -m1 CONFIG_ISCSI_TARGET
dpkg-query -l cuda-cudart-dev-12-6 # CUDA 检测等
# ③ 依赖检查与自动补装
dpkg-query -l <pkg> # 逐个检查必需包
dpkg --purge <失败的*-dkms包>
apt-get update
apt-get install -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' <缺失包>
# ④ 卸载旧版本/冲突包
which ofed_uninstall.sh && yes | MLNX_OFED_COMPONENTS="kernel user" ofed_uninstall.sh
dpkg-query -l "*<旧包名>*"
dpkg --purge --dry-run '<pkg>' | grep "depends on" # 递归查依赖
dpkg --configure -a --force-all --force-confdef --force-confold
apt-get install -f -y
apt-get remove -y <冲突包列表>
apt-get remove --purge -y <残留配置包>
rm -rf /usr/src/mlnx-ofed-kernel*
# ⑤ 逐包构建(对每个选中的源码包,工作目录 /var/tmp/<parent>/)
cp SOURCES/<parent>_<ver>.orig.tar.gz . && tar xzf ...
dpkg-buildpackage -us -uc # 内核包带 configure_options 环境变量
cp ../*.deb DEBS/<distro>/<arch>/
# ⑥ 逐包安装
dpkg -i --force-confmiss <debs...>
# ⑦ 内核包验证
/sbin/depmod $(uname -r)
/sbin/modinfo -k $(uname -r) mlx5_core # 及各 .ko
dpkg -S <ko路径>
# ⑧ 安装后配置
systemctl disable opensmd
# 改写 /etc/modprobe.d/mlnx.conf、/etc/infiniband/openib.conf(SDP_LOAD=no、QIB_LOAD=no、RUN_MLNX_TUNE=no)
# ⑨ PCIe 链路检查
lspci -d 15b3:
setpci -s <dev> ... # 读链路宽度/速率并告警
7. 关键设计要点小结
- 源码现场构建 :这是 SRC 包,不是二进制仓库;安装时长主要取决于
mlnx-ofed-kernel、openmpi、ucx等的编译时间,构建中间文件在/var/tmp/<parent>/,产物缓存在DEBS/<distro>/<arch>/(重装时可复用)。 - DKMS 优先 :内核模块默认走 DKMS(
mlnx-ofed-kernel-dkms等),内核升级后自动重编;仅当内核头文件非 deb 安装或--without-dkms时退回-modules一次性编译模式。 - 强破坏性 :安装前会卸载所有发行版自带 RDMA 栈及旧 OFED(约 200 个包名在
@remove_debs),并递归处理依赖者;未加--force时若存在外部依赖会直接中止(退出 174)。 - 原子性较弱但可回滚 :单个包失败即整体中止;内核包验证失败时主动调用
ofed_uninstall.sh --force回滚。 - 非交互 :
DEBIAN_FRONTEND=noninteractive+apt-get -y+dpkg --force-confdef/confold/confmiss,全流程无需人工干预。