netlink使用

首先分享下网上关于netlink的几篇好的文章

http://blog.csdn.net/leonan/article/details/8712157?utm_source=tuicool&utm_medium=referral

http://blog.csdn.net/haomcu/article/details/7371835

自己总结的也只是对代码的一些理解,也并未深入原理。

1、关键函数简介

内核态

netlink_kernel_create

函数简介

在内核中使用 uevent事件通知用户空间。uevent首先在内核中调用 netlink_kernel_create()函数创建一个socket套接字,该函数原型在netlink.h有定义,其类型是表示往用户空间发送消息的

 

struct sock *netlink_kernel_create(structnet *net, int unit, unsigned intgroups,

                    void (*input)(struct sk_buff *skb),

                    struct mutex *cb_mutex, struct module *module)

 

struct net是一个网络名字空间namespace,在不同的名字空间里面可以有自己的转发信息库,有自己的一套net_device等等。默认情况下都是使用init_net这个全局变量

参数unit表示netlink协议类型,系统定义了16个,可以在net/netlink.h中找到。

参数input则为内核模块定义的netlink消息处理函数,当有消息到达这个netlink socket时,该input函数指针就会被引用。函数指针input的参数skb实际上就是函数netlink_kernel_create返回的 struct sock指针,sock实际是socket的一个内核表示数据结构,用户态应用创建的socket在内核中也会有一个struct sock结构来表示。

函数input()会在发送进程执行sendmsg()时被调用,这样处理消息比较及时,但是,如果消息特别长时,这样处理将增加系统调用sendmsg()的执行时间,也就是说当用户的程序调用sendmsg ()函数时,如果input()函数处理时间过长,也就是说input()函数不执行不完,用户程序调用的sendmsg()函数就不会返回。只有当内核空间中的input()函数返回时,用户调用的sendmsg()函数才会返回。对于这种情况,可以定义一个内核线程专门负责消息接收,而函数input的工作只是唤醒该内核线程,这样sendmsg将很快返回。(这里网上的的说明)不过在查看Linux2.6.37版本的内核时并没有发现这种处理过程,一般都是按下面的方法进行处理。

nlsk = netlink_kernel_create(net, NETLINK_XFRM, XFRMNLGRP_MAX,
                                 xfrm_netlink_rcv, NULL, THIS_MODULE);
 

static void xfrm_netlink_rcv(struct sk_buff *skb)
{
       mutex_lock(&xfrm_cfg_mutex);
       netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
       mutex_unlock(&xfrm_cfg_mutex);
}
netlink_rcv_skb()函数中进行接收处理。

 

netlink_unicast

函数简介

 

int netlink_unicast(struct sock *ssk, struct sk_buff *skb,

                 u32 pid, int nonblock)

模块调用函数 netlink_unicast来发送单播消息

参数ssk为函数 netlink_kernel_create()返回的socket,参数skb存放消息,它的data字段指向要发送的netlink消息结构,而 skb的控制块保存了消息的地址信息,前面的宏NETLINK_CB(skb)就用于方便设置该控制块,参数pid为接收消息进程的pid,参数nonblock表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回,而如果为0,该函数在没有接收缓存可利用定时睡眠。

 

发送之前数据准备:

1nlmsg_new

函数简介

static inline struct sk_buff *nlmsg_new(size_tpayload,gfp_t flags)

 

payload是要发送数据的大小,flags设定为GFP_KERNEL

       函数就不具体分析了,nlmsg_new会新申请一个socket buffer,其大小为socket消息头大小 + netlink消息头大小 +用户消息大小,传入参数payload即为用户消息大小。

 

2NLMSG_NEW

该宏基本等同于nlmsg_put函数,填充netlink消息头的部分内容。

 

3NLMSG_DATA

该宏获取存放数据的指针

 

代码示例:

pSkb = nlmsg_new(iByteSize,ETNO_WAIT);//GFP_KERNEL = 0

       if (NULL ==pSkb){

              STAT_INC(SEND_GET_SKBUFF_FAILED);       

       PrintfLog(LOG_ERROR, FID_ETRAINF_KERN,"NULL == pSkb\r\n");

              returnETERROR;

       }

/*NLMSG_NEW该宏基本等同于nlmsg_put函数,填充netlink消息头的部分内容*/

       pNlMsgHdr =NLMSG_NEW(pSkb, 0, 0, eType, iByteSize, 0);

       pData =NLMSG_DATA(pNlMsgHdr);

       memcpy(pData,pBuf, iByteSize);/*填充用户区数据*/

 

netlink_broadcast

函数简介

 

int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32pid,

                    u32 group,gfp_t allocation)

       前面的三个参数与 netlink_unicast相同,参数group为接收消息的多播组,该参数的每一个位代表一个多播组,因此如果发送给多个多播组,就把该参数设置为多个多播组组ID的位或。参数allocation为内核内存分配类型,一般地为GFP_ATOMICGFP_KERNELGFP_ATOMIC用于原子的上下文(即不可以睡眠),而GFP_KERNEL用于非原子上下文。

NETLINK_CB(skb).pid = 0;

NETLINK_CB(skb).dst_pid = 0;

NETLINK_CB(skb).dst_group = 1;

   字段pid表示消息发送者进程 ID,也即源地址,对于内核,它为 0 dst_pid表示消息接收者进程 ID,也即目标地址,如果目标为组或内核,它设置为 0,否则 dst_group 表示目标组地址,如果它目标为某一进程或内核,dst_group应当设置为 0


用户态使用的函数就是标准的socked一些接口就不多说了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值