使用 Netlink 协议规范¶
本文档是使用 Netlink 协议规范的快速入门指南。 有关规范的更详细描述,请参见 Netlink 协议规范 (YAML 格式)。
简单 CLI¶
内核自带一个简单的 CLI 工具,在开发 Netlink 相关代码时应该很有用。 该工具用 Python 实现,可以使用 YAML 规范向内核发出 Netlink 请求。 仅支持通用 Netlink。
该工具位于 tools/net/ynl/pyynl/cli.py
。 它接受一些参数,其中最重要的参数是
--spec
- 指向规范文件
--do $name
/--dump $name
- 发出请求$name
--json $attrs
- 为请求提供属性
--subscribe $group
- 接收来自$group
的通知
YAML 规范可以在 Documentation/netlink/specs/
下找到。
使用示例
$ ./tools/net/ynl/pyynl/cli.py --spec Documentation/netlink/specs/ethtool.yaml \
--do rings-get \
--json '{"header":{"dev-index": 18}}'
{'header': {'dev-index': 18, 'dev-name': 'eni1np1'},
'rx': 0,
'rx-jumbo': 0,
'rx-jumbo-max': 4096,
'rx-max': 4096,
'rx-mini': 0,
'rx-mini-max': 4096,
'tx': 0,
'tx-max': 4096,
'tx-push': 0}
输入参数被解析为 JSON,而输出仅是 Python 格式化的。 这是因为某些 Netlink 类型不能直接表示为 JSON。 如果输入中需要这些属性,则需要对脚本进行一些 hacking。
规范和 Netlink 内部结构被分解为一个独立的库 - 重用 cli.py
中的代码应该很容易编写 Python 工具/测试。
生成内核代码¶
tools/net/ynl/ynl-regen.sh
扫描内核树以查找需要更新的自动生成的文件。 使用此工具是生成/更新自动生成代码的最简单方法。
默认情况下,只有在规范比源文件更新时才会重新生成代码,要强制重新生成,请使用 -f
。
ynl-regen.sh
在文件中搜索 YNL-GEN
(请注意,它只扫描 git 索引中的文件,即仅扫描 git 跟踪的文件!)。 例如,fou_nl.c
内核源文件包含
/* Documentation/netlink/specs/fou.yaml */
/* YNL-GEN kernel source */
ynl-regen.sh
将找到此标记并使用基于 fou.yaml 的内核源文件替换该文件。
基于规范生成新文件的最简单方法是将上面两个标记行添加到文件中,将该文件添加到 git,然后运行重新生成工具。 在树中 Grep YNL-GEN
以查看其他示例。
代码生成本身由 tools/net/ynl/pyynl/ynl_gen_c.py
执行,但它需要一些参数,因此直接为每个文件调用它很快就会变得乏味。
YNL lib¶
tools/net/ynl/lib/
包含一个 C 库(基于 libmnl)的实现,该库与 tools/net/ynl/pyynl/ynl_gen_c.py
生成的代码集成,以创建易于使用的 netlink 封装器。
YNL 基础知识¶
YNL 库由两部分组成 - 通用代码(函数以 ynl_
为前缀)和每个系列的自动生成代码(以系列名称为前缀)。
要创建 YNL 套接字,请调用 ynl_sock_create() 并传递系列结构(系列结构由自动生成的代码导出)。 ynl_sock_destroy() 关闭套接字。
YNL 请求¶
发出 YNL 请求的步骤最好用一个示例来解释。 此示例中的所有函数和类型都来自自动生成的代码(在本例中是 netdev 系列)
// 0. Request and response pointers
struct netdev_dev_get_req *req;
struct netdev_dev_get_rsp *d;
// 1. Allocate a request
req = netdev_dev_get_req_alloc();
// 2. Set request parameters (as needed)
netdev_dev_get_req_set_ifindex(req, ifindex);
// 3. Issues the request
d = netdev_dev_get(ys, req);
// 4. Free the request arguments
netdev_dev_get_req_free(req);
// 5. Error check (the return value from step 3)
if (!d) {
// 6. Print the YNL-generated error
fprintf(stderr, "YNL: %s\n", ys->err.msg);
return -1;
}
// ... do stuff with the response @d
// 7. Free response
netdev_dev_get_rsp_free(d);
YNL 转储¶
执行转储的模式与请求类似。 转储返回一个对象列表,该列表由特殊标记终止,或者在出错时返回 NULL。 使用 ynl_dump_foreach()
迭代结果。
YNL 通知¶
YNL lib 支持使用同一个套接字进行通知和请求。 如果在处理请求期间收到通知,它们将在内部排队,并可以在稍后检索。
要订阅通知,请使用 ynl_subscribe()
。 必须从套接字中读取通知,ynl_socket_get_fd()
返回底层套接字 fd,该 fd 可以插入到适当的异步 IO API(如 poll
或 select
)中。
可以使用 ynl_ntf_dequeue()
检索通知,并且必须使用 ynl_ntf_free()
释放通知。 由于我们事先不知道通知类型,因此通知作为 struct ynl_ntf_base_type *
返回,并且用户应该基于 cmd
成员将其转换为适当的完整类型。