Linux用户空间和内核空间通信方法:系统调用、procfs、ioctl接口、netlink
netlink 是 Linux 用户态与内核态通信最常用的一种方式。
netlink:netlink socekt是一种用于在内核态和用户态进程之间进行数据传输的特殊的IPC。它通过为内核模块提供一组特殊的API,并为用户程序提供了一组标准的socket 接口的方式,实现了一种全双工的通讯连接。类似于TCP/IP中使用AF_INET地址族一样,netlink socket使用地址族AF_NETLINK。
为新的特性添加一个新的系统调用,ioctls或者一个proc文件的做法并不是很容易的一件事情,因为我们要冒着污染内核代码并且可能破坏系统稳定性的风险去完成这件事情。netlink socket却是如此的简单,你只需要在文件netlink.h中添加一个常量来标识你的协议类型,然后,内核模块和用户程序就可以立刻使用socket风格的API进行通讯了!
Netlink提供了一种异步通讯方式,系统调用和ioctl是同步的。因此,当我们使用一个系统调用来从用户态传递消息到内核时,如果处理这个消息的时间很长的话,内核调度的粒度就会受到影响。
Netlink优于系统调用,ioctls和proc文件系统的另外一个特点就是它支持多点传送。一个进程可以把消息传输给一个netlink组地址,然后任意多个进程都可以监听那个组地址(并且接收消息)。这种机制为内核到用户态的事件分发提供了一种近乎完美的解决方案。
系统调用和ioctl都属于单工方式的IPC,也就是说,这种IPC会话的发起者只能是用户态程序。Netlink 通过允许内核初始化会话的方式完美的解决了此问题,我们称之为netlink socket的双工特性。
使用 netlink 的内核部分能采用模块的方式实现,使用 netlink 的应用部分和内核部分没有编译时依赖,但系统调用就有依赖,而且新的系统调用的实现必须静态地连接到内核中,他无法在模块中实现,使用新系统调用的应用在编译时需要依赖内核。
在内核空间使用专用的内核API接口,在内核端可用于进程上下文与中断上下文。用户空间可使用标准的BSD socket接口。易用。
不仅可以实现内核-用户空间通信还可以用于两个用户进程的通信,但是很少用。用户空间通信有很多方式。
我需要一种可以在内核态主动发起消息的通知方式,而用户态的程序最好可以采用一种“阻塞调用”的方式等待消息。这样的模型可以最大限度的节省CPU的调度,同时可以满足及时处理的要求,最终选择了netlink完成通信的过程。
因为netlink是一个面向数据报的服务。类似于UDP。
Netlink的通信模型和socket通信非常相似,主要要点如下:
- netlink采用自己独立的地址编码,struct sockaddr_nl;
- 每个通过netlink发出的消息都必须附带一个netlink自己的消息头,struct nlmsghdr;
- 用户态的netlink操作完成采用标准socket函数,非常方便和简单,有TCP/UDP socket编程基础的非常容易上手。内核态有专门的的API来使用netlink。