资讯动态

ipmitool源码编译与二次开发实战:从编译到自定义OEM命令

发布时间:2026/9/29 16:11:53 来源:尧图企业网站定制
简介IPMItool 源码包面向服务器运维工程师、嵌入式开发者及希望深入理解 IPMI 协议实现的技术人员用于研究开源命令行工具如何通过 IPMI 协议与 BMC 交互完成传感器读取、事件日志获取、电源控制等硬件级管理任务。压缩包共 171 个文件约 752KB以 49 个 c 源文件和 50 个 h 头文件为主体辅以 16 个 am 构建脚本、22 个 in 模板及 configure、Makefile 等编译配置另有 debian、redhat、suse 等发行版打包文件与 readme、changelog 说明文档。源码按模块组织commands 目录下各命令独立成文件ipmi.c 与 ipmi.h 实现协议核心lan.c、serial.c 处理通信接口sdr.c 负责传感器数据记录解析chassis.c 管理电源状态并涵盖认证安全与跨平台构建逻辑。已有 551 人学习适合通过阅读源码掌握 IPMI 消息结构、接口驱动与命令扩展方式为定制功能或适配特定硬件提供参考。1. 拆开 ipmitool 源码为什么一线运维宁可自己编译也不直接用包管理器机房半夜告警一台 Dell R750 的 BMC 风扇转速突然拉满ipmitool sdr却读不到温度。包管理器装的 1.8.18 版本对这块新 BMC 的 sensor 解析直接返回Unknown换成自己编译的 1.8.19 才把CPU1 Temp读出来。这就是我坚持留一份 ipmitool 源码在跳板机上的原因——发行版仓库里的版本往往落后一到两年新 BMC 固件的 SDR、FRU、SEL 记录格式一变老二进制就抓瞎。ipmitool 是走 IPMI 协议跟服务器 BMC 对话的命令行工具带内走/dev/ipmi0的 KCS 接口带外走 LAN 上的 RMCP。源码包的价值不在「能编译」这件事本身而在于你能改lib/ipmi_sdr.c里的解析逻辑、能加自定义 OEM 命令、能在交叉编译环境里给 ARM 架构的 BMC 出二进制。适合谁管着几十台以上物理机、被各种厂商 BMC 兼容性折磨过的运维以及做带外监控平台、需要把 ipmitool 当库嵌进自己程序的开发。如果你只是偶尔power on一台机器发行版自带的够用但只要碰到「读不到、读不准、命令不支持」源码就是唯一的后悔药。2. 源码目录结构与编译链路从 configure 到可执行文件拿到一份 ipmitool 源码先别急着./configure。花十分钟把目录摸清楚后面改代码、加插件、交叉编译都省事。这份代码结构是典型的 autotools 工程主干清晰插件式设计是它最大的特点。2.1 目录布局与各模块职责顶层目录里src/是主程序入口和命令分发lib/是 IPMI 协议实现的核心include/放头文件contrib/是一些厂商补丁和示例doc/是 man page。真正干活的是lib/下面这一堆文件文件职责改动频率ipmi_sdr.cSDR 传感器记录解析高新 BMC 常要改ipmi_fru.cFRU 现场可替换单元读取中ipmi_sel.c系统事件日志解析中ipmi_lanplus.cRMCP 带外会话低ipmi_kcs.c带内 KCS 接口低ipmi_intf.c接口抽象层注册所有 intf低ipmi_sol.cSerial over LAN低src/ipmitool.c是入口main()里做参数解析后调用ipmi_main()再根据子命令分发到ipmi_sdr_main()、ipmi_sel_main()这些函数。理解这条调用链你才知道想加一个自定义命令该往哪塞。lib/ipmi_intf.c里的ipmi_intf_table[]是接口注册表带内、带外、串口、D Bus 全在这里挂载。想加一种新的传输方式就是往这个表里加一项实现open/close/sendrecv三个回调。2.2 依赖检查与 configure 参数编译前先确认依赖。带外 LAN 功能依赖 OpenSSLSOL 依赖 readline这些在configure阶段会检查。缺了不会直接报错而是静默关掉对应功能编出来的二进制跑起来才发现lanplus不支持这是最常见的翻车点。# 先装依赖Debian/Ubuntu 系 apt-get install -y build-essential autoconf automake libtool \ libssl-dev libreadline-dev # 生成 configure 脚本源码包如果没带现成的 configure autoreconf -i # 关键配置显式打开 lanplus 和 sol关掉不需要的 ./configure \ --prefix/usr/local/ipmitool \ --enable-lanplus \ --enable-sol \ --enable-intf-lan \ --enable-intf-open \ --disable-intf-dbus \ --disable-intf-serial--enable-lanplus是带外加密会话的核心不显式打开的话 configure 检测不到 OpenSSL 就悄悄跳过。--prefix装到独立目录避免覆盖系统自带的/usr/bin/ipmitool出问题好回退。--disable-intf-dbus在容器或精简系统里能省掉一堆 D-Bus 头文件依赖。配置完看输出末尾的 summary确认LAN/LANPLUS interface: yes、SOL interface: yes。如果 lanplus 显示 no八成是libssl-dev没装或版本太老。2.3 编译、安装与验证make -j$(nproc) make install # 验证版本和编译进去的接口 /usr/local/ipmitool/bin/ipmitool -V /usr/local/ipmitool/bin/ipmitool -h 21 | grep -i lanplus-V打印版本号-h的帮助里能看到-I lanplus说明带外加密接口编进去了。这一步别省我见过太多人编完直接拿去连 BMC结果报Invalid interface lanplus回头查半天是 configure 阶段静默跳过了。交叉编译给 ARM BMC 用的话在 configure 前设好--hostarm-linux-gnueabihf和对应的CCOpenSSL 也要用目标平台的库否则链接阶段会报架构不匹配。这一步坑最深的是 OpenSSL 的交叉编译建议单独编一份目标平台的 OpenSSL 再--with-openssl/path/to/cross/openssl。3. 用源码里的接口做二次开发加一条自定义 OEM 命令编译只是入门源码真正的价值是能改。这一章讲一个实际场景厂商 BMC 有个私有命令读电源模块温度标准sdr读不到需要自己发一条 raw 命令并解析返回。我把它做成 ipmitool 的一个子命令比每次手敲raw 0x3a 0x0c ...靠谱得多。3.1 理解 raw 命令与命令分发机制IPMI 的 raw 命令本质是直接发 NetFn Cmd Data绕过 ipmitool 的语义解析。ipmitool raw 0x3a 0x0c 0x01就是往 NetFn0x3a、Cmd0x0c 发一个字节 0x01。私有命令都这么玩但每次要记 NetFn、Cmd、返回字节的含义容易错。在源码里加子命令走的是src/ipmitool.c的ipmi_main()里那张命令表。找到类似{ sdr, ipmi_sdr_main }的注册项照着加一行然后实现自己的_main函数。这样ipmitool mycmd就能直接调用。3.2 实现一个自定义子命令下面这段是加一个pmtemp子命令的骨架读私有命令并解析返回的温度值。放在src/ipmitool.c里或者单独建个src/ipmi_pmtemp.c再在 Makefile.am 里加进去。/* 自定义子命令读取电源模块温度 * 私有命令 NetFn0x3a Cmd0x0c返回第 2 字节为温度摄氏度 */ #include ipmitool/ipmi.h #include ipmitool/ipmi_intf.h static int ipmi_pmtemp_main(struct ipmi_intf *intf, int argc, char **argv) { struct ipmi_rs *rsp; struct ipmi_rq req; uint8_t msg_data[1] { 0x01 }; /* 通道号按厂商文档改 */ memset(req, 0, sizeof(req)); req.msg.netfn 0x3a; /* 厂商私有 NetFn */ req.msg.cmd 0x0c; /* 读温度命令 */ req.msg.data msg_data; req.msg.data_len 1; rsp intf-sendrecv(intf, req); if (rsp NULL) { lprintf(LOG_ERR, 命令无响应检查 BMC 是否支持该 OEM 命令); return -1; } if (rsp-ccode 0) { lprintf(LOG_ERR, 命令返回错误码 0x%02x, rsp-ccode); return -1; } /* 返回数据第 2 字节是温度第 1 字节通常是完成码 */ printf(Power Module Temp: %d C\n, rsp-data[1]); return 0; } /* 在 ipmi_main() 的命令表里注册 * { pmtemp, ipmi_pmtemp_main }, */逻辑说明intf-sendrecv是接口抽象层统一的收发函数带内带外都走它所以这段代码不用关心底层是 KCS 还是 LAN。req.msg.netfn和cmd必须查厂商的 IPMI 规范填错会返回ccode0xc1Invalid command。rsp-data[1]取第 2 字节是因为 IPMI 响应第 1 字节通常是 completion code 的镜像具体偏移看厂商文档别照抄。参数说明msg_data里的通道号、netfn、cmd三个值全部来自厂商私有规范不同品牌完全不同。改完在Makefile.am的ipmitool_SOURCES里加上新文件重新autoreconf ./configure make。3.3 调试与验证改完代码别直接上生产。先在测试机上用-I lanplus -H bmc_ip -U admin -P pass pmtemp跑配合-v -v -v打开三级调试能看到完整的收发字节流。# 三级 verbose打印原始报文 ipmitool -I lanplus -H 10.0.0.5 -U admin -P xxx -v -v -v pmtemp输出里会看到Sending IPMI request和Received IPMI response两段十六进制。对照厂商文档核对 NetFn、Cmd、返回字节比盲猜快得多。如果sendrecv返回 NULL先确认 BMC 的 LAN 配置里 IPMI over LAN 是开的再确认用户名权限够OPERATOR 级别通常够读ADMIN 才能改。4. 避坑与排查编译和使用 ipmitool 源码时最容易翻车的五件事这一章全是血泪经验每条都按「现象 → 原因 → 解决」写。ipmitool 这东西看着简单坑都在细节里。现象configure 通过make 报undefined reference to SSL_...。原因系统装了 OpenSSL 运行时库但没装开发头文件或者装了但 pkg-config 找不到。解决装libssl-devDebian 系或openssl-develRHEL 系然后pkg-config --cflags --libs openssl确认能输出路径。还不行就./configure --with-openssl/usr显式指定。现象编出来的二进制连 BMC 报Error: Unable to establish LAN session。原因九成是 configure 时 lanplus 没编进去或者 BMC 只支持 IPMI 1.5 而你用了 2.0 的加密会话。解决先ipmitool -h | grep lanplus确认接口存在再用-I lan试非加密会话如果-I lan能通而-I lanplus不通是 BMC 固件没开 RMCP 或 cipher suite 不匹配加-C 3指定 cipher suite 试。现象sdr输出一堆Unknown或no reading。原因BMC 的 SDR 记录格式跟 ipmitool 内置的解析表对不上新固件常见。解决升级到最新源码重新编译或者直接改lib/ipmi_sdr.c里ipmi_sdr_print_sensor_*系列函数把厂商的私有 sensor type 加进解析分支。改之前先用ipmitool sdr dump sdr.bin把原始 SDR 导出来对照。现象带内/dev/ipmi0打不开报Could not open device at /dev/ipmi0。原因内核模块ipmi_devintf和ipmi_si没加载或者权限不够。解决modprobe ipmi_devintf ipmi_si然后ls -l /dev/ipmi0确认设备节点存在。权限问题就把用户加进能访问该设备的组别直接chmod 777。现象交叉编译给 ARM BMC 用运行时报Exec format error或链接库找不到。原因编译时用的 OpenSSL 是宿主机的 x86 库或者--host没设对。解决单独交叉编译一份目标平台的 OpenSSLconfigure 时--with-openssl/path/to/cross/openssl并用file ipmitool确认二进制架构正确。运行时如果缺库用--enable-static编静态链接版本省去目标机装依赖的麻烦。5. 进阶技巧把 ipmitool 源码当库用嵌进自己的监控程序到这一步你已经能编译、能改命令、能排错。最后一个技巧是把 ipmitool 的lib/当静态库链进自己的程序省去 fork 进程调命令行的开销。做带外监控平台的话这个用法比system()调 ipmitool 优雅得多也稳定得多。思路是把lib/编成libipmitool.a在自己的程序里#include ipmitool/ipmi_intf.h手动构造struct ipmi_intf调ipmi_intf_load()加载 lanplus 接口然后直接sendrecv。这样你的监控程序就能在一个进程里轮询几十台 BMC不用每台 fork 一次。/* 把 ipmitool 当库用初始化 lanplus 接口并读一条 SDR */ #include ipmitool/ipmi_intf.h #include ipmitool/ipmi_sdr.h struct ipmi_intf *intf ipmi_intf_load(lanplus); if (intf NULL) { fprintf(stderr, 加载 lanplus 接口失败\n); return -1; } /* 设置连接参数等价于命令行 -H -U -P */ intf-open(intf); /* 内部会读 intf-hostname / username / password */ /* 之后就能直接调 ipmi_sdr_main(intf, argc, argv) 或自己发 raw */关键点ipmi_intf_load按名字找接口open之前要把hostname、username、password填进intf结构体这些字段在include/ipmitool/ipmi_intf.h里定义。链接时把lib/下所有.o和 OpenSSL 一起链进去注意-lssl -lcrypto顺序放在后面。我一般会先写个最小验证程序只做open 读一条Get Device IDNetFn0x06 Cmd0x01确认链路通了再往上堆业务逻辑。从那以后我每次把 ipmitool 嵌进新程序都强制先跑通这条最小链路再动其他代码——因为 90% 的「库用不起来」都是连接参数没填对或接口没加载成功跟业务逻辑无关。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑