转载请标明出处:http://www.jianshu.com/users/183339cdc7ae/latest_articles
概述
先来看一下wikipedia上如何解释什么是netlink的
Netlink socket family is a Linux kernel interface used for inter-process communication (IPC) between the kernel and userspace processes, as well as between user processes, in a way similar to the Unix domain sockets.
Like Unix domain sockets (and unlike INET sockets), Netlink communication cannot traverse host boundaries. However, while Unix domain sockets use the filesystem namespace, Netlink processes are addressed by process identifiers (PIDs).
很明显我们可以知道:
- netlink也是用于IPC通信的。可以用于kernel和userspace[ 主要作用 ] ,也可以用于userspace中的processes通信[ userspace间通信笔者并没有研究过,请忽略 ]
- netlink不是基于文件系统来通信的,这是和socket的区别. 也就是说当你使用netlink通信的时候,不会产生一个文件用于通信, 但socket会
- netlink是基于PID来通信的。这里是说,kernerl是通过pid来找到要将信息发送到哪里
协议族
netlink是一个协议族,也就是一堆协议的集合,如内核事件向用户态通知使用NETLINK_KOBJECT_UEVENT协议,IPv6 防火墙使用NETLINK_IP6_FW协议。其中包括:
- define NETLINK_ROUTE 0 /* Routing/device hook */
- define NETLINK_FIREWALL 3 /* Firewalling hook */
- define NETLINK_IP6_FW 13
- define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ 【本文章主要讲解该协议】
define MAX_LINKS 32等,最大32个协议。 更多协议可以在源码中external/libnl/include/linux/netlink.h中查看支持哪些协议。
工作模型
wikipedia中还有这么一段话
Netlink provides a standard socket-based interface for userspace processes
也就是说,在userspace中,直接调用socket这个接口就可以使用netlink
客服端:创建socket—绑定pid—recvmsg
服务端(kernel):netlink_kernel_create(创建)-netlink_broadcast_filtered(通知)
注: 服务端的代码一般都会封装在模块中。如NETLINK_KOBJECT_UEVENT协议会封装在一个kobject_uevent.c模块里。
该文件有2个方法kobject_uevent_init(封装netlink_kernel_create)和kobject_uevent(封装netlink_broadcast_filtered)。因为在模块加载的时候已经调用了kobject_uevent_init,所以只要我们的驱动程序直接调用kobject_uevent就可以发送通知到userspace中
代码框架
client
这里还是以NETLINK_KOBJECT_UEVENT协议为例 客服端:sa.nl_pid = getpid(); 需要注意的是
int main(){
...
structsockaddr_nl sa;
sa.nl_family=AF_NETLINK;
sa.nl_groups=NETLINK_KOBJECT_UEVENT;
sa.nl_pid = getpid();
...
intsockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);
...
bind(sockfd,(structsockaddr *)&sa,sizeof(sa)
...
len=recvmsg(sockfd,&msg,0);
}
server
由于是NETLINK_KOBJECT_UEVENT协议,sd卡驱动会监听热插拔,从而调用kobject_uevent直接通知userspace所以这里不写出server代码
Demo
github下载
使用:
- gcc -c netlink_clinet.c -o netlink_clinet
- 运行:./netlink_clinet
这个时候,已经开始监听uevent事件,只要插入usb或者拔出usb就会打出如下信息
received 274 bytes
add@/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1
SUBSYSTEM=usb
MAJOR=189
MINOR=2
DEVNAME=bus/usb/001/003
DEVTYPE=usb_device
PRODUCT=5c6/903a/310
TYPE=0/0/0
BUSNUM=001
DEVNUM=003
SEQNUM=2305