常规适配网卡时,我们可根据 network_adapter/src/lualib/hardware_config 下支持的协议进行 SR 文件适配即可, 需要关注 SR 中NetworkAdapter(网卡类)中的 Model属性,即芯片型号,芯片型号决定了该网卡支持哪些协议 , 框架会根据 NetworkAdapter 的 Model 属性加载对应的 network_adapter/src/lualib/hardware_config 下的协议配置文件, 例如: 配置 Model 为 E810 即加载对应的 network_adapter/src/lualib/hardware_config/E810.lua 文件;
网卡部分 ncsi 获取部分属性流程如下
当现有的 network_adapter/src/lualib/hardware_config 下支持协议不满足当前网卡需求时, 就需要对网卡进行新的协议适配, 当前框架支持对已有协议的拓展、新增, 以满足不同网卡的 OEM 命令需求。
如何新增一个协议配置文件?
1. 基础配置结构
network_adapter/src/lualib/hardware_config 下新增 Test.lua 文件
local bs = require 'mc.bitstring'
local log = require 'mc.logging'
local libmgmt_protocol = require 'libmgmt_protocol'
local utils = require 'mc.utils'
local Test_ncsi = {
protocol_dependencies = {
ncsi_standard = {endpoint = nil} -- 运行时注入端点信息
},
properties = {
-- 属性定义区域
}
}
return {
smbus = nil, -- 不使用 SMBUS 协议
mctp = function(endpoint)
local obj = utils.table_copy(Test_ncsi)
obj.protocol_dependencies.ncsi_standard.endpoint = endpoint
return obj
end
}
1.1 协议依赖配置
protocol_dependencies = {
ncsi_standard = {
endpoint = nil -- 由运行时动态注入
}
-- 可添加其他协议依赖
}
2. 属性基本结构
每个属性包含以下关键字段:
PropertyName = {
protocol = 'ncsi_standard', -- 使用的协议名称
action = 'on_demand|on_schedule', -- 执行模式
period_in_sec = 5, -- 定时执行时的间隔(秒)
request = { -- 请求配置
packet_type = 0x00, -- NCSI 数据包类型
expect_rsp_packet_type = 0x80, -- 期望的响应包类型
data = '\x00\x01\x02' -- 可选:附加数据
},
response = function(data) -- 响应解析函数
-- 数据解析逻辑
return parsed_data
end
}
2.1 执行模式说明
按需执行 (on_demand)
action = 'on_demand'
-- 适用于初始化、控制命令等不频繁执行的操作
定时执行 (on_schedule)
action = 'on_schedule'
period_in_sec = 5 -- 执行间隔,根据监控需求调整
-- 适用于状态监控、统计信息收集等需要定期更新的数据
3. 请求配置&响应解析
3.1 标准 NCSI 命令请求
request = {
packet_type = 0x00, -- 命令包类型
expect_rsp_packet_type = 0x80, -- 响应包类型(通常为命令包类型 + 0x80)
-- data 字段可选
}
3.2 厂商 OEM 命令请求
request = {
packet_type = 0x50,
expect_rsp_packet_type = 0xD0,
data = '\x00\x00\x01\x57\x06' -- 厂商特定数据
}
若 data 后仍有 padding 字段,只需填写 data 部分即可,框架会进行自动补全,且将 data 长度将 data 长度计算为 payload length。
4. 响应数据解析
4.1 基础解析模板
response = function(data)
local r = bs.new([[
response_code:16/big,
reason_code:16/big,
field1:8,
field2:16/big,
-- 更多字段...
]]]):unpack(data, true)
return {
FieldName1 = r.field1,
FieldName2 = r.field2,
-- 映射到输出字段
}
end
字节序说明
big: 大端字节序(网络字节序)little: 小端字节序- 默认:大端字节序
响应解析函数bs.new():unpack(data, true)中构造字段的总字节数应与对应命令返回的长度一致,否则会导致 bs.new 解析失败对应属性无法获取数据
4.2 复杂数据解析示例
response = function(data)
local r = bs.new([[
rsp_code:16,
reason_code:16,
manu_id:32,
intel_cmd:8,
mac_addr:1/MAC_ADDRESS,
padding:8
]]], libmgmt_protocol.common_bs_helper):unpack(data, true)
return r.mac_addr.mac_address
end
框架供了通用的bitstring格式和通用的协议响应数据解析函数,用于解析协议返回的响应数据。
- 通用bitstring格式
通用bitstring格式存于include/libmgmt_protocol/common/init.lua, 使用时调用libmgmt_protocol.common_bs_helper
目前支持的格式:
| 名称 | bitstring名称 | 返回格式 |
|---|---|---|
| Mac地址 | MAC_ADDRESS |
{mac_address = '00:11:22:33:44:55'} |
| Ipv4地址 | IPV4 |
{ipv4 = '192.168.1.255'} |
- 通用响应数据解析函数
目前支持的函数:
| 名称 | 介绍 | 入参 | 返回格式 |
|---|---|---|---|
create_array_parser |
用于解析bitstring数组 | (单个bitstring定义字符串, 单个数据长度) | 表数组 |
5. 调试和日志
5.1 response 中添加日志打印
response = function(data) 函数中我们可以添加相关 lua 代码进行数据转换和逻辑处理,当然我们在其中加入 log 打印查看命令响应是否正确、以及 bs 解析是否正常
示例:
log:error("DEBUG>>> default mac address byte length is: %d", #data)
local byteArray = {}
for i = 1, #data do
local byte = data:byte(i)
table.insert(byteArray, byte)
end
log:error("DEBUG>>> default mac address bytes: %s", table.concat(byteArray, " "))
DefaultMacAddrNCSI = {
protocol = 'ncsi_standard',
action = 'on_demand',
request = {
-- 运行时需传入channel_id(也就是port id)
packet_type = 0x50,
expect_rsp_packet_type = 0xD0,
data = '\x00\x00\x01\x57\x06\x00\x00\x00'
},
response = function(data)
log:error("DEBUG>>> default mac address byte length is: %d", #data)
local byteArray = {}
for i = 1, #data do
local byte = data:byte(i)
table.insert(byteArray, byte)
end
log:error("DEBUG>>> default mac address bytes: %s", table.concat(byteArray, " "))
local r = bs.new([[<<
rsp_code:16,
reason_code:16,
manu_id:32,
intel_cmd:8,
mac_addr1:1/MAC_ADDRESS,
mac_addr2:1/MAC_ADDRESS
>>]], libmgmt_protocol.common_bs_helper):unpack(data, true)
log:error("DEBUG>>> default Macaddr1: %s", r.mac_addr1.mac_address)
return r.mac_addr1.mac_address
end
},
建议可在 bs 前将 data 的每个字节通过日志打印,避免 bs 解析失败导致无日志输出。
该方法只能查看响应的数据,无法查看具体下发的命令
5.2 代码注入
1. 新建 test_mctp_capture.lua 放到机器 /tmp 目录下
local c_mctp_engine = require 'mctp_engine'
local mctp_engine = c_mctp_engine.new()
mctp_engine:enable_pcie_capture()
2. 查寻 hardware 端口
netstat -anp | grep 0.0.0.0:400
3. telnet 进端口注入代码
telnet ip 40030
inject :0000000e //test_mctp_capture.lua


