MLNX_OFED 的 install.pl 安装流程分析

分析对象: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 等

  • 采集平台信息:

    bash 复制代码
    uname -m      # 架构 $arch
    uname -r      # 内核版本 $kernel
    # 内核头文件目录:/lib/modules/$(uname -r)/build
  • 交叉编译检测:若环境变量 ARCH 与本机不同则启用交叉编译模式

  • BlueField 检测(167 行):

    bash 复制代码
    lspci -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. 发行版识别与包名决策

  1. DKMS 可用性预检 (449-462 行):若内核头文件目录不是由 deb 包安装的(dpkg -S /lib/modules/$(uname -r)/build/scripts 失败),自动关闭 DKMS(除非 --force-dkms)。
  2. 发行版检测 (464-489 行,common.pl: os_release()):读取 /etc/os-release 的 ID+VERSION_ID(Debian 改读 /etc/debian_version),拼出如 ubuntu22.04、debian12;仅支持 debian/ubuntu/uos,否则红字报错退出。uos 强制禁用 DKMS。
  3. 内核包名决策 (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 后缀。
  4. 发行版相关依赖名适配 (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 等。
  5. 创建输出目录:DEBS/<distro>/<arch>/(837-839 行)。
  6. 模块与包数据库 :
    • 内核模块组(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

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() 实查):

    bash 复制代码
    tac /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",然后:

  1. 若系统已有旧版 OFED(which ofed_uninstall.sh 存在):先运行旧卸载器

    bash 复制代码
    yes | MLNX_OFED_COMPONENTS="kernel user" ofed_uninstall.sh [--force]
  2. 用 @remove_debs(377 行,约 200 个历史/冲突包名:旧 OFED、发行版自带 rdma-core/libibverbs、mlnx-en、mft 等)匹配已安装包:

    bash 复制代码
    dpkg-query -l "*<name>*"
  3. get_requires() 递归找出依赖这些包的其它包(除非 --force,发现非 OFED 依赖即退出 174;qemu-system-* 系列免疫不删):

    bash 复制代码
    dpkg --purge --dry-run '<pkg>' | grep "depends on"
  4. 修复 dpkg 数据库:

    bash 复制代码
    dpkg --configure -a --force-all --force-confdef --force-confold
    apt-get install -f -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'
  5. 批量卸载并清除残留配置:

    bash 复制代码
    apt-get remove -y <包列表>
    apt-get remove --purge -y <处于 config-files 状态的包>
  6. 清理 DKMS 源目录:

    bash 复制代码
    rm -rf /usr/src/mlnx-ofed-kernel*

步骤 9:构建并安装新包 install_selected()(2964-3327 行)------核心环节

对 @selected_packages 中每个包依次:

  1. 清理一批环境变量(DEB_CONFIGURE_EXTRA_FLAGS、KVER、MLX5 等,2975-2994 行)

  2. 先在 DEBS/<distro>/<arch>/ 找匹配版本的现成 .deb(内核包额外匹配 kver.<内核版本> 并校验模块齐全)------有则直接跳到第 5 步安装

  3. 构建 (3057-3256 行):

    bash 复制代码
    rm -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_HOME
    • rdma-core:无 pyverbs 时加 nopyverbs 构建选项
      然后执行构建与收集:
    bash 复制代码
    dpkg-buildpackage -us -uc [-P...]      # 日志:/tmp/OFED.<pid>.logs/<name>.debbuild.log
    cp ../*.deb DEBS/<distro>/<arch>/

    构建失败 → addSetupInfo() 收集调试信息后退出 1。支持 --pre/post-build-<pkg> 钩子脚本。

  4. 构建后再次 glob 确认 .deb 已产出,没有则报错退出

  5. 安装 (3259-3269 行):

    bash 复制代码
    dpkg -i --force-confmiss [--force-breaks] <debs...>   # 日志:<name>.debinstall.log

    (--force-confmiss 恢复缺失配置文件;ubuntu24/debian13+ 的 ibverbs 包加 --force-breaks;支持 --pre/post-install-<pkg> 钩子。)

  6. 内核包安装后验证 (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 行):

    bash 复制代码
    systemctl 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. 关键设计要点小结

  1. 源码现场构建 :这是 SRC 包,不是二进制仓库;安装时长主要取决于 mlnx-ofed-kernel、openmpi、ucx 等的编译时间,构建中间文件在 /var/tmp/<parent>/,产物缓存在 DEBS/<distro>/<arch>/(重装时可复用)。
  2. DKMS 优先 :内核模块默认走 DKMS(mlnx-ofed-kernel-dkms 等),内核升级后自动重编;仅当内核头文件非 deb 安装或 --without-dkms 时退回 -modules 一次性编译模式。
  3. 强破坏性 :安装前会卸载所有发行版自带 RDMA 栈及旧 OFED(约 200 个包名在 @remove_debs),并递归处理依赖者;未加 --force 时若存在外部依赖会直接中止(退出 174)。
  4. 原子性较弱但可回滚 :单个包失败即整体中止;内核包验证失败时主动调用 ofed_uninstall.sh --force 回滚。
  5. 非交互 :DEBIAN_FRONTEND=noninteractive + apt-get -y + dpkg --force-confdef/confold/confmiss,全流程无需人工干预。
相关推荐
Eloudy3 小时前
RoCE UC Receive 实现代码结构与原理分析
rdma·roce
对讲机数码科普3 小时前
从电路原理到协议栈:模拟对讲机与数字对讲机的技术内核拆解
运维·网络·架构·软件工程
我送炭你添花3 小时前
ASA原理与电子维修实战:前言 一路修来,一路学习
运维·网络·学习
张小姐的猫4 小时前
【Linux】网络编程 —— 多路转接:epoll
linux·运维·网络
睡一觉就好了。4 小时前
linux网络编程基础
网络
花间相见4 小时前
【计算基础|网络09】TCP(上):三次握手与四次挥手
网络·网络协议·tcp/ip
wdfk_prog4 小时前
LWIP教程 08:从 `tcp_write()` 到 ACK 清队列——TCP 数据发送、窗口与回调
网络·网络协议·tcp/ip
anew___5 小时前
《从零手写操作系统 (37):网络协议栈基础——Socket接口与TCP状态机》
网络·网络协议·tcp/ip
wdfk_prog5 小时前
LWIP教程 10:从 `tcp_receive()` 到 `ooseq` / SACK——TCP 乱序、重组与选择确认
网络·数据库·tcp/ip