天天看點

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,該函數在沒有接收緩存可利用定時睡眠。

發送之前資料準備:

1、nlmsg_new

函數簡介

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

payload是要發送資料的大小,flags設定為GFP_KERNEL

       函數就不具體分析了,nlmsg_new會新申請一個socket buffer,其大小為socket消息頭大小 + netlink消息頭大小 +使用者消息大小,傳入參數payload即為使用者消息大小。

2、NLMSG_NEW

該宏基本等同于nlmsg_put函數,填充netlink消息頭的部分内容。

3、NLMSG_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;

       }

       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_ATOMIC或GFP_KERNEL,GFP_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一些接口就不多說了

繼續閱讀