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支持双端口协议的第二个对外端口;单端口协议不可配置。
InnerPortnsm 为端口转发分配的内部监听端口;冲突时会自动选择其他端口。

1.5 外部交互边界图

text
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 接口,其 PortSparePortEnabled 等属性及 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 个端口。

调试示例

命令行调试
sh
# 仅用于内部组件开发和调试
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 接口:

sh
busctl --user introspect bmc.kepler.nsm \
  /bmc/kepler/Managers/1/NetworkProtocol/MyService \
  bmc.kepler.Managers.NetworkProtocol.PortConfig

读取注册后的主端口:

sh
busctl --user get-property bmc.kepler.nsm \
  /bmc/kepler/Managers/1/NetworkProtocol/MyService \
  bmc.kepler.Managers.NetworkProtocol.PortConfig Port

通过生成的资源将主端口修改为 12346,再使用上述 get-property 命令确认属性值:

sh
busctl --user call bmc.kepler.nsm \
  /bmc/kepler/Managers/1/NetworkProtocol/MyService \
  bmc.kepler.Managers.NetworkProtocol.PortConfig SetPorts \
  'a{ss}qq' 0 12346 0

2.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
PropertyValueOutOfRangeSSDP 端口超出范围将 SSDP 主端口设置为 1~1023。将 SSDP 主端口设置为 1024~65535 范围内的未占用端口。

应用场景

管理员调整 HTTPS、SSH、SNMP 或其他已注册服务的监听端口。

限制条件

需要 SecurityMgmt 权限。一般协议的主端口不能为 0,SSDP 主端口必须为 1024~65535;备用端口仅用于双端口服务。修改会注销相关协议已有会话,并可能重载 nginx、sshd 或 snmpd。

调试示例

命令行调试
sh
busctl --user call bmc.kepler.nsm /bmc/kepler/Managers/1/NetworkProtocol/HTTPS \
  bmc.kepler.Managers.NetworkProtocol.PortConfig SetPorts 'a{ss}qq' 0 8443 0

2.3 SetAlgorithmsState

功能说明

批量启停一类 SSH 算法。接口分别位于 CiphersMACsKexAlgorithmsHostKeyAlgorithms 对象;成功后持久化并安排 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 更新流程生效。

调试示例

命令行调试
sh
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' false

3. 组件扩展案例

3.1 扩展能力概述

组件支持动态协议注册、模型数据及代码级扩展。可通过 Register 注册普通协议;可在 proto/datas.yaml 增加内置协议、内部端口或 SSH 算法并重新生成模型;构建可按 WEBVNC、SNMP 和芯片选项裁剪;customization/customization.py 用于镜像定制。

3.2 扩展点说明

  • 动态注册适合无需额外 D-Bus 接口的普通协议。
  • proto/datas.yamlt_protocol_configt_protocol_inner_port 定义协议默认数据。
  • 新增 SSH 算法还需同步 src/lualib/common/config.lua 的有效列表;新增 KEX/HostKey 算法应走 New*Algorithm 兼容表。
  • CMake 根据 CONAN_DEFS_WEBVNC_SUPPORTEDCONAN_DEFS_SNMP_SUPPORTED 和芯片选项安装模块。

3.3 二次开发指导

步骤一

仅新增普通服务时使用 Register;需要额外属性或方法时,在 mds/model.jsonproto/datas.yaml 定义模型,并在 src/lualib 实现回调。不要手工修改带 DO NOT EDIT 标记的 gen/ 文件。

步骤二

执行 make gen 生成代码,补充 test/unittest/integration 用例,再执行 bingo test。构建环境需提供 TPL_DIR 和 Conan 安装生成的 temp 环境。

示例代码

lua
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 = ''
})

验证方法

  1. 启动 nsm 依赖、nsm.service 和扩展服务。
  2. 执行 busctl --user introspect bmc.kepler.nsm /bmc/kepler/Managers/1/NetworkProtocol/MyService
  3. 预期对象存在、Port 为 12345,且 nsm 日志出现注册成功信息。

注意事项

  1. 协议名最长 32,端口最多 2 个,主备及不同协议端口不能冲突。
  2. 新 SSH 算法须同步模型、有效算法列表和兼容表,每类至少启用一个。
  3. 配置通过 /dev/shm 临时文件替换持久化文件,扩展须沿用安全文件接口和权限。

4. 日志说明

4.1 一键日志收集

组件未注册自定义 on_dump 回调,一键日志按框架默认逻辑收集。诊断时同时保留 nsm 的标准日志、目标服务日志和网络配置快照。

4.2 关键日志信息

日志片段日志级别含义解读建议处理动作
New port %u conflicts with %sERROR新端口与受管协议端口冲突。查询全部协议端口并换用空闲端口。
[nginx] Restart service failed, attempt to forcibly restartERRORnginx 常规重启失败。检查生成配置、证书和后续日志。
[session] %s log out failed, err: %sWARN配置变化后会话注销失败。检查 SessionService 并清理会话。
nsm(network service mgmt) service startNOTICEnsm 开始启动。反复出现时检查 systemd 重启原因。
[register] Protocol(%s) register successfullyINFO协议注册成功。查询资源对象及内部端口。

5. 问题定界指南

5.1 典型问题定界

现象描述是否为本组件问题判断依据关键证据收集方法
修改端口返回冲突通常是冲突校验由 nsm 执行。收集 conflicts with 日志并读取全部协议端口。
属性已更新但 HTTPS 不监听需联合定界nsm 管配置和 nginx;证书或外部进程也可能导致失败。收集 nsm/nginx 日志,执行 nginx -tss -lntp
nsm.service 持续重启是或依赖问题配置为 Restart=always,强依赖 dbus、maca、persistence。查询相关服务状态和 journalctl -u nsm.service
SNMP 配置正常但 UDP 161 未监听需联合定界构建可能关闭 SNMP,或 snmpd 启动失败。检查 SNMP 能力、snmpd、配置文件及 ss -lnup

5.2 最小化复现与证据收集

  1. 记录协议名、当前端口、备选端口、Enabled 状态和 IsMultiInterface
  2. 使用 busctl 读取对象属性并记录调用前后的值。
  3. 复现端口冲突时,收集 nsm、目标协议服务和 iptables 日志。
  4. 配置变更后记录 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。

复现问题方法

  1. 前置条件设置:确认 nsm 及 dbus、maca、persistence 正常,记录目标协议当前端口。
  2. 操作步骤:将另一协议已用端口通过 SetPorts 设置给目标协议,同时跟踪 nsm 日志。
  3. 预期现象:调用收到 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.jsongen/nsm/json_types/:资源、权限、D-Bus 签名和类型。
  • proto/datas.yamlsrc/lualib/:默认数据和接口实际实现。

附录 B 修订记录

版本日期修订人修订内容
v1.02026-08-27o1315548501更新补充README文档。
v1.12026-09-01o1315548501明确 Register 的内部调用入口、注册后资源路径及验证方法,修正接口与方法说明。