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一些接口就不多說了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章