一个网口对象创建了两个mgmtport对象

基于2512 LTS版本的openUBMC

发现一个问题,只插了一张四口网卡:

但是网络管理页面出现五个网口:

可以看到MgmtPort_2和MgmtPort_146的DeviceId、DevicePortId相同,这说明一个网口对应了多个mgmtport对象:

怀疑可能是这里创建mgmtport对象时没有检查并删除废弃的mgmtport导致:

希望确认一下这个问题。

答案内容由AI生成,仅供参考:

:pushpin: 总结与结论

项目 内容
问题性质 :red_exclamation_mark: Bug 级问题:一个物理网口不应创建多个 MgmtPort 对象
根本原因 AddMgmtPort 调用前缺乏重复性校验,且不同类型(ExternalPCIe/Ocp)可并行注册同一端口
影响范围 网络配置混乱、IP 冲突、WebUI 显示异常、导入导出配置错误
是否与您猜测一致 :white_check_mark: 完全一致:ncsi_nc_port_register() 缺少对废弃对象的主动检测与清除机制
建议措施 :one: 注册前增加去重判断
:two: 引入 NetworkPort 作为唯一物理端口标识
:three: 启动时自动清理异常实例
点击此处查看详细分析解答

关于“一个网口对象创建了两个 MgmtPort 对象”的问题分析

根据您提供的现象和信息,针对在基于 2512 LTS 版本的 openUBMC 系统中出现“一个物理网口对应多个 MgmtPort 对象”的问题,结合系统架构、日志数据及代码逻辑分析,以下是详细结论。


:magnifying_glass_tilted_left: 问题概述

  • 现象

    • 物理上仅插入一张四口 PCIe 网卡(SF400T-L201),但网络管理页面显示了 5 个网口
    • 其中 MgmtPort_2MgmtPort_146DeviceId=1, DevicePortId=1, Silkscreen="Port1" 完全相同,仅 Id 不同,且分属不同类型(ExternalPCIe vs Ocp),表明 同一物理端口被注册为两个不同的管理网口对象
    • 这导致 BMC 网络配置界面出现重复或冗余的网口条目。
  • 核心怀疑点

    • ncsi_info:ncsi_nc_port_register() 函数执行时,未正确检测并清理废弃的 MgmtPort 实例,可能引发重复创建。

:puzzle_piece: 根本原因分析

1. MgmtPort 的唯一性由多个字段共同决定

从知识库可知,MgmtPort 类型属于 BMC 中用于表示物理网络接口的管理对象。其关键标识属性如下:

属性 含义 是否唯一
Id BMC 内部对象唯一 ID(主键) :white_check_mark:
DeviceId 设备编号(如 PCIe 卡编号) :cross_mark:
DevicePortId 卡上的端口号(如 Port1=1) :cross_mark:
EthId 关联的系统以太网设备号(如 eth0) :cross_mark:
Type 网卡类型(Dedicated / ExternalPCIe / Ocp) :cross_mark:
Silkscreen 丝印标签(如 “Port1”) :cross_mark:

虽然上述属性描述网口位置和类型,但 只有 Id 是全局唯一标识。因此,即使 DeviceIdDevicePortId 相同,只要 Id 不同,系统仍视为两个独立对象。


2. AddMgmtPort 方法可能导致重复注册

AddMgmtPort 是用于向 BMC 添加管理网口的核心方法,原型如下:

ok, rsp = pcall(eth_obj.AddMgmtPort_PACKED, self, ctx_new, 
                SlotId, PortId, Silkscreen, EthId, Type, MgmtPortId)
  • 参数说明:
    • SlotId: 插槽编号
    • PortId: NCSI 端口 ID
    • Silkscreen: 显示名称(如 Port1)
    • EthId: 对应 ethX 设备编号
    • Type: 网口类型(ExternalPCIeOcp 等)
    • MgmtPortId: 指定分配的 MgmtPortId(可选)

:warning: MgmtPortId 未强制校验或复用已有对象,则可能在不同上下文中对同一物理端口调用多次 AddMgmtPort,导致重复创建。


3. ncsi_info:ncsi_nc_port_register() 逻辑存在隐患

代码逻辑审查:

for id = 1, nc_info.PortNum do
    port_info = self.db:select(...):where({PortId = id}):first()
    if port_info.PortAvailable then
        -- 尝试添加 MgmtPort
        ok, rsp = pcall(eth_obj.AddMgmtPort_PACKED, ..., port_info.Type, port_info.MgmtPortId)
        if ok then
            port_info.MgmtPortId = rsp.PortId  -- 更新数据库中的 MgmtPortId
            port_info:save()
        end
    elseif port_info.MgmtPortId ~= 255 and port_info.MgmtPortId ~= 0 then
        -- 删除不可用端口对应的 MgmtPort
        ok, rsp = pcall(eth_obj.DeleteMgmtPort_PACKED, self, ctx_new, port_info.MgmtPortId)
        if ok then
            port_info.MgmtPortId = 0
            port_info:save()
        end
    end
end

存在的问题点:

问题 分析
:white_check_mark: 有删除逻辑 PortAvailable=falseMgmtPortId ≠ 0/255 时会触发删除
:cross_mark: 无前置去重机制 AddMgmtPort未检查是否已存在相同 (DeviceId, DevicePortId, Type) 的 MgmtPort 对象,直接创建
:cross_mark: 依赖数据库状态同步 MgmtPortId 存储于 NcsiNCPortInfo 表中,若状态异常或未持久化,可能导致重复注册
:cross_mark: Type 不同即视为不同对象 即使同一物理端口,若先后以 ExternalPCIeOcp 类型注册,系统认为是两个不同对象

结果:当系统因热插拔、固件升级或配置变更多次触发注册流程时,可能因未清理旧对象而产生多个 MgmtPort 实例指向同一物理端口


4. 实际案例佐证:MgmtPort_2 与 MgmtPort_146

对比二者属性:

属性 MgmtPort_2 MgmtPort_146
Id 2 146
DeviceId 1 1
DevicePortId 1 1
EthId 0 0
Silkscreen “Port1” “Port1”
Type "ExternalPCIe" "Ocp"
LinkStatus “” “Connected”
OriginalGroupId 0 1
  • 两者 DeviceIdDevicePortId 完全一致 → 指向同一个物理网口。
  • Type 不同 → 来自不同注册上下文(NC-SI over PCIe vs OCP 模块)。
  • 均通过 AddMgmtPort 注册,且未在注册前销毁对方

:backhand_index_pointing_right: 结论:系统将 同一物理端口按照不同接口标准进行了两次独立注册,形成了两个“影子”对象。


:white_check_mark: 建议修复方案

:white_check_mark: 方案一:注册前增加重复性检查(推荐)

在调用 AddMgmtPort_PACKED 前,先查询是否存在已注册的相同物理端口对象:

-- 伪代码:查找是否已有相同 DeviceId + DevicePortId + Type 的 MgmtPort
local existing = self.db:query_mgmtport_by_key(DeviceId, DevicePortId, Type)
if existing then
    log:warn("MgmtPort already exists for DeviceId=%d, PortId=%d, Type=%s", DeviceId, DevicePortId, Type)
    port_info.MgmtPortId = existing.Id  -- 复用已有 Id
    port_info:save()
else
    -- 正常 AddMgmtPort 流程
end

优势:避免重复创建,保持对象一致性。


:white_check_mark: 方案二:统一网口抽象层级,引入 NetworkPort 作为底层实体

引用知识库中的概念:

NetworkPort 是代表物理或逻辑网络接口的系统级实体,作为 MgmtPort 的基础对象。

建议重构为:

  • 一个 NetworkPort 对应一个实际的物理网口(基于 BDF + DevicePortId 唯一标识);
  • 多个 MgmtPort 可绑定到同一个 NetworkPort,但仅允许一个处于“激活”状态;
  • 添加互斥机制,防止同一 NetworkPort 被多类型同时启用。

:backhand_index_pointing_right: 类似 Redfish 中的 PhysicalPortEthernetInterface 映射关系。


:white_check_mark: 方案三:启动时/注册前执行一致性清理

添加启动或注册前扫描逻辑,自动删除非法或重复的 MgmtPort

-- 清理规则示例
for each mgmtport in all_mgmtports:
    if not is_port_physical_exists(DeviceId, DevicePortId):
        delete_mgmtport(Id)
    else:
        count = count_same_physical_port(DeviceId, DevicePortId)
        if count > 1:
            keep latest one, delete others

可作兼容性兜底措施。


:pushpin: 总结与结论

项目 内容
问题性质 :red_exclamation_mark: Bug 级问题:一个物理网口不应创建多个 MgmtPort 对象
根本原因 AddMgmtPort 调用前缺乏重复性校验,且不同类型(ExternalPCIe/Ocp)可并行注册同一端口
影响范围 网络配置混乱、IP 冲突、WebUI 显示异常、导入导出配置错误
是否与您猜测一致 :white_check_mark: 完全一致:ncsi_nc_port_register() 缺少对废弃对象的主动检测与清除机制
建议措施 :one: 注册前增加去重判断
:two: 引入 NetworkPort 作为唯一物理端口标识
:three: 启动时自动清理异常实例

:paperclip: 参考资料依据(来自 Context)

  1. MgmtPort 是“物理网络卡信息持有者”,包含 DeviceId, DevicePortId, Silkscreen 等字段;
  2. AddMgmtPort 是“添加管理端口”的方法,参数含 Type, Silkscreen, EthId 等;
  3. NetworkPort 是“系统级网络接口实体”,更适合作为物理端口抽象;
  4. 已有评审文档支持多网口组管理(如 EthGroup)、导入导出 MgmtPort->Id,说明 Id 是关键追踪字段;
  5. 存在 DeleteMgmtPort 接口,具备删除能力,但当前流程未有效利用。

如需进一步定位具体是哪个模块(如 OCP 模块加载、NC-SI 发现)率先注册了该端口,建议启用 BMC 日志中的 ncsi:*ethmgr:* 跟踪,抓取完整注册时序日志。