Netlink 和 libnl 基础
本文介绍了netlink和libnl。
Netlink简介
Netlink is used to transfer information between kernel and user-space processes. It consists of a standard sockets-based interface for user space processes and an internal kernel API for kernel modules.
Netlink是基于socket的用户空间进程和内核态进程通信的方式。 用途有两个,
- 内核为用户态程序提供了很多接口(如route, firewall, ipsec等),直接在用户空间连接相应的socket,就可以获得广播信息。
- 自己编写内核模块,需要和用户空间通信,比/proc,设备驱动方式更加灵活。
这里不得不插一句,socket真是个牛逼的工具:
- 网络间通信(网络上的两个进程)用: Network socket
- 同一主机内进程间通信(用户态): Unix domain socket
- 用户态进程和内核态进程通信: Netlink socket
创建一个Netlink socket的方式如下
netlink_socket = socket(AF_NETLINK, socket_type, netlink_family);
实际上domain和socket_type都是固定的,其中socket_type可以是SOCK_DGRAM,但是不予区分。所以创建一个netlink socket的接口基本如下
netlink_socket = socket(AF_NETLINK, SOCK_RAW, netlink_family);
变化的只是netlink_family,socket的第三个参数protocol,为了说明netlink_family的作用,先看看通常的UDP/TCP socket的创建方式
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
通过here 发现UDP是SOCK_DGRAM类型的默认协议,TCP是SOCK_STREAM类型的默认协议,所以也可以写成
udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
那么netlink_family的作用是什么?
netlink_family selects the kernel module or netlink group to communicate with. –netlink manual
The protocol specifies a particular protocol to be used with the socket. Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0. However, it is possible that many protocols may exist, in which case a particular protocol must be specified in this manner. The protocol number to use is specific to the “communication domain” in which communication is to take place; – socket manual
socket手册对protocol的解释是,如果socket_type不能唯一标识通信协议,就要用protocol来指定明确的通信“协议”(封装标准)。
所以这个protocol就是指定通信标准,常用的网络编程主要是TCP/UDP socket,该参数设置为0,用默认的协议,导致了在netlink socket上的疑虑。 netlink_family 列表见man7.org
实例1
这里有一个Netlink实例
在内核中PF_NETLINK和AF_NETLINK是一个东西,证据在此
- network socket 用<saddr,sport,daddr,dport>四元组来标识一个通信链接(链路,两个进程)。
- unix domain socket 用 pid来标识两个进程。 -netlink socket 用pid来标识两个进程 ?
nl_pid is the unicast address of netlink socket. It’s always 0 if the destination is in the kernel. For a user-space process, nl_pid is usually the PID of the process owning the destination socket. However, nl_pid identifies a netlink socket, not a process.
nl_pid在用户空间能标识一个进程,在内核空间通过netlink_kernel_create
创建socket并注册消息处理函数(每次收到数据后调用)。
用户态进程发送的数据怎么交付给内核态进程? 应该是nl_family
?细节尚未搞懂。
libnl简介
The libnl suite is a collection of libraries providing APIs to netlink protocol based Linux kernel interfaces.
libnl 库封装了netlink socket 底层操作,提供了一系列高级API,简化了netlink编程。 libnl 包含四个主要的lib
- libnl
- libnl-genl
- libnl-route
- libnl-nf
如下图所示
从图中可以清楚的看出,原来需要直接操作socket接口的工作,现在可以用libnl来间接完成。
实例2
stackoverflow上同样有一个类似【实例1】的程序,区别在于其用libnl实现,libnl example
参考
- http://man7.org/linux/man-pages/man7/netlink.7.html
- http://www.infradead.org/~tgr/libnl/
下一步
根据内核提供的taskstats接口,分析用libnl实现的taskstats监控程序,理解netlink在内核的工作原理。
- https://github.com/mechanicalpulse/taskstats
- https://www.kernel.org/doc/Documentation/accounting/taskstats.txt
留下评论