首页 > 技术文章 > netlink机制

Huluwa-Vs-Aoteman 2013-12-29 17:21 原文

一、netlink机制简介

  netlink是一种基于网络的机制,允许在内核内部以及内核与用户之间进行通信。正式定义见RFC3549。手册见netlink(3)和netlink(7)。netlink(3)描述了内核中用于操作、访问、创建netlink数据报的宏。netlink(7)包含了netlink套接字的一般性信息,并给出了这里使用的数据结构的文档。

  该机制不仅仅用于网络通信,更重要的用户是通用对象类型

  netlink机制比procfs或sysfs中文件想必有下列优势:

    1. 任何一方都不需要轮询,如果使用文件传递状态消息,那么用户层需要不断的检查是否有新消息到达。

    2. 系统调用和ioctl也能够从用户态向内核传递信息,但比简单的netlink连接更难与实现

    3. 内核可以直接向用户层发送消息,无需用户层事先请求。使用文件也可以做到,但系统调用和ioctl是不可能的。

    4. 除了简单的套接字,用户空间应用程序不需要使用其他东西来与内核交互。

二、数据结构

  指定地址

  类似于其他网络协议,每个netlink套接字都需要分配一个地址。struct sockaddr:

  

<netlink.h>

struct sockaddr_nl { sa_family_t nl_family; /* AF_NETLINK *//*区分内核不同部分使用各个不同的netlink通道*/ unsigned short nl_pad; /* 0 *//**/ __u32 nl_pid; /* 端口ID *//*nl_pid此类套接字唯一标示符,对内核自身来讲,该字段始终是0,用户应用程序通常使用其线程组ID,不强求,可以是任何唯一值*/ __u32 nl_groups; /* 多播组掩码 *//*nl_groups是一个位图,属于该套接字所属的多播地址,如果不允许多播,该字段为0*/ };

 

  消息格式

每个消息由两部分组成:首部和净荷。首部表示为struct nlmsghdr,而净荷可以是任意的。netlink消息的各部分,对齐到NLMSG_ALIGNTO(通常是4)字节边界。查询netlink(3)正确计算边界。一个消息的长度不应该超过一页,这样对内存分配的压力较小。

1 <netlink.h>
2 struct nlmsghdr
3 {
4      __u32 nlmsg_len;     /*消息长度,包含首部在内*/
5      __u32 nlmsg_type;    /*消息内容的类型*/
6      __u32 nlmsg_flags;   /*附加的标志*/
7      __u32 nlmsg_seq;     /*序列号*/
8      __u32 nlmsg_pid;     /*发送进程的端口ID*/
9 };

  各种标志可以保存在nlmsg_flags,所有可能的值都在netlink.h中。主要关注两个标志:如果消息包含一个请求,要求执行某个特定的操作(而不是传输一些状态信息),那么NLM_F_REQUEST将置位,而NLM_F_ACK要求在接收到上述消息并成功处理请求后发送一个确认消息。

  nlmsg_seq包含一个序列号,表示一系列消息之间在时间上的前后关系。

 二、编程接口

  netlink套接字既可以从内核打开,也可以从用户层打开。前一种使用了netlink_kernel_create,在后一种情况下,将通过标准的网络编程接口出发netlink_ops的bind方法。

1 net/netlink/af_netlink.c
2 struct sock *
3 netlink_kernel_create(struct net *net, int unit, unsigned int groups, 
void (*input)(struct sk_buff *skb),
struct mutex *cb_mutex, struct module *module);

net表示网络命名空间,unit制定所属协议族成员,而input是一个回调函数,在数据到达该套接字将调用input。如果对input指定了NULL指针,那么套接字将只能从内核向用户层传输数据,发过来就不行了。

 1 kernel/audit.c
 2 
 3 static void audit_receive_skb(struct sk_buff *skb)
 4 {
 5      int err;
 6      u32 rlen;
 7      struct nlmsghdr *nlh;
 8 
 9      while(skb->len >= NLMSG_SPACE(0))
10      {
11            nlh = nlmsg_hdr(skb);
12            ……
13            rlen = NLMSG_ALIGN(nlh->nlmsg_len);
14            ……
15            if((err = audit_receive_msg(skb, nlh)))
16            {
17                   netlink_ack(skb, nlh, err);
18             }
19             else if (nlh->nlmsg_flags & NLM_F_ACK)
20                    netlink_ack(skb, nlh, 0);
21             skb_pull(skb, rlen);
22       }
24 }

 

 

推荐阅读