3. Netlink 套接字
为了使用 netlink 协议,我们首先需要一个 netlink 套接字[^1]。每个套接字都定义了一 个独立的消息发送和接收的上下文环境。一个应用程序可以使用多个套接字,比如一个套接 字用于发送请求消息和接受应答消息另一个套接字用来订阅某个多播组以便接收通知消息。
3.1. 套接字结构体(struct nl_sock)
netlink 套接字以及和他相关的包括实际的文件描述符在内的所有属性都使用 nl_sock 结构体表示的。
1 |
|
应用程序必须为它想要使用的每一个 netlink 套接字分配一个 struct nl_sock
结构体
实例。
3.2. 序列号
libnl 库会自动为应用程序管理序列号。在套接字结构体内部存储了一个序列号计数器,如 果你发送了一个期望得到回复的请求消息,而且这个回复是诸如错误消息或者是其他任何需 要用到相关的原始消息的消息,那么这个计数器会自动递增。
此外,这个计数器也可以直接通过 nl_socket_use_seq()
函数使用。这个函数会返回计
数器当前的值然后自增一。
1 |
|
当然大部分的应用程序都不会想要自己处理序列号,是调用 nl_send_auto()
函数的时候
,序列号会自动填充并在收到回复信息的时候再次匹配。更多信息请参考 消息/数据的发
送和接收 一节
如果 netlink 协议的实现不需要使用请求/应答模式,比如当一个套接字是用来接收通知消 息的时候,序列号的这种行为可以也必须取消掉.
1 |
|
关于 nelink 序列号背后的的更多理论知识,请参考 序列号 一节。
3.3. 多播组的订阅
每一个套接字都可以订阅它连接的 netlink 协议的任意数量的多播组,之后这个套接字将 会接收到发送到其中任何一组的任何一条消息的拷贝。多播组一般是用来实现事件通知。
在 2.6.14 版本之前的内核中组的订阅是通过一个位掩码(bitmask)来实现的,这就限制
了每个协议簇最多能够使用 32 个组。虽然在新的代码中不建议再使用这个过时的接口,你
还是可以通过 nl_join_groups()
来访问它。
1 |
|
2.6.14 内核引入了新的实现方式,这使得你可以订阅几乎是无限数量的多播组。
1 |
|
3.3.1 多播示例
1 |
|
此外还有一个直接修改套接字回调配置的快捷函数:
1 |
|
示例
1 |
|
3.5. 套接字属性
本地端口号
本地端口唯一的标识了一个套接字的同时也被用来在寻址的时候锁定该套接字。一个本地端 口号是在分配套接字的时候自动生成的。它由进程ID(22位)和一个随机数(10位)组合而 成,所以每个进程可以使用1024个套接字。
1 |
|
关于端口号的更多的信息,请查看 寻址 一节。
注意: 你可以重新设置端口,但是你必须要保证你提供的值是唯一的,此外你还需要 保证没有其他的应用程序的套接字使用了这个值。
对等端口
一个套接字可以设置一个对等端口,这将会导致所有通过这个套接字发送的单播消息都会发 送到这个对等节点。如果没有设置对等节点,消息会被发送到内核,而内核会自动尝试把这 个套接字和内核里面同一个 netlink 协议簇下的套接字绑定在一起。人们通常不会把套接 字绑定到一个对等端口,因为通常一个在同一个 netlink 协议簇中只存在一个内核端套接 字。
1 |
|
关于端口号的更多的信息,请查看 寻址 一节。
文件描述符
Netlink 使用的是 BSD 套接字的接口,所以在每个套接字背后都有一个你可以直接使用的 文件描述符。
1 |
|
如果一个套接字只是用来接收通知消息的,那么最好把它设置成非阻塞模式,然后周期性的 轮询新的通知消息。
1 |
|
发送和接收缓存区大小
套接字的缓冲区被用来在发送方和接收方之间充当 netlink 消息队列。这个缓冲区的大小 决定了你可以调用 write() 函数向 netlink 套接字写入的最大长度,也就是说它间接的定 义了最大消息的长度。这个缓冲区的默认大小是 32KiB。
1 |
|
Enable/Disable Credentials
TODO [^2]
1 |
|
启用/禁用 Auto-ACK 模式
下面的这些函数可以用来在一个套接字中启用或是禁用 Auto-Ack
模式。关于这个模式的
含义的详细信息请参考 Auto-Ack 模式 一节。Auto-Ack
模式是默认
开启的。
1 |
|
启用/禁用消息窥视
如果启用了消息窥视功能,nl_rcv()
函数将会尝试使用 MSG_PEEK
来读取收到的下一
个消息的大小,并分配一个同样大小的缓存区。消息窥视功能是默认启用的但你可以使用下
面的函数禁用它:
1 |
|
启用/禁用数据包信息的接收
如果这项功能启用了的话,从内核中收到的每一条 netlink 消息都会在控制消息中额外包
含一个 struct nl_pkinfo
结构体。下面这些函数可以用来启用或禁用数据包信息的接收
。
1 |
|
注意: NETLINK_PKINFO
的处理目前还没有实现。
[^1]: 这篇文章中的套接字基本上都是指 libnl
库中的套接字结构体 struct nl_sock
而不是BSD 套接字接口中的套接字概念。
[^2]: 在原文中这一段没有任何内容只有标题和下面的函数,所以很难判断这个函数的作用,个人也没有相关的知识背景所以没有翻译标题。「译者注」