lsnmp

版本信息

项目内容
组件版本1.40.19
首发版本1.30.16
文档作者openUBMC 社区
最后更新2026-09-13

1. 组件概述

1.1 组件简介

lsnmp 是 openUBMC 平台中的 Lua 动态库组件,用于封装 net-snmp 的部分 C API。组件将 SNMP Trap 发送以及 SNMPv3 密钥派生能力暴露为 Lua 函数和 Lua 可访问的数据结构,供告警上报、事件通知和 SNMP 用户密钥管理等上层业务使用。

组件类型为 library,编译产物为 lsnmp.so,默认安装到 /opt/bmc/luaclib。它不启动独立进程、不注册 D-Bus 服务,也不维护独立配置模型;实际代码运行在调用该库的宿主进程内。

1.2 解决什么问题

上层 Lua 业务若直接调用 net-snmp,需要自行处理 Lua/C 数据转换、SNMP 会话初始化、PDU 构造、SNMPv3 鉴权与加密参数配置以及 Ku/Kul 密钥派生。lsnmp 对这些公共操作进行统一封装,使业务组件可以在 Lua 层完成以下工作:

  • 构造并发送 SNMPv1、SNMPv2c 或 SNMPv3 Trap。
  • 根据口令和鉴权算法生成 SNMPv3 Ku。
  • 根据 Ku 和 EngineID 生成本地化密钥 Kul。
  • 复用一致的参数校验、错误返回和日志输出方式。

1.3 核心功能

  • Trap 发送:通过 send_snmp_trap_msg 构造变量绑定并发送 SNMPv1、SNMPv2c 或 SNMPv3 Trap。
  • Ku 生成:通过 generate_ku 根据口令和鉴权协议生成 SNMPv3 用户密钥 Ku。
  • Kul 生成:通过 generate_kul 将 Ku 与指定 EngineID 绑定,生成本地化密钥 Kul(接口字段名为 pwd_key)。
  • Lua 数据类型封装:提供 SNMP_TRAP_MSGGEN_KU_STRUGEN_KUL_STRU 三种数据结构及其 zero() 方法。

1.4 关键术语表

术语解释
TrapSNMP 代理主动向管理站发送的异步事件通知。
OIDObject Identifier,对象标识符;在本组件中以 Lua 数字数组表示。
Variable BindingTrap 中携带的 OID、值和 ASN.1 类型组合。
EngineIDSNMPv3 引擎的唯一标识,用于密钥本地化。
Ku由用户口令和鉴权算法派生的主密钥。
Kul由 Ku 和 EngineID 派生的本地化密钥。

1.5 外部交互边界图

构建时依赖 libmc4lua >= 1.1.0net-snmp >= 5.9.3。运行时的网络通信和日志归属宿主进程;组件自身没有常驻进程、监听端口或 D-Bus 交互面。

2. API 使用说明与示例

安装后使用以下方式加载模块:

lua
local lsnmp = require 'lsnmp_core'

模块导出三个函数和三个数据结构。以下接口均为 Lua 本地接口,不是资源协作接口,不能通过 busctl 调用。

2.1 send_snmp_trap_msg

功能说明

按照输入的 Trap 参数、变量绑定和企业 OID 构造并发送一条 SNMP Trap,支持 SNMPv1、SNMPv2c 和 SNMPv3。

属性内容
首发版本1.30.16
废弃状态正常可用

函数签名:

lua
local ret = lsnmp.send_snmp_trap_msg(snmp_trap_msg, bindings, oid)

参数说明

参数名方向类型描述取值范围
snmp_trap_msg输入SNMP_TRAP_MSGTrap 版本、目的地址、凭据等参数,字段见 2.4.1。非空实例。
bindings输入table变量绑定数组,每项为 {oid_table, value, type}至少 1 项;单项 OID 最多 14 个节点;值转换为字符串后必须小于 1024 字节。
oid输入tableTrap 企业 OID;SNMPv1 时最后一个节点还用于生成 specific trap type。非空数字数组。

bindings 子项的格式如下:

位置类型描述
[1]table绑定项 OID 数字数组,长度不超过 14。
[2]可转为 string 的值绑定项的值,写入内部 1024 字节缓冲区。
[3]stringnet-snmp snmp_add_var 接受的 ASN.1 类型字符,例如 sito。组件只使用字符串首字符。

返回值与异常

返回值含义触发条件处理建议
0RET_OKTrap 已提交给 net-snmp 发送。会话和 PDU 创建成功,snmp_send 返回成功。无。注意 UDP 发送成功不代表管理站已接收。
-1RET_ERR发送失败。版本、地址、OID、bindings 或 SNMPv3 参数非法;会话/PDU 创建失败;snmp_send 失败。结合 4.2 节日志和 5.3 节步骤排查。

应用场景

  • BMC 告警或事件通过 Trap 上报到网管系统。
  • 发送测试 Trap,验证目的管理站、网络和 SNMP 参数配置。
  • 上层 Lua 服务复用统一的 SNMPv3 鉴权加密发送能力。

限制条件

  • version 仅接受 SNMPv1SNMPv2cSNMPv3,区分大小写。
  • 目的地址可为 IPv4、IPv6 或可解析域名;IPv6 链路本地地址应通过 veth 提供作用域后缀,例如 %eth0
  • SNMPv1/SNMPv2c 使用 community;SNMPv3 固定按 authPriv 安全级别初始化,需要用户名、鉴权/加密协议、对应密钥和可读取的 snmpd 配置文件。
  • SNMPv3 的 authentication_keyencryption_key 为不带 0x 前缀的十六进制字符串,至少包含 2 个字符;应使用与协议匹配的有效密钥长度。
  • SNMPv3 用户名内部缓冲区为 32 字节,用户名必须能完整写入该缓冲区。
  • 会话超时固定为 1 秒,重试次数固定为 3 次。
  • 组件使用进程内静态状态保存部分 SNMPv3 和 OID 数据,调用方不应并发调用 send_snmp_trap_msg

调试示例

Lua 调试
lua
local lsnmp = require 'lsnmp_core'

local trap = lsnmp.SNMP_TRAP_MSG()
trap.version = 'SNMPv2c'
trap.address = '192.168.1.100'
trap.port = 162
trap.community = 'public'
trap.is_test_event = true
trap.veth = ''
trap.agent_address = '0.0.0.0'

local bindings = {
    {{1, 3, 6, 1, 4, 1, 9999, 1}, 'alarm test message', 's'},
}
local enterprise_oid = {1, 3, 6, 1, 4, 1, 9999, 1}

local ret = lsnmp.send_snmp_trap_msg(trap, bindings, enterprise_oid)
print('send result:', ret)

2.2 generate_ku

功能说明

根据用户口令和鉴权协议生成 SNMPv3 Ku。鉴权用途与加密用途的 Ku 均按鉴权协议派生。

属性内容
首发版本1.30.16
废弃状态正常可用

函数签名:

lua
local ret = lsnmp.generate_ku(gen_ku)

参数说明

参数名方向类型描述取值范围
gen_ku输入/输出GEN_KU_STRU输入 protocolpwd,成功后从 ku 读取二进制结果。非空实例;协议枚举见 2.5;口令至少 8 字符。

返回值与异常

返回值/异常含义触发条件处理建议
0RET_OKKu 生成成功。net-snmp generate_Ku 调用成功。gen_ku.ku 获取二进制密钥。
-1RET_ERR参数非法。C++ 入口收到空对象。确保传入 GEN_KU_STRU 实例。
runtime_errorKu 计算失败。net-snmp 返回非成功状态。检查协议枚举与口令,并查看 fail to generate securityAuthKey 日志。

应用场景

为 SNMPv3 用户生成鉴权或加密使用的 Ku,或作为 generate_kul 的输入。

限制条件

  • ku 是二进制字符串,可能包含 \0,不得使用只适用于文本的处理方式截断它。
  • 源码在口令少于 8 字符时仍以最小长度 8 调用 net-snmp,但这会读取超出口令实际长度的数据并使结果不可预期;调用方必须保证口令长度不少于 8 字符。
  • 对未识别的鉴权协议枚举,底层当前会回退到 SHA512。调用方仍应只使用 2.5 节列出的有效非零鉴权算法,避免配置与计算结果不一致。

调试示例

Lua 调试
lua
local lsnmp = require 'lsnmp_core'

local gen = lsnmp.GEN_KU_STRU()
gen.protocol = 2
gen.pwd = 'MyPassword'

local ret = lsnmp.generate_ku(gen)
print('generate_ku result:', ret, 'ku length:', #gen.ku)

2.3 generate_kul

功能说明

根据 Ku、鉴权协议和 EngineID 生成 SNMPv3 本地化密钥 Kul。成功结果通过十六进制字符串字段 pwd_key 返回。

属性内容
首发版本1.30.16
废弃状态正常可用

函数签名:

lua
local ret = lsnmp.generate_kul(gen_kul)

参数说明

参数名方向类型描述取值范围
gen_kul输入/输出GEN_KUL_STRU输入 protocolkuengine_id,成功后从 pwd_key 读取 Kul 十六进制字符串。非空实例;EngineID 必须为 0x 加 26 位十六进制字符(13 字节);协议须与生成 Ku 时一致。

返回值与异常

返回值含义触发条件处理建议
0RET_OKKul 生成并转换为十六进制字符串成功。EngineID、Ku 和算法有效。gen_kul.pwd_key 获取结果。
-1RET_ERR参数转换或计算失败。对象为空、EngineID 非法、算法/Ku 不匹配或输出转换失败。检查输入并结合 dal_convert_*calculate_snmp_kul_property failed 日志排查。
其他非零值net-snmp 计算错误。generate_kul 返回底层错误码。校验 Ku 长度、EngineID 和协议。

应用场景

把用户 Ku 本地化到具体的 SNMP Engine,用于 SNMPv3 Trap 的鉴权密钥或加密密钥配置。

限制条件

  • 当前实现固定按 13 字节 EngineID 参与计算,因此 engine_id 必须为 0x 加 26 位十六进制字符。
  • ku 必须直接使用 generate_ku 的二进制输出,且生成 Ku/Kul 使用的 protocol 必须一致。
  • pwd_key 是不带 0x 前缀的十六进制字符串。

调试示例

Lua 调试
lua
local lsnmp = require 'lsnmp_core'

local gen_ku = lsnmp.GEN_KU_STRU()
gen_ku.protocol = 2
gen_ku.pwd = 'MyPassword'
assert(lsnmp.generate_ku(gen_ku) == 0)

local gen_kul = lsnmp.GEN_KUL_STRU()
gen_kul.protocol = 2
gen_kul.ku = gen_ku.ku
gen_kul.engine_id = '0x80001f8880aabbccddeeff1234'

local ret = lsnmp.generate_kul(gen_kul)
print('generate_kul result:', ret, 'pwd_key:', gen_kul.pwd_key)

2.4 数据结构说明

2.4.1 SNMP_TRAP_MSG

成员类型描述适用范围/约束
versionstringSNMP 版本。SNMPv1SNMPv2cSNMPv3
addressstring目的 IP 或域名。非空且可解析。
portnumber目的 UDP 端口。065535,通常为 162
communitystring团体名。SNMPv1/SNMPv2c 使用。
is_test_eventboolean是否为测试事件。SNMPv1 为 true 时 specific type 固定为 1。
vethstringIPv6 地址的接口作用域后缀。IPv4 通常为空;IPv6 链路本地地址可设为 %eth0
snmpv3_userstringSNMPv3 用户名。SNMPv3 使用;内部缓冲区为 32 字节。
authentication_protocolnumber鉴权协议枚举。见 2.5。
authentication_keystring已本地化鉴权密钥的十六进制字符串。不带 0x 前缀。
encryption_protocolnumber加密协议枚举。见 2.5。
encryption_keystring已本地化加密密钥的十六进制字符串。不带 0x 前缀。
snmpd_cfg_filestringsnmpd 配置文件路径。SNMPv3 使用,文件中需有 oldEngineIDoldEngineBakID
typestringTrap 类型。当前发送流程保留该字段;SNMPv1 specific type 实际由企业 OID 最后一项或测试标志决定。
agent_addressstringSNMPv1 PDU 的代理 IPv4 地址。空或 0.0.0.0 时使用本机地址。

方法 zero() 会对结构对象占用的内存做清零。由于结构包含 C++ std::string 成员,业务代码不应把 zero() 当作常规重置方法使用;需要重置时建议重新创建对象并逐项赋值。

2.4.2 GEN_KU_STRU

成员类型描述
protocolnumber鉴权协议枚举。
pwdstring输入口令,至少 8 字符。
kustring输出的二进制 Ku。

2.4.3 GEN_KUL_STRU

成员类型描述
protocolnumber鉴权协议枚举,须与 Ku 的生成协议一致。
kustring输入的二进制 Ku。
engine_idstring0x 加 26 位十六进制字符。
pwd_keystring输出的 Kul 十六进制字符串,不带 0x

2.5 协议/算法枚举

鉴权协议枚举适用于 authentication_protocolGEN_KU_STRU.protocolGEN_KUL_STRU.protocol

取值算法
0无鉴权;不用于本组件当前固定为 authPriv 的 SNMPv3 Trap 流程。
1MD5
2SHA96(SHA-1)
3SHA224
4SHA256
5SHA384
6SHA512

加密协议枚举适用于 encryption_protocol

取值算法
0无加密;不用于本组件当前固定为 authPriv 的 SNMPv3 Trap 流程。
1DES
2AES128
3AES256

3. 组件扩展案例

3.1 扩展能力概述

lsnmp 不提供插件机制、配置 DSL 或运行时扩展点。mds/service.jsonrequired 为空,仓库中也没有 model.jsonipmi.json。组件支持的扩展方式是代码级二次开发:

  • 上层组件增加对 lsnmp 的构建/运行依赖后调用现有 Lua API。
  • lsnmp 中新增 C/C++ 封装函数或数据结构,并通过 lsnmp_core 模块导出。

3.2 扩展点说明

扩展位置作用触发时机
src/l_snmp.cpp 中的 lsnmp_init向 Lua 模块表注册新函数。执行 require 'lsnmp_core' 时。
src/l_type_register.cpp注册 Lua 可构造的数据结构、属性和方法。模块初始化时。
src/msg_send.cpp扩展 Trap PDU 构造或发送能力。调用 Trap 发送 API 时。
src/ku_manage.cppsrc/kul_manage.cpp扩展 SNMPv3 密钥处理能力。调用 Ku/Kul API 时。

3.3 二次开发指导

步骤一:实现 C/C++ 入口

src 目录中实现新能力,使用 gint32 返回状态;对输入进行校验,并通过 debug_log 记录可定位但不泄露密钥或口令的信息。

步骤二:注册 Lua API

在头文件声明入口,并在 src/l_snmp.cpplsnmp_init 中注册。例如新增 query_feature

cpp
t.set("query_feature", c_func_wrap(L, l_query_feature));

如需新的 Lua 数据结构,在 src/l_type_register.cpp 中使用 luawrap::lua_class 注册。

示例代码

上层组件使用现有能力时,应先在其依赖清单中声明 lsnmp,再加载模块:

lua
local lsnmp = require 'lsnmp_core'

local request = lsnmp.GEN_KU_STRU()
request.protocol = 4
request.pwd = 'StrongPassword'
assert(lsnmp.generate_ku(request) == 0)

验证方法

  1. 使用项目构建环境编译,确认生成无 lib 前缀的 lsnmp.so
  2. 将产物安装到 Lua C 模块搜索路径,执行 require 'lsnmp_core'
  3. 调用新增 API 的成功、非法参数和底层失败场景。
  4. 预期成功场景返回 0,失败场景返回明确错误或抛出文档化异常,并产生不包含敏感信息的定位日志。

注意事项

  • 保持 Lua 导出名称、结构字段名称和错误语义向后兼容。
  • 不得在日志中输出口令、Ku、Kul、鉴权密钥或加密密钥。
  • 组件存在进程内静态状态;修改发送路径时需重点评估并发安全和多宿主调用影响。
  • 新增算法时需同步确认 net-snmp 版本、OID 长度和密钥长度要求。
  • 若新增 API,须同步更新本文档的 API、错误码、日志和 FAQ 章节。

4. 日志说明

4.1 一键日志收集

lsnmp 是动态库,不创建独立日志文件,也没有仓库内声明的独立一键日志收集项。源码通过 debug_log 写入调用它的宿主进程日志,因此系统执行一键日志收集时,是否收集到这些日志以及对应文件路径由宿主组件的日志配置决定。

文件路径内容说明
不适用(宿主进程日志)lsnmp 的 ERROR/DEBUG 日志随宿主进程输出;排障时应先确定实际调用者,再收集该进程日志。

4.2 关键日志信息

日志片段日志级别含义解读建议处理动作
get snmp version failed / the version name is invalidERRORversion 为空或不是支持的三个版本名称。修正为 SNMPv1SNMPv2cSNMPv3
Failed to parse domain name / get trap peername failedERROR目的地址为空、解析失败或 peername 构造失败。检查 DNS、IP、端口和 IPv6 veth
get oid failed / get bindings failed / get table len failedERROROID 或 bindings 不是非空合法 Lua 数组,或绑定 OID 超长。按 2.1 节格式检查数组和数据类型。
set_snmpv3_key failed / get encrypted auth_key invalidERRORSNMPv3 密钥为空、过短、格式不合法或无法写入会话。使用不带 0x 的合法十六进制本地化密钥。
set_snmpv3_engine failed / fopen_s failedERRORsnmpd 配置文件不可读,或无法获得 EngineID。检查路径、权限及 oldEngineID/oldEngineBakID
init snmp session failedERRORSNMP 会话初始化或打开失败。先检查前置 SNMPv3 日志,再核对地址、凭据和算法。
snmp_add_var failedERROR变量绑定的 ASN.1 类型和值不匹配。修正 bindings 的 type/value。
send snmp message failed / send snmp trap oid message failedERRORnet-snmp 未能提交报文。查看紧随其后的 net-snmp 错误,并检查本机网络栈。
fail to generate securityAuthKeyERRORgenerate_Ku 失败。检查口令和鉴权协议。
dal_convert_hex_to_string failedERROREngineID 十六进制转换失败。使用 0x 加 26 位合法十六进制字符。
fail to generate pwdkey Key / calculate_snmp_kul_property failedERRORKul 计算失败。确认 Ku、EngineID 和协议相互匹配。

5. 问题定界指南

5.1 典型问题定界

问题描述是否为本组件问题判断依据关键证据收集方法
require 'lsnmp_core' 失败可能是lsnmp.so 未安装、依赖库缺失或 Lua C 模块路径错误均可能导致。检查 /opt/bmc/luaclib/lsnmp.so、Lua package.cpath 和加载器错误。
API 返回 -1 且宿主日志出现参数解析关键字是或调用方输入问题失败发生在 lsnmp 参数校验/转换阶段。保存调用参数的非敏感字段、返回值和对应宿主日志。
send_snmp_trap_msg 返回 0,管理站未收到 Trap通常不是UDP 提交成功不代表远端接收;可能为路由、防火墙、端口或管理站凭据/规则问题。在发送端和接收端分别抓取 UDP 162 报文,核对目的 IP、端口、版本和凭据。
SNMPv3 初始化失败并出现 EngineID/密钥日志可能是配置问题组件依赖正确的配置文件、用户名、算法和本地化密钥。收集脱敏后的参数、配置文件路径/权限及相关 ERROR 日志,禁止收集明文密钥。
generate_kugenerate_kul 结果与其他工具不同可能是输入差异口令编码、协议、EngineID 或 Ku 的二进制/十六进制表示不一致会产生不同结果。比较口令字节长度、算法枚举、EngineID 字节和 Ku 表示方式。

5.2 错误码速查表

错误码含义可能原因排查建议
0RET_OK成功调用正常完成。对 Trap 发送仍需通过抓包或管理站日志确认端到端接收。
-1RET_ERR通用失败参数非法、内存/转换失败、会话或发送失败。根据 API 和最接近的 ERROR 日志定位。
net-snmp 非零错误码底层密钥计算失败算法、口令、Ku 或 EngineID 不合法/不匹配。对照 net-snmp 约束核对输入;generate_ku 会将其包装为 runtime_error

5.3 调试方法

开启调试日志

组件没有独立日志级别开关。应在宿主进程或系统日志配置中开启 DEBUG 级别,再按 lsnmp 源码日志关键字过滤。不要为排障打印口令、Ku、Kul 或 SNMPv3 密钥。

复现问题方法

  1. 确认 /opt/bmc/luaclib/lsnmp.so 可被 require 'lsnmp_core' 加载。
  2. 使用第 2 章最小示例,先验证 generate_kugenerate_kul,再验证 Trap 发送。
  3. 对发送问题,在管理站监听 UDP 162,并在发送端执行 tcpdump -ni any udp port 162
  4. 预期 API 返回 0;发送端能观察到发往配置地址/端口的 UDP 报文,管理站能解析相同版本和凭据的 Trap。

lsnmp 没有 D-Bus 对象,因此不存在 busctl 命令行调试方式;应使用 Lua 脚本和网络抓包。

5.4 错误对象解读

lsnmp 的 Lua API 返回整数 rc 或字符串结果,不使用 D-Bus 结构化错误对象。0 表示成功,-1 表示参数、内存或底层库调用失败,其他返回值按 5.2 节错误码表解释。

6. 常见问题解答

Q1:为什么 require 'lsnmp_core' 找不到模块?

  • 问题描述:Lua 报告找不到 lsnmp_core 或无法加载共享库。
  • 一句话答案:检查 lsnmp.so 是否安装在 Lua C 模块搜索路径中,以及其动态依赖是否完整。
  • 根因说明:模块入口名是 luaopen_lsnmp_core,文件由构建系统安装到 /opt/bmc/luaclib/lsnmp.so;路径、文件或依赖缺失都会导致加载失败。
  • 解决方案:确认文件存在,将 /opt/bmc/luaclib/?.so 纳入 package.cpath,并根据加载器报错补齐依赖。
  • 规避方案:通过组件包和正式构建流程安装,不要只复制单个共享库。
  • 适用版本:1.30.16。

Q2:为什么 send_snmp_trap_msg 返回 -1 并提示版本错误?

  • 问题描述:日志出现 get snmp version failedthe version name is invalid
  • 一句话答案:version 必须精确填写为 SNMPv1SNMPv2cSNMPv3
  • 根因说明:组件对版本字符串做区分大小写的精确匹配。
  • 解决方案:修正 SNMP_TRAP_MSG.version 后重试。
  • 规避方案:在上层使用固定枚举映射,不接受任意版本字符串透传。
  • 适用版本:1.30.16。

Q3:为什么 SNMPv3 Trap 初始化失败?

  • 问题描述:日志出现 set_snmpv3_key failedset_snmpv3_engine failedinit snmp session failed
  • 一句话答案:核对用户名、算法、本地化密钥以及 snmpd 配置文件中的 EngineID。
  • 根因说明:SNMPv3 会话固定使用 authPriv,必须同时配置鉴权和加密信息;组件还会从配置文件读取 oldEngineIDoldEngineBakID
  • 解决方案:提供合法十六进制密钥、匹配的算法和可读配置文件,并确认 EngineID 与密钥本地化时一致。
  • 规避方案:统一通过 generate_ku/generate_kul 生成密钥,并在配置变更后重新本地化。
  • 适用版本:1.30.16。

Q4:为什么 generate_ku 失败或每次结果不一致?

  • 问题描述:抛出 runtime_error,或口令较短时结果异常。
  • 一句话答案:使用不少于 8 字符的口令,并选择有效鉴权协议。
  • 根因说明:当前实现对短口令把传给 net-snmp 的长度提升到 8,可能读取超出口令实际内容的数据,结果不可预期。
  • 解决方案:使用长度至少为 8 的口令重新生成 Ku;同时确认协议枚举一致。
  • 规避方案:上层在调用前强制校验口令长度。
  • 适用版本:1.30.16。

Q5:为什么 API 返回 0,管理站仍收不到 Trap?

  • 问题描述:调用成功但管理站没有事件。
  • 一句话答案:返回 0 只表示报文已成功提交给本机 net-snmp/UDP 发送路径,不代表远端确认接收。
  • 根因说明:Trap 使用 UDP,没有应用层确认;路由、防火墙、目的端口、团体名、SNMPv3 凭据或管理站过滤规则都可能丢弃报文。
  • 解决方案:两端抓包确认报文路径,再核对版本、端口、团体名或 SNMPv3 用户/算法/密钥。
  • 规避方案:部署前进行端到端测试 Trap 验证,并监控网络策略变化。
  • 适用版本:1.30.16。

附录

附录 A 参考资料

附录 B 修订记录

版本日期修订人修订内容
v1.02026-08-27openUBMC 社区按组件文档模板补充组件概述、API、扩展、日志、问题定界、FAQ 和参考资料。