创建mctp over pcie的接口是否有超时的机制?

问题描述

当前通过mctp_lib这个库的get_endpoint_and_transport来创建endpoint时会一直卡住,不会超时退出也没报错。通过log可看到start 3有打印,start 4一直没打印;
具体的代码逻辑如下:

求助内容:

1.get_endpoint_and_transport这个接口是否有超时的机制呢?
2.当前代码中phy_addr对应的pcie设备不存在的情况下,该接口也没报错,是否也不正常?

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

总结

问题 结论 建议
get_endpoint_and_transport 是否有超时机制? 无内置超时机制,可能导致永久阻塞 添加外部超时控制
设备不存在时不报错是否正常? 不正常,应提前校验并返回错误 调用前检查设备存在性
如何定位问题? 使用 tracemctp 查看通信过程 启用调试命令辅助分析
长期解决方向? 接口缺乏鲁棒性 推动增加超时和异步支持

:pushpin: 最终建议:在调用 get_endpoint_and_transport 前,务必校验设备存在性 + 添加外部超时机制,以规避当前接口的设计局限。

点击此处查看详细分析解答

关于 get_endpoint_and_transport 接口的超时机制与异常行为分析

根据您提供的上下文信息,以下是针对您提出的两个问题的详细分析与解答。


1. get_endpoint_and_transport 接口是否有超时机制?

**结论:当前 get_endpoint_and_transport 接口在调用过程中 **(MCTP over PCIe)

分析依据:

  • mctpd 服务管理 MCTP 通信生命周期
    mctpd 是 OpenUBMC 中负责管理 MCTP 协议通信的核心服务,它通过 mctp_lib 提供的接口(如 get_endpoint_and_transport)来创建和管理 MCTP Endpoint 和 Transport 对象。
    mctpd 支持对 MCTP 请求设置超时机制,例如存在 MctpRequestTimeout 错误类型,表示 MCTP 请求超时(如参考文档 #5 所示:“kepler.mctpd.MctpRequestTimeout: The Mctp request timeout”)。

  • 但 get_endpoint_and_transport 本身不保证内部操作有超时处理
    尽管 MCTP 请求通信层具备超时能力,但从当前行为看,get_endpoint_and_transport 在等待远端设备响应或路由建立时可能会阻塞,且无内置超时退出机制。
    您的日志中“start 3”已打印而“start 4”未打印,说明该函数调用处于永久阻塞状态,并未触发错误或返回,这表明:

    • 函数内部可能在等待某个事件(如 D-Bus 接口创建、路由信息更新、endpoint 初始化完成);
    • 该等待过程缺乏主动超时控制,导致调用方线程卡住。
  • 系统为异步事件驱动架构,初始化依赖事件时序而非同步阻塞
    上下文提到系统采用“System Asynchronous Event-Driven Architecture”,即组件初始化依赖事件触发而非顺序执行。
    因此,get_endpoint_and_transport 可能在等待一个尚未发生的事件(如 PCIe 设备上线、mctpd 完成路由表构建),但由于未设置超时,最终造成无限等待。


2. 当 PCIe 设备不存在时,接口不报错是否正常?

结论:不正常 —— 若目标 PCIe 设备不存在,get_endpoint_and_transport 应返回明确错误或超时,而不是一直阻塞。

分析依据:

  • 正确流程应包含设备可达性校验
    该函数的工作流程包括:

    1. 通过 phy_addr 定位远端 MCTP Endpoint;
    2. 查询系统路由表确认该地址是否可达;
    3. 向 mctpd 请求创建对应的 Endpoint 和 Transport 对象;
    4. 等待对象创建完成并返回句柄。

    其中第 2 步应能检测到 phy_addr 是否有效。如果对应设备不存在(如 BDF 地址无实际硬件),则路由表中不应存在对应条目,此时应快速返回失败。

  • 实际存在类似失败场景的日志记录
    上下文日志(参考文档 #3)显示:

    pcie_device ERROR : device_service.lua (342): [DeviceService] Can not find matching PCIeAddrinfo, PCIeDevice position = 00 DeviceType = 26 SlotID = 1
    

    这表明系统在尝试查找 PCIe 地址信息失败时会明确记录错误。说明系统具备检测“设备未匹配”的能力。

  • 当前无报错 + 无限等待 = 存在设计缺陷或配置问题
    结合上述日志和行为分析,get_endpoint_and_transport 在设备不存在时仍卡住,属于以下一种或多种情况:

    • 路由信息未及时更新或未正确生成:即使设备不存在,mctpd 仍尝试发起通信并等待响应;
    • 缺乏前置校验机制:函数未先检查设备是否存在(如通过 get_pcie_device_info() 或 D-Bus 查询 PCIe 设备列表);
    • 通信底层无限重试:底层驱动或 mctpd 在发送 Discover 请求后无限重试,未设定最大重试次数或超时。

建议解决方案

:white_check_mark: 方案 1:手动添加外部超时控制

使用 Lua 的异步任务或定时器机制,避免阻塞主线程:

local function register_pcie_endpoint_with_timeout(bus, bus_num, dev_num, func_num, timeout_sec)
    local timeout_occurred = false
    local timer = setTimeout(timeout_sec * 1000, function()
        timeout_occurred = true
        log:error("get_endpoint_and_transport timeout after %d seconds", timeout_sec)
    end)

    local success = false
    local co = coroutine.create(function()
        local ok, phy_addr = pcall(mctp_lib.bdf_to_phy_addr, bus_num, dev_num, func_num)
        if not ok then
            log:error('bdf to phy addr failed')
            return
        end

        -- 使用非阻塞方式或后台任务尝试获取 endpoint
        local ok2, endpoint, transport = pcall(mctp_lib.get_endpoint_and_transport, bus, "yctco_app", phy_addr, MSG_TYPE_VDPCI)
        
        if timeout_occurred then return end
        clearTimeout(timer)

        if not ok2 or not endpoint or not transport then
            log:error('get_endpoint_and_transport failed')
        else
            log:notice("Endpoint created successfully")
            success = true
        end
    end)

    resume(co) -- 启动协程
end

注意:需确认当前 Lua 环境是否支持协程或异步任务机制。


:white_check_mark: 方案 2:调用前校验设备存在性

在调用 get_endpoint_and_transport 前,先确认 PCIe 设备已识别:

local pci_device = c_nvme_mctp:get_pcie_device_info()
if not pci_device then
    log:error("No matching PCIe device found for given position")
    return
end

确保设备已在系统资源树中注册(如 /bmc/kepler/Systems/.../PCIeDevices/ 路径下可查)再进行 MCTP 连接。


:white_check_mark: 方案 3:启用调试工具定位通信问题

使用 tracemctp 工具查看底层通信是否发出请求及是否有响应:

attach mctpd
tracemctp start

可判断:

  • 是否发送了 Discover 或 Set-EID 请求;
  • 是否收到响应;
  • 是否因底层通信失败导致无返回。

参考文档 #6 提出新增 TraceMessage 方法以打印报文,说明 缺乏调试手段是常见痛点。


:white_check_mark: 方案 4:建议推动接口改进

向 mctp_lib 组件维护者提出以下改进建议:

  • 为 get_endpoint_and_transport 增加可选超时参数;
  • 在设备不可达时主动返回错误(如 NO_ROUTE_TO_HOST);
  • 提供非阻塞异步版本接口(如 get_endpoint_and_transport_async);

总结

问题 结论 建议
get_endpoint_and_transport 是否有超时机制? 无内置超时机制,可能导致永久阻塞 添加外部超时控制
设备不存在时不报错是否正常? 不正常,应提前校验并返回错误 调用前检查设备存在性
如何定位问题? 使用 tracemctp 查看通信过程 启用调试命令辅助分析
长期解决方向? 接口缺乏鲁棒性 推动增加超时和异步支持

:pushpin: 最终建议:在调用 get_endpoint_and_transport 前,务必校验设备存在性 + 添加外部超时机制,以规避当前接口的设计局限。

这个接口是不存在超时的,底层是死等创建,一般通过fork个skynet协程去调用,接口不返回也不会有什么性能上的损耗。这个本来是确定有这个硬件才调用这个接口的。

如果期望超时退出可以用get_endpoint_and_transport_with_timeout接口,入参是bus, module_name, ep_info, timeout。bus, module_name和get_endpoint_and_transport一致,ep_info是字典,需要包含以下参数:

ep_info = {
        phy_addr = phy_addr,
        msg_type = msg_type,
        position = position,
        system_id = system_id
    }

其中phy_addr和msg_type必填;position为smbus协议才有的,pcie协议可以不填;system_id是主机id,选填,默认主机1。
timeout是超时时间,单位10ms,不填默认5分钟。