Linux 用户态与内核态的交互netlink

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

这是一篇学习笔记,主要是对《Linux 系统内核空间与用户空间通信的实现与分析》中的源码imp2的分析。其中的源码,可以到以下URL下载:

/developerworks/cn/linux/l-netlink/imp2.tar.gz

参考文档

《Linux 系统内核空间与用户空间通信的实现与分析》陈鑫

/developerworks/cn/linux/l-netlink/?ca=dwcn-newsletter-linux

《在 Linux 下用户空间与内核空间数据交换的方式》杨燚

/developerworks/cn/linux/l-kerns-usrs/

理论篇

在 Linux 2.4 版以后版本的内核中,几乎全部的中断过程与用户态进程的通信都是使用netlink 套接字实现的,例如iprote2网络管理工具,它与内核的交互就全部使用了netlink,著名的内核包过滤框架Netfilter在与用户空间的通读,也在最新版本中改变为netlink,无疑,它将是Linux用户态与内核态交流的主要方法之一。它的通信依据是一个对应于进程的标识,一般定为该进程的 ID。当通信的一端处于中断过程时,该标识为 0。当使用 netlink 套接字进行通信,通信的双方都是用户态进程,则使用方法类似于消息队列。但通信双方有一端是中断过程,使用方法则不同。netlink 套接字的最大特点是对中断过程的支持,它在内核空间接收用户空间数据时不再需要用户自行启动一个内核线程,而是通过另一个软中断调用用户事先指定的接收函数。工作原理如图:

如图所示,这里使用了软中断而不是内核线程来接收数据,这样就可以保证数据接收的实时性。

当 netlink 套接字用于内核空间与用户空间的通信时,在用户空间的创建方法和一般套接字使用类似,但内核空间的创建方法则不同,下图是 netlink 套接字实现此类通信时创建的过程:

用户空间

用户态应用使用标准的socket与内核通讯,标准的socket API 的函数, socket(), bind(), sendmsg(), recvmsg() 和 close()很容易地应用到 netlink socket。

为了创建一个 netlink socket,用户需要使用如下参数调用 socket():

1.socket(AF_NETLINK, SOCK_RAW, netlink_type)

复制代码

netlink对应的协议簇是 AF_NETLINK,第二个参数必须是SOCK_RAW或SOCK_DGRAM,第三个参数指定netlink协议类型,它可以是一个自定义的类型,也可以使用内核预定义的类型:

1.#define NETLINK_ROUTE 0 /* Routing/device hook */

2.#define NETLINK_W1 1 /* 1-wire subsystem */

3.#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */

4.#define NETLINK_FIREWALL 3 /* Firewalling hook */

5.#define NETLINK_INET_DIAG 4 /* INET socket monitoring */

6.#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */

7.#define NETLINK_XFRM 6 /* ipsec */

8.#define NETLINK_SELINUX 7 /* SELinux event notifications */

9.#define NETLINK_ISCSI 8 /* Open-iSCSI */

10.#define NETLINK_AUDIT 9 /* auditing */

11.#define NETLINK_FIB_LOOKUP 10

12.#define NETLINK_CONNECTOR 11

13.#define NETLINK_NETFILTER 12 /* netfilter subsystem */

14.#define NETLINK_IP6_FW 13

15.#define NETLINK_DNRTMSG 14 /* DECnet routing messages */

16.#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */

复制代码

#define NETLINK_GENERIC 16

同样地,socket函数返回的套接字,可以交给bing等函数调用:

1.static int skfd;

2.skfd = socket(PF_NETLINK, SOCK_RAW, NL_IMP2);

3.if(skfd < 0)

4.{

5.printf("can not create a netlink socket\n");

6.exit(0);

7.}

复制代码

bind函数需要绑定协议地址,netlink的socket地址使用struct sockaddr_nl结构描述:

1.struct sockaddr_nl

2.{

3.sa_family_t nl_family;

4.unsigned short nl_pad;

5.__u32 nl_pid;

6.__u32 nl_groups;

7.};

复制代码

成员 nl_family为协议簇 AF_NETLINK,成员 nl_pad 当前没有使用,因此要总是设置为0,成员 nl_pid 为接收或发送消息的进程的 ID,如果希望内核处理消息或多播消息,就把该字段设置为 0,否则设置为处理消息的进程 ID。成员 nl_groups 用于指定多播组,bind 函数用于把调用进程加入到该字段指定的多播组,如果设置为 0,表示调用者不加入任何多播组:

1.struct sockaddr_nl local;

2.

3.memset(&local, 0, sizeof(local));

4.local.nl_family = AF_NETLINK;

5.local.nl_pid = getpid(); /*设置pid为自己的pid值*/

6.local.nl_groups = 0;

7./*绑定套接字*/

8.if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)

9.{

10.printf("bind() error\n");

11.return -1;

12.}

复制代码

用户空间可以调用send函数簇向内核发送消息,如sendto、sendmsg等,同样地,也可以使用struct sockaddr_nl来描述一个对端地址,以待send函数来调用,与本地地址稍不同的是,因为对端为内核,所以nl_pid成员需要设置为0:

1.struct sockaddr_nl kpeer;

2.memset(&kpeer, 0, sizeof(kpeer));

相关文档
最新文档