nsm(Network Service Management)
版本信息
| 项目 | 内容 |
|---|---|
| 组件版本 | 1.140.15 |
| 首发版本 | 1.130.12 |
| 文档作者 | openUBMC 社区 |
| 最后更新 | 2026-09-13 |
1. 组件概述
1.1 组件简介
nsm 是 openUBMC 的网络服务管理组件,以 nsm.service 运行并通过 bmc.kepler.nsm D-Bus 服务发布资源。组件统一维护 HTTP、HTTPS、SSH、SNMP、KVMIP、VirtualMedia、Video、WEBVNC 等服务的状态和端口,生成 nginx、sshd、snmpd 配置,维护端口转发,并管理 SSH 算法及不安全协议告警。设计目标是使资源模型、持久化配置、配置文件和底层服务状态保持一致。
1.2 解决什么问题
nsm 解决多个 BMC 网络服务分散配置、端口冲突、配置无法持久化和运行状态不同步的问题。使用者通过统一的网络服务资源模型及配套的 D-Bus 接口,完成服务注册、使能状态、端口和 SSH 算法配置。
1.3 核心功能
- 网络协议与端口管理:注册协议,维护使能状态和主备端口,检测内外部端口冲突。
- 服务配置与控制:生成 nginx、sshd、snmpd 配置并控制相关服务和 iptables/NAT 规则。
- 安全策略管理:管理 SSH 算法,阻止同类算法全部禁用,上报不安全协议和算法告警。
1.4 关键术语表
| 术语 | 解释 |
|---|---|
| Port | 对外提供网络服务的当前主用端口,类型为 uint16。 |
| SparePort | 支持双端口协议的第二个对外端口;单端口协议不可配置。 |
| InnerPort | nsm 为端口转发分配的内部监听端口;冲突时会自动选择其他端口。 |
1.5 外部交互边界图
Redfish / Web / CLI IPMI 客户端 其他 BMC 组件
| D-Bus 属性/方法 | OEM 命令 | 协议注册
+---------------------------+-----------------------+
v
bmc.kepler.nsm(D-Bus)
nsm(Lua / Skynet)
|
+----------+--------------+-------------------------+
| | | |
v v v v
MDB persistence 网络配置与转发控制 安全与会话联动
资源协作模型 持久化服务 | | |
+--> iptables / NAT | +--> SessionService
+--> nginx | 注销受影响会话
+--> sshd +----------> Events
+--> snmpd 上报安全事件
^
| 对象及属性订阅
+--------------------+--------------------+
| | |
证书与 TLS 配置 网口/地址/EthGroup 账号与 SNMP 配置2. API 使用说明与示例
以下路径按默认 ManagerId=1 给出。方法首参 a{ss} 是框架调用上下文字典,命令行调试传空字典 0;业务调用应携带发起者信息。权限取自 mds/model.json。
2.1 Register
功能说明
Register 供自研组件、应用市场组件等内部服务向 nsm 注册网络协议资源,不属于面向管理员或外部客户端开放的管理接口。注册过程会建立持久化数据和资源对象并返回内部监听端口,同时检查名称、端口数量、协议类型、共享关系和端口冲突。HTTPS、SSH、SNMP 等 IsMultiInterface=true 的服务不能被覆盖注册。
| 项目 | 内容 |
|---|---|
| D-Bus 服务名 | bmc.kepler.nsm |
| 调用对象路径 | /bmc/kepler/Managers/1/NetworkProtocol |
| 接口名 | bmc.kepler.Managers.NetworkProtocol |
| 方法名 | Register |
| 使用范围 | 组件间内部调用,不作为对外管理 API。 |
| 废弃状态 | 正常可用 |
Register 的调用入口是上述 NetworkProtocol 父对象。注册成功后会生成 /bmc/kepler/Managers/1/NetworkProtocol/{Name} 协议资源;例如 Name=MyService 时生成 /bmc/kepler/Managers/1/NetworkProtocol/MyService。生成的资源实现 bmc.kepler.Managers.NetworkProtocol.PortConfig 接口,其 Port、SparePort、Enabled 等属性及 SetPorts 方法应在该资源对象上访问,不能在注册入口对象上访问。
参数说明
| 参数名 | 方向 | 类型 | 描述 | 取值范围 |
|---|---|---|---|---|
| 调用上下文 | 输入 | a{ss} | 框架调用上下文。 | 调试可为空字典。 |
| Name | 输入 | string | 服务名称。 | 长度 1~32;不能覆盖多接口服务。 |
| ProtocolType | 输入 | string | 传输层协议。 | 有端口时为 tcp/udp;无端口时为空。 |
| DefaultPorts | 输入 | array<uint16> | 默认主端口及可选备用端口。 | 0~2 个;元素不能为 0,主备端口应不同。相同或与其他协议的外部端口冲突时,注册资源可能被禁用并将冲突端口置为 0。 |
| PortShareWith | 输入 | string | 将端口共享给的服务。 | 无端口时必须为空。 |
| PortShareFrom | 输入 | string | 端口共享来源服务。 | 有端口时必须为空。 |
| InnerPorts | 输出 | array<uint16> | 分配的内部主端口和可选备用端口。 | 0~2 个有效端口。 |
返回值与异常
| 返回值 | 含义 | 触发条件 | 处理建议 |
|---|---|---|---|
aq | 成功 | 校验、分配和持久化完成。 | 使用返回值作为内部监听端口。 |
InvalidValue | 参数错误 | 名称、协议类型、端口数量或共享关系非法。 | 按参数约束修正。 |
PortIdModificationFailed | 默认端口非法 | DefaultPorts 中包含 0。 | 使用 1~65535 范围内的非零端口。 |
CreateLimitReachedForResource | 内部端口资源耗尽 | 候选内部监听端口均冲突。 | 清理无用注册或端口占用后重试。 |
OperationFailed | 不支持注册 | 尝试覆盖多接口内置服务。 | 使用该内置资源自身接口。 |
默认主备端口相同或默认外部端口与其他协议冲突时,当前实现不会直接返回上述异常,而是可能完成注册、禁用生成的资源,并将相应冲突端口置为 0。内部监听端口冲突时,nsm 会尝试重新分配内部端口;只有候选内部端口耗尽时注册才失败。
应用场景
新增 BMC 内部网络服务时,由服务启动流程向 nsm 注册默认端口,之后由 nsm 统一发布资源并管理端口映射。
限制条件
需要 ReadOnly 权限;调用会写入持久化数据库。同一服务重复注册可能更新已有数据,仅支持注册 0~2 个端口。
调试示例
命令行调试
# 仅用于内部组件开发和调试
busctl --user call bmc.kepler.nsm /bmc/kepler/Managers/1/NetworkProtocol \
bmc.kepler.Managers.NetworkProtocol Register \
'a{ss}(ssaqss)' 0 'MyService' 'tcp' 1 12345 '' ''预期返回类似 aq 1 12345。返回值是服务应实际监听的内部端口,不是生成资源的对象路径;内部端口冲突时可能返回重新分配的端口。
注册后查看生成资源及其 PortConfig 接口:
busctl --user introspect bmc.kepler.nsm \
/bmc/kepler/Managers/1/NetworkProtocol/MyService \
bmc.kepler.Managers.NetworkProtocol.PortConfig读取注册后的主端口:
busctl --user get-property bmc.kepler.nsm \
/bmc/kepler/Managers/1/NetworkProtocol/MyService \
bmc.kepler.Managers.NetworkProtocol.PortConfig Port通过生成的资源将主端口修改为 12346,再使用上述 get-property 命令确认属性值:
busctl --user call bmc.kepler.nsm \
/bmc/kepler/Managers/1/NetworkProtocol/MyService \
bmc.kepler.Managers.NetworkProtocol.PortConfig SetPorts \
'a{ss}qq' 0 12346 02.2 SetPorts
功能说明
原子修改协议主端口和备用端口。组件检查端口变化、服务端口能力、0 值和冲突;成功后更新持久化数据及资源对象,并注销该协议已有会话。
| 属性 | 内容 |
|---|---|
| 接口名 | bmc.kepler.Managers.NetworkProtocol.PortConfig |
| 方法名 | SetPorts |
| 废弃状态 | 正常可用 |
参数说明
| 参数名 | 方向 | 类型 | 描述 | 取值范围 |
|---|---|---|---|---|
| 调用上下文 | 输入 | a{ss} | 框架调用上下文。 | 调试可为空字典。 |
| Port | 输入 | uint16 | 新主端口。 | 一般协议为 1~65535;SSDP 为 1024~65535;不能与其他受管端口冲突。 |
| SparePort | 输入 | uint16 | 新备用端口。 | 仅 PortCount=2 有效;单端口服务保持当前值(通常为 0)。 |
| 无 | 输出 | 无 | 成功时无返回参数。 | 不适用。 |
SetPorts 的两个 uint16 参数在 D-Bus 调用中均需提供。只修改其中一个端口时,另一个参数应传入其当前值;单端口服务的 SparePort 通常传 0。
返回值与异常
| 返回值 | 含义 | 触发条件 | 处理建议 |
|---|---|---|---|
| 空返回 | 成功 | 端口未变化或已完成持久化。 | 读取属性确认。 |
InvalidValue | 参数/对象错误 | 内部调用未提供任何端口,或目标协议的持久化数据不存在。 | 检查对象路径及调用参数。 |
PortIdModificationFailed | 端口不可用 | 为 0、主备冲突或与其他协议冲突。 | 改用未占用端口。 |
OperationFailed | 不支持修改 | 无端口服务被修改,或单端口服务设置备用端口。 | 先检查 PortCount。 |
PropertyValueOutOfRange | SSDP 端口超出范围 | 将 SSDP 主端口设置为 1~1023。 | 将 SSDP 主端口设置为 1024~65535 范围内的未占用端口。 |
应用场景
管理员调整 HTTPS、SSH、SNMP 或其他已注册服务的监听端口。
限制条件
需要 SecurityMgmt 权限。一般协议的主端口不能为 0,SSDP 主端口必须为 1024~65535;备用端口仅用于双端口服务。修改会注销相关协议已有会话,并可能重载 nginx、sshd 或 snmpd。
调试示例
命令行调试
busctl --user call bmc.kepler.nsm /bmc/kepler/Managers/1/NetworkProtocol/HTTPS \
bmc.kepler.Managers.NetworkProtocol.PortConfig SetPorts 'a{ss}qq' 0 8443 02.3 SetAlgorithmsState
功能说明
批量启停一类 SSH 算法。接口分别位于 Ciphers、MACs、KexAlgorithms、HostKeyAlgorithms 对象;成功后持久化并安排 sshd 配置刷新及安全告警复核。
| 属性 | 内容 |
|---|---|
| 接口名 | bmc.kepler.Managers.NetworkProtocol.SSH.Algorithms |
| 方法名 | SetAlgorithmsState |
| 废弃状态 | 正常可用 |
参数说明
| 参数名 | 方向 | 类型 | 描述 | 取值范围 |
|---|---|---|---|---|
| 调用上下文 | 输入 | a{ss} | 框架调用上下文。 | 调试可为空字典。 |
| AlgorithmsState | 输入 | array<struct<string, boolean>> | 算法名及目标状态。 | 有效修改项的名称应属于目标类别;未知名称会被忽略;每类至少保留一个启用算法。 |
| 无 | 输出 | 无 | 成功时无返回参数。 | 不适用。 |
返回值与异常
| 返回值 | 含义 | 触发条件 | 处理建议 |
|---|---|---|---|
| 空返回 | 成功 | 修改完成、输入为空数组或状态无变化。 | 读取 Enabled 属性确认。 |
AllAlgorithmsDisabled | 安全约束失败 | 将关闭该类别全部算法。 | 至少保留一个启用算法。 |
应用场景
SSH 安全加固、禁用 ssh-rsa 或弱密钥交换算法,以及按客户端兼容性开启安全算法。
限制条件
需要 SecurityMgmt 权限。未知算法会记录 invalid algorithm_name 并被忽略;空数组或全部状态均未变化时直接成功返回;不得关闭某类别全部有效算法。配置通过异步 sshd 更新流程生效。
调试示例
命令行调试
busctl --user call bmc.kepler.nsm \
/bmc/kepler/Managers/1/NetworkProtocol/SSH/Algorithms/HostKeyAlgorithms \
bmc.kepler.Managers.NetworkProtocol.SSH.Algorithms SetAlgorithmsState \
'a{ss}a(sb)' 0 1 'ssh-rsa' false3. 组件扩展案例
3.1 扩展能力概述
组件支持动态协议注册、模型数据及代码级扩展。可通过 Register 注册普通协议;可在 proto/datas.yaml 增加内置协议、内部端口或 SSH 算法并重新生成模型;构建可按 WEBVNC、SNMP 和芯片选项裁剪;customization/customization.py 用于镜像定制。
3.2 扩展点说明
- 动态注册适合无需额外 D-Bus 接口的普通协议。
proto/datas.yaml的t_protocol_config、t_protocol_inner_port定义协议默认数据。- 新增 SSH 算法还需同步
src/lualib/common/config.lua的有效列表;新增 KEX/HostKey 算法应走New*Algorithm兼容表。 - CMake 根据
CONAN_DEFS_WEBVNC_SUPPORTED、CONAN_DEFS_SNMP_SUPPORTED和芯片选项安装模块。
3.3 二次开发指导
步骤一
仅新增普通服务时使用 Register;需要额外属性或方法时,在 mds/model.json、proto/datas.yaml 定义模型,并在 src/lualib 实现回调。不要手工修改带 DO NOT EDIT 标记的 gen/ 文件。
步骤二
执行 make gen 生成代码,补充 test/unit 或 test/integration 用例,再执行 bingo test。构建环境需提供 TPL_DIR 和 Conan 安装生成的 temp 环境。
示例代码
local context = require('mc.context')
-- 调用方在 mds/service.json 中声明依赖后,由框架为调用方生成客户端。
local client = require('my_service.client')
local obj = client:GetNetworkProtocolObjects()
['/bmc/kepler/Managers/1/NetworkProtocol']
local inner_ports = obj:Register(context.new('my_service', 'N/A', 'N/A'), {
Name = 'MyService', ProtocolType = 'tcp', DefaultPorts = {12345},
PortShareWith = '', PortShareFrom = ''
})验证方法
- 启动 nsm 依赖、
nsm.service和扩展服务。 - 执行
busctl --user introspect bmc.kepler.nsm /bmc/kepler/Managers/1/NetworkProtocol/MyService。 - 预期对象存在、
Port为 12345,且 nsm 日志出现注册成功信息。
注意事项
- 协议名最长 32,端口最多 2 个,主备及不同协议端口不能冲突。
- 新 SSH 算法须同步模型、有效算法列表和兼容表,每类至少启用一个。
- 配置通过
/dev/shm临时文件替换持久化文件,扩展须沿用安全文件接口和权限。
4. 日志说明
4.1 一键日志收集
组件未注册自定义 on_dump 回调,一键日志按框架默认逻辑收集。诊断时同时保留 nsm 的标准日志、目标服务日志和网络配置快照。
4.2 关键日志信息
| 日志片段 | 日志级别 | 含义解读 | 建议处理动作 |
|---|---|---|---|
New port %u conflicts with %s | ERROR | 新端口与受管协议端口冲突。 | 查询全部协议端口并换用空闲端口。 |
[nginx] Restart service failed, attempt to forcibly restart | ERROR | nginx 常规重启失败。 | 检查生成配置、证书和后续日志。 |
[session] %s log out failed, err: %s | WARN | 配置变化后会话注销失败。 | 检查 SessionService 并清理会话。 |
nsm(network service mgmt) service start | NOTICE | nsm 开始启动。 | 反复出现时检查 systemd 重启原因。 |
[register] Protocol(%s) register successfully | INFO | 协议注册成功。 | 查询资源对象及内部端口。 |
5. 问题定界指南
5.1 典型问题定界
| 现象描述 | 是否为本组件问题 | 判断依据 | 关键证据收集方法 |
|---|---|---|---|
| 修改端口返回冲突 | 通常是 | 冲突校验由 nsm 执行。 | 收集 conflicts with 日志并读取全部协议端口。 |
| 属性已更新但 HTTPS 不监听 | 需联合定界 | nsm 管配置和 nginx;证书或外部进程也可能导致失败。 | 收集 nsm/nginx 日志,执行 nginx -t、ss -lntp。 |
nsm.service 持续重启 | 是或依赖问题 | 配置为 Restart=always,强依赖 dbus、maca、persistence。 | 查询相关服务状态和 journalctl -u nsm.service。 |
| SNMP 配置正常但 UDP 161 未监听 | 需联合定界 | 构建可能关闭 SNMP,或 snmpd 启动失败。 | 检查 SNMP 能力、snmpd、配置文件及 ss -lnup。 |
5.2 最小化复现与证据收集
- 记录协议名、当前端口、备选端口、
Enabled状态和IsMultiInterface。 - 使用
busctl读取对象属性并记录调用前后的值。 - 复现端口冲突时,收集 nsm、目标协议服务和 iptables 日志。
- 配置变更后记录 SessionService 清理结果及客户端重连结果。
5.3 错误对象解读
资源协作方法成功时返回数据或空返回,失败时抛出消息异常;代码未定义 0/-1 数字错误码。
| 错误码 | 含义 | 可能原因 | 排查建议 |
|---|---|---|---|
InvalidValue | 输入无效 | 参数缺失、值错误或对象数据不存在。 | 对照签名检查参数和路径。 |
PortIdModificationFailed | 端口修改失败 | 端口为 0、冲突或使能时无有效端口。 | 查看冲突日志并换空闲端口。 |
OperationFailed | 操作不支持 | 覆盖多接口服务或修改不支持的端口。 | 查询 IsMultiInterface/PortCount。 |
CreateLimitReachedForResource | 内部端口耗尽 | 候选端口持续冲突至超过 65535。 | 清理无效注册和占用。 |
AllAlgorithmsDisabled | 禁止关闭全部算法 | 某算法类别将无启用项。 | 至少启用一个算法。 |
PropertyValueOutOfRange | 属性值超出允许范围 | SSDP 主端口小于 1024。 | 为 SSDP 选择 1024~65535 范围内的未占用端口。 |
5.4 调试方法
开启调试日志
dist/config.cfg 仅定义日志路径,级别由公共 libmc 配置及 mc.logging 管理,仓库无运行时一键 DEBUG 接口。调试环境可在公共日志配置中将 nsm 设为 DEBUG 后重启;单元测试默认由 test/unit/test.lua 设置为 INFO,可在本地临时调整为框架支持的 DEBUG。
复现问题方法
- 前置条件设置:确认 nsm 及 dbus、maca、persistence 正常,记录目标协议当前端口。
- 操作步骤:将另一协议已用端口通过
SetPorts设置给目标协议,同时跟踪 nsm 日志。 - 预期现象:调用收到
PortIdModificationFailed,日志出现冲突信息,原端口保持不变。
6. 常见问题解答
Q1:为什么设置端口后返回端口修改失败?
- 问题描述:
SetPorts返回PortIdModificationFailed。 - 一句话答案:主端口、备端口或其他协议已占用目标端口。
- 根因说明:nsm 跨普通协议和多系统协议统一校验,主备之间也不能冲突。
- 解决方案:查看冲突日志,读取协议端口并选择空闲端口。
- 规避方案:建立统一端口规划。
- 相关文档链接:本文 2.2、5.2 节。
- 适用版本:1.140.14。
Q2:为什么 Register 不能覆盖 HTTPS、SSH 或 SNMP?
- 问题描述:注册同名内置服务时失败。
- 一句话答案:内置多接口服务由专用对象和回调维护,不能由 Register 动态覆盖。
- 根因说明:其专用属性和回调无法由普通动态注册完整建立。
- 解决方案:使用现有 HTTPS、SSH 或 SNMP 对象及
SetPorts。 - 规避方案:动态服务使用唯一名称。
- 相关文档链接:本文 2.1 节。
- 适用版本:1.140.14。
Q3:为什么不能禁用某类全部 SSH 算法?
- 问题描述:返回
AllAlgorithmsDisabled。 - 一句话答案:同类算法必须至少保留一个,否则 SSH 无法完成协商。
- 根因说明:全部禁用会使 SSH 无法协商,组件会在持久化前阻止。
- 解决方案:同一请求中至少保留一个安全算法为
true。 - 规避方案:先核对客户端兼容算法。
- 相关文档链接:本文 2.3 节。
- 适用版本:1.140.14。
Q4:为什么修改网络服务配置后连接可能受到影响?
- 问题描述:修改端口或使能状态后已有连接退出,或者修改 SSH 算法后新连接的协商结果发生变化。
- 一句话答案:服务配置和会话清理会改变现有连接或后续协商条件。
- 根因说明:受支持协议的端口或使能状态变化后,组件会延迟 3 秒调用 SessionService 清理对应会话;SSH 算法变化会触发 sshd 配置刷新,主要影响后续连接及算法协商。
- 解决方案:服务配置生效后使用新端口或新算法重新连接;失败时检查 nsm 和对应服务日志。
- 规避方案:通过独立管理通道在低峰期执行配置变更。
- 相关文档链接:本文 2.2、2.3 节。
- 适用版本:1.140.14。
Q5:为什么 SNMP 资源或 snmpd 不存在?
- 问题描述:无 SNMP 对象或 UDP 161 未监听。
- 一句话答案:产品构建未启用 SNMP,或能力配置未打开。
- 根因说明:nsm 根据构建选项和
SNMPSupported决定是否初始化 SNMP。 - 解决方案:确认产品构建选项、能力配置和
snmpd.service状态。 - 规避方案:产品配置阶段明确能力,升级后检查资源树和端口。
- 相关文档链接:本文 1.5、5.1 节。
- 适用版本:1.140.14。
附录
附录 A 参考资料
mds/service.json:版本、依赖和订阅关系。mds/model.json、gen/nsm/json_types/:资源、权限、D-Bus 签名和类型。proto/datas.yaml、src/lualib/:默认数据和接口实际实现。
附录 B 修订记录
| 版本 | 日期 | 修订人 | 修订内容 |
|---|---|---|---|
| v1.0 | 2026-08-27 | o1315548501 | 更新补充README文档。 |
| v1.1 | 2026-09-01 | o1315548501 | 明确 Register 的内部调用入口、注册后资源路径及验证方法,修正接口与方法说明。 |