在创建/使用netlink
协议时,netlink
属性旨在为协议提供一个干净的自我记录布局,以允许未来的可扩展性。这意味着,如果您想要使用除了当前协议中已经存在的数据类型之外的其他数据类型,那么代码将是兼容的,而不会破坏已经存在的操作。
“属性”是协议相关的,并且与使用所述协议发送的特定消息有关。
以taskstats
接口为例:
taskstat
属性:
enum {
TASKSTATS_CMD_ATTR_UNSPEC = 0,
TASKSTATS_CMD_ATTR_PID,
TASKSTATS_CMD_ATTR_TGID,
TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
__TASKSTATS_CMD_ATTR_MAX,
};
在这些属性中,您可以通过在它们之间添加自定义属性UNSPEC
并将MAX
该属性映射到所需的特定功能或操作来轻松“扩展”它们。
内核空间taskstat
策略:
static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
[TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 },
[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
我相信您已经遇到过 for 的定义,这是使用协议和接口struct nlattr
加载此结构的字段的示例:NETLINK_GENERIC
taskstats
struct nlattr na;
na.nla_type = CTRL_ATTR_FAMILY_NAME; // defined in linux/genetlink.h
na.nla_len = strlen(TASKSTATS_GENL_NAME) + 1 // defined in linux/taskstats.h
// note: you will need to copy/access nlattr data in the same way the NLMSG_DATA
// macro operates.
现在在内核方面,当解析这些属性时,将调用相关的函数并就如何继续进行预期的操作。
我不确定你发布的图表是否让你失望,但是,缩小一点给你一个更大的视角:
根据内核源代码v3.16 include/net/netlink.h
:
/* ========================================================================
* Netlink Messages and Attributes Interface (As Seen On TV)
* ------------------------------------------------------------------------
* Messages Interface
* ------------------------------------------------------------------------
*
* Message Format:
* <--- nlmsg_total_size(payload) --->
* <-- nlmsg_msg_size(payload) ->
* +----------+- - -+-------------+- - -+-------- - -
* | nlmsghdr | Pad | Payload | Pad | nlmsghdr
* +----------+- - -+-------------+- - -+-------- - -
* nlmsg_data(nlh)---^ ^
* nlmsg_next(nlh)-----------------------+
*
* Payload Format:
* <---------------------- nlmsg_len(nlh) --------------------->
* <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) ->
* +----------------------+- - -+--------------------------------+
* | Family Header | Pad | Attributes |
* +----------------------+- - -+--------------------------------+
* nlmsg_attrdata(nlh, hdrlen)---^
在这里您可以看到您发布的标头和有效负载图只是更大有效负载的一部分。该段与struct nlmsghdr
消息格式中的 a 一起出现。
现在在政策上,当发送 netlink 消息时,发送者需要遵守协议格式。消息的接收者将用于struct nla_policy
在访问有效负载之前验证属性。
内核使用“族”或标识符来跟踪要与之通信的适当协议接口,无论是标准协议还是自定义协议,如Generic Netlink。
当您问“我们可以避免这种情况吗?”时,如果您通过编写自己的自定义通用 netlink 协议来扩展 netlink,那么这些协议的存在是为了让该协议可以轻松调整和维护,而无需经历和更改/修复与之相关的所有操作,或者协议崩溃了。您还建议如何解析具有不同数据类型且没有关联长度或类型的嵌套消息?类型和长度允许在正确的对齐上解析消息并允许发生所需的操作。如果没有为有效负载提供标签的属性类型,您将如何解释它,“什么是”有效负载?没有长度你怎么知道“有多大” 有效载荷是?可能有多个长度不同的有效载荷,而没有任何东西可以区分它们的大小,也无法分辨一个从哪里开始,另一个在哪里结束。
这是libnl(一个用于处理 netlink 套接字的库,强烈推荐)文档属性的链接。