如何使用通用netlink的多部分机制将这个字符串分解成更小的部分,以便在内核端发送和重组?
Netlink 的 Multipart 功能“可能”帮助您传输已经分段的字符串,但它不会帮助您进行实际的字符串分段操作。那是你的工作。 Multipart 是一种通过几个数据包而不是一个大对象来传输几个小的相关对象的方法。一般来说,Netlink 作为一个整体的设计是假设您要发送的任何原子数据都可以放在一个数据包中。我同意 6Kbs 的字符串有点奇怪的观点。
实际上,在我看来,Multipart 是一个定义不明确的噱头。问题是内核实际上并没有以任何通用能力处理它。如果您查看所有NLMSG_DONE usage instances,您会注意到它不仅很少被读取(其中大多数是写入),而且,它不是Netlink 代码,而是一些specific protocol 为一些static 做的(即私人)操作。换句话说,NLMSG_DONE 的语义是由你给出的,而不是内核给出的。如果您选择使用 Linux,它不会为您节省任何工作。
另一方面,libnl-genl-3 似乎确实可以使用 Multipart 标志(NLMSG_DONE 和 NLM_F_MULTI)执行一些自动处理,但这仅适用于您从内核空间发送内容到用户空间的情况,并且最重要的是,甚至图书馆本身也承认it doesn't really work。
另外,NLMSG_DONE 应该是 placed in the "type" Netlink header field,而不是在“标志”字段中。这让我感到莫名其妙,因为通用 Netlink stores the family identifier in type,所以看起来没有办法同时告诉 Netlink 该消息属于您,并且它应该结束一些数据流。除非我遗漏了一些重要的东西,否则 Multipart 和 Generic Netlink 彼此不兼容。
因此,我建议在必要时实施您自己的消息控制,并忘记 Multipart。
通用 netlink 和 libnl nla_put_string 函数支持的最大字符串大小是多少?
这不是一个常数。 nlmsg_alloc()储备
getpagesize() 每个数据包的字节数 by default。您可以使用nlmsg_set_default_size() 调整此默认值,或者更多地使用nlmsg_alloc_size() 覆盖它。
然后您必须查询actual allocated size(因为不能保证它是您要求的)并从那里构建。要获得可用的有效负载,您必须减去要添加的任何属性的 Netlink header 长度、Generic Header 长度和 Attribute Header 长度。还有user header length,如果你有的话。您还必须对齐所有这些组件,因为它们的 sizeof 不一定是它们的实际大小 (example)。
话虽如此,内核仍然会拒绝超过页面大小的数据包,因此即使您指定了自定义大小,您仍然需要对字符串进行分段。
真的,忘记上面所有的。只需将字符串分段为 getpagesize() / 2 之类的东西,然后分块发送。
这是一般的想法:
static void do_request(struct nl_sock *sk, int fam, char const *string)
{
struct nl_msg *msg;
msg = nlmsg_alloc();
genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, fam,
0, 0, DOC_EXMPL_C_ECHO, 1);
nla_put_string(msg, DOC_EXMPL_A_MSG, string);
nl_send_auto(sk, msg);
nlmsg_free(msg);
}
int main(int argc, char **argv)
{
struct nl_sock *sk;
int fam;
sk = nl_socket_alloc();
genl_connect(sk);
fam = genl_ctrl_resolve(sk, FAMILY_NAME);
do_request(sk, fam, "I'm sending a string.");
do_request(sk, fam, "Let's pretend I'm biiiiiig.");
do_request(sk, fam, "Look at me, I'm so big.");
do_request(sk, fam, "But I'm already fragmented, so it's ok.");
nl_close(sk);
nl_socket_free(sk);
return 0;
}
我在my Dropbox 中留下了一个完整的沙盒。请参阅自述文件。 (在内核 5.4.0-37-generic 中测试。)