学习笔记:从ncsi/nc-si协议和代码了解网络协议的设计范式
- 参考文档:
c
https://www.dmtf.org/standards/published_documents
https://www.dmtf.org/dsp/DSP0222
https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.2.0.pdf
- 参考代码
c
https://github.com/torvalds/linux/blob/master/net/ncsi/ncsi-pkt.h
- ncsi/nc-si协议简介:
一般用于服务器主板上的BMC芯片与智能网卡MAC芯片之间的直连控制线通讯。
Ethernet Header中Des Add全1,且 EtherType = 0x88F8时即为NCSI协议数据。
- ncsi协议一般是在BMC与MAC之间互发数据,有三种
c
struct ncsi_cmd_pkt_hdr { // BMC发给MAC的操作命令
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
};
struct ncsi_rsp_pkt_hdr { // MAC执行命令后,返回给BMC的操作结果
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
__be16 code; /* Response code */
__be16 reason; /* Response reason */
};
struct ncsi_aen_pkt_hdr { // MAC主动发给BMC的异步事件,例如拔网线了
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
unsigned char reserved2[3]; /* Reserved */
unsigned char type; /* AEN packet type */
};
- 以上三种的数据头的公用数据头只有一种ncsi_pkt_hdr
通过type来区分后续的数据结构,这也是典型的派生类c语言实现方式
c
struct ncsi_pkt_hdr { //16byte
unsigned char mc_id; /* Management controller ID, BMC id==1 */
unsigned char revision; /* NCSI version - 0x01 */
unsigned char reserved; /* Reserved ==0 */
unsigned char id; /* Packet sequence number,方便BMC区分最多255个命令的MAC反馈结果 */
unsigned char type; /* Packet type */
unsigned char channel; /* Network controller ID,BMC一对多MAC定位用 */
__be16 length; /* Payload length,有效负载数据,不含checksum部分,也不含ncsi_pkt_hdr 部分 */
__be32 reserved1[2]; /* Reserved */
};
- 最基本的没有额外描述信息的cmd、rsp结构
需要注意的是,这种基本cmd有效Payload length 0,rsp Payload length 4。Payload length是相对于基类ncsi_pkt_hdr 而言的附加部分长度,且不含数据检验checksum部分。
rsp的4byte是Response code+Response reason
c
/* NCSI common command packet */
struct ncsi_cmd_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 checksum; /* Checksum */
unsigned char pad[26];
};
struct ncsi_rsp_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
- payload length非0的cmd示例
ncsi_cmd_sp_pkt 的payload length为4,reserved[3]+hw_arbitration
不含checksum,也不含pad填充区
c
/* Select Package */
struct ncsi_cmd_sp_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header 16byte*/
unsigned char reserved[3]; /* Reserved */
unsigned char hw_arbitration; /* HW arbitration */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
static struct ncsi_cmd_handler {
unsigned char type;
int payload;
int (*handler)(struct sk_buff *skb,
struct ncsi_cmd_arg *nca);
} ncsi_cmd_handlers[] = {
{ NCSI_PKT_CMD_SP, 4, ncsi_cmd_handler_sp },
-
ncsi_cmd_sp_pkt 的pad填充区是为了满足最小网络数据包的大小限制
ncsi_cmd_sp_pkt 长度为16+4+4+22,共46,
加上前面的Ethernet Header 14byte,再加最后面的FCS,
刚好凑足64byte
-
ncsi_cmd_handler 的写法是典型的虚函数的c语言实现模式
实际执行时,根据 ncsi_pkt_hdr 的type调用对应的处理函数。
MAC芯片的rsp侧也类似
c
static struct ncsi_rsp_handler {
unsigned char type;
int payload;
int (*handler)(struct ncsi_request *nr);
} ncsi_rsp_handlers[] = {
{ NCSI_PKT_RSP_SP, 4, ncsi_rsp_handler_sp },
- cmd、rsp、aen的type code定义范式
各厂商自定义cmd type也给了一个OEM 0x50,允许不同厂商在padload部分任意定义
c
#define NCSI_PKT_CMD_SP 0x01 /* Select Package */
#define NCSI_PKT_RSP_SP (NCSI_PKT_CMD_SP + 0x80)
#define NCSI_PKT_AEN 0xFF /* AEN Packet*/
以下三种aen子分类code存储在padload部分的type中
#define NCSI_PKT_AEN_LSC 0x00 /* Link status change */
#define NCSI_PKT_AEN_CR 0x01 /* Configuration required */
#define NCSI_PKT_AEN_HNCDSC 0x02 /* HNC driver status change */
#define NCSI_PKT_CMD_OEM 0x50 /* OEM */
-
netlink.h.c部分
我的理解是,提供给用户态程序的netlink接口,允许做一些有限操作或查询。
-
internal.h manager.c部分
我的理解是, h为多模块共用的结构定义、常量定义
c部分是内核管理bmc端数据状态的代码,与mac端保持一致。
-
ncsi的目的和来龙去脉
ncsi的目的:远程集中管理大型机房中不同型号的服务器。
一般是通过redfish(dell基于这个进行修改)web界面远程设置服务器的net MAC特性。
以前这种管理需求是IBM自己的一套管理系统(大概是叫 IPMI),后来延伸到 任意品牌服务器的管理,所以交由dmtf开源组织进行定义(ncsi mctp redfish),实现则由一家codeconstruct.com.au提供。
-
一点总结:
图灵机的7元组中δ是算法,其他都是数据。
更进一步,一切都是围绕数据去构建的。
数据的本质是真实物理世界的模型映射,数字化后,在硅基电路上进行信息处理,再通过各种物理设备反馈于真实世界。
linux的c实现提供各种优秀的范式,核心只有一个,数据。cpp等语言与c图灵等价。cpp能实现的概念,本质上都可以用c等价实现,只是方法不同,或编译期实现。其实,我满能理解linus本人反对cpp的,虽然不是完全赞同。
操作可以理解为对数据的解释,并反作用于数据。
硬件是基于数字电路对数据进行读写、存储、传输、解释执行的支持。