Netlink 是一種特別的 socket,他是 Linux 所特有的,類似于 BSD 中的AF_ROUTE 但又遠比他的功能強大,目前在最新的 Linux 內(nèi)核(2.6.14)中使用netlink 進行應(yīng)用和內(nèi)核通信的應(yīng)用非常多,包括:路由 daemon(NETLINK_ROUTE),1-wire 子系統(tǒng)(NETLINK_W1),用戶態(tài) socket 協(xié)議(NETLINK_USERSOCK),防火墻(NETLINK_FIREWALL),socket 監(jiān)視(NETLINK_INET_DIAG),netfilter 日志(NETLINK_NFLOG),ipsec 安全策略(NETLINK_XFRM),SELinux 事件通知(NETLINK_SELINUX),iSCSI 子系統(tǒng)(NETLINK_ISCSI),進程審計(NETLINK_AUDIT),轉(zhuǎn)發(fā)信息表查詢(NETLINK_FIB_LOOKUP),netlink connector(NETLINK_CONNECTOR),netfilter 子系統(tǒng)(NETLINK_NETFILTER),IPv6 防火墻(NETLINK_IP6_FW),DECnet 路由信息(NETLINK_DNRTMSG),內(nèi)核事件向用戶態(tài)通知(NETLINK_KOBJECT_UEVENT),通用 netlink(NETLINK_GENERIC)。
Netlink 是一種在內(nèi)核和用戶應(yīng)用間進行雙向數(shù)據(jù)傳輸?shù)姆浅:玫姆绞剑脩魬B(tài)應(yīng)用使用標(biāo)準(zhǔn)的 socket API 就能使用 netlink 提供的強大功能,內(nèi)核態(tài)需要使用專門的內(nèi)核 API 來使用 netlink。 Netlink 相對于系統(tǒng)調(diào)用,ioctl 及 /proc 文件系統(tǒng)而言具有以下好處: 1,為了使用 netlink,用戶僅需要在 include/linux/netlink.h 中增加一個新類型的 netlink 協(xié)議定義即可, 如 #define NETLINK_MYTEST 17 然后,內(nèi)核和用戶態(tài)應(yīng)用就能即時通過 socket API 使用該 netlink 協(xié)議類型進行數(shù)據(jù)交換。但系統(tǒng)調(diào)用需要增加新的系統(tǒng)調(diào)用,ioctl 則需要增加設(shè)備或文件, 那需要不少代碼,proc 文件系統(tǒng)則需要在 /proc 下添加新的文件或目錄,那將使本來就混亂的 /proc 更加混亂。 2. netlink是一種異步通信機制,在內(nèi)核和用戶態(tài)應(yīng)用之間傳遞的消息保存在socket緩存隊列中,發(fā)送消息只是把消息保存在接收者的socket的接收隊列,而不必等待接收者收到消息,但系統(tǒng)調(diào)用和 ioctl 則是同步通信機制,如果傳遞的數(shù)據(jù)太長,將影響調(diào)度粒度。 3.使用 netlink 的內(nèi)核部分能采用模塊的方式實現(xiàn),使用 netlink 的應(yīng)用部分和內(nèi)核部分沒有編譯時依賴,但系統(tǒng)調(diào)用就有依賴,而且新的系統(tǒng)調(diào)用的實現(xiàn)必須靜態(tài)地連接到內(nèi)核中,他無法在模塊中實現(xiàn),使用新系統(tǒng)調(diào)用的應(yīng)用在編譯時需要依賴內(nèi)核。 4.netlink 支持多播,內(nèi)核模塊或應(yīng)用能把消息多播給一個netlink組,屬于該neilink 組的所有內(nèi)核模塊或應(yīng)用都能接收到該消息,內(nèi)核事件向用戶態(tài)的通知機制就使用了這一特性,所有對內(nèi)核事件感興趣的應(yīng)用都能收到該子系統(tǒng)發(fā)送的內(nèi)核事件,在后面的文章中將介紹這一機制的使用。 5.內(nèi)核能使用 netlink 首先發(fā)起會話,但系統(tǒng)調(diào)用和 ioctl 只能由用戶應(yīng)用發(fā)起調(diào)用。 6.netlink 使用標(biāo)準(zhǔn)的 socket API,因此非常容易使用,但系統(tǒng)調(diào)用和 ioctl則需要專門的培訓(xùn)才能使用。 用戶態(tài)使用 netlink 用戶態(tài)應(yīng)用使用標(biāo)準(zhǔn)的socket APIs, socket(), bind(), sendmsg(), recvmsg() 和 close() 就能非常容易地使用 netlink socket,查詢手冊頁能了解這些函數(shù)的使用細節(jié),本文只是講解使用 netlink 的用戶應(yīng)該怎么使用這些函數(shù)。注意,使用 netlink 的應(yīng)用必須包含頭文件 linux/netlink.h。當(dāng)然 socket 需要的頭文件也必不可少,sys/socket.h。 為了創(chuàng)建一個 netlink socket,用戶需要使用如下參數(shù)調(diào)用 socket(): socket(AF_NETLINK, SOCK_RAW, netlink_type) 第一個參數(shù)必須是 AF_NETLINK 或 PF_NETLINK,在 Linux 中,他們倆實際為一個東西,他表示要使用netlink,第二個參數(shù)必須是SOCK_RAW或SOCK_DGRAM, 第三個參數(shù)指定netlink協(xié)議類型,如前面講的用戶自定義協(xié)議類型NETLINK_MYTEST, NETLINK_GENERIC是個通用的協(xié)議類型,他是專門為用戶使用的,因此,用戶能直接使用他,而不必再添加新的協(xié)議類型。內(nèi)核預(yù)定義的協(xié)議類型有: #define NETLINK_ROUTE 0 /* Routing/device hook */ #define NETLINK_W1 1 /* 1-wire subsystem */ #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ #define NETLINK_FIREWALL 3 /* Firewalling hook */ #define NETLINK_INET_DIAG 4 /* INET socket monitoring */ #define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ #define NETLINK_XFRM 6 /* ipsec */ #define NETLINK_SELINUX 7 /* SELinux event notifications */ #define NETLINK_ISCSI 8 /* Open-iSCSI */ #define NETLINK_AUDIT 9 /* auditing */ #define NETLINK_FIB_LOOKUP 10 #define NETLINK_CONNECTOR 11 #define NETLINK_NETFILTER 12 /* netfilter subsystem */ #define NETLINK_IP6_FW 13 #define NETLINK_DNRTMSG 14 /* DECnet routing messages */ #define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ #define NETLINK_GENERIC 16 對于每一個netlink協(xié)議類型,能有多達 32多播組,每一個多播組用一個位表示,netlink 的多播特性使得發(fā)送消息給同一個組僅需要一次系統(tǒng)調(diào)用,因而對于需要多撥消息的應(yīng)用而言,大大地降低了系統(tǒng)調(diào)用的次數(shù)。 函數(shù) bind() 用于把一個打開的 netlink socket 和 netlink 源 socket 地址綁定在一起。netlink socket 的地址結(jié)構(gòu)如下: struct sockaddr_nl { sa_family_t nl_family; unsigned short nl_pad; __u32 nl_pid; __u32 nl_groups; }; 字段 nl_family 必須設(shè)置為 AF_NETLINK 或著 PF_NETLINK,字段 nl_pad 當(dāng)前沒有使用,因此要總是設(shè)置為 0,字段 nl_pid 為接收或發(fā)送消息的進程的 ID,如果希望內(nèi)核處理消息或多播消息,就把該字段設(shè)置為 0,否則設(shè)置為處理消息的進程 ID。字段 nl_groups 用于指定多播組,bind 函數(shù)用于把調(diào)用進程加入到該字段指定的多播組,如果設(shè)置為 0,表示調(diào)用者不加入所有多播組。 傳遞給 bind 函數(shù)的地址的 nl_pid 字段應(yīng)當(dāng)設(shè)置為本進程的進程 ID,這相當(dāng)于 netlink socket 的本地地址。不過,對于一個進程的多個線程使用 netlink socket 的情況,字段 nl_pid 則能設(shè)置為其他的值,如: pthread_self() 因此字段 nl_pid 實際上未必是進程 ID,他只是用于區(qū)分不同的接收者或發(fā)送者的一個標(biāo)識,用戶能根據(jù)自己需要設(shè)置該字段。函數(shù) bind 的調(diào)用方式如下: bind(fd, (struct sockaddr*)&nladdr, sizeof(struct sockaddr_nl)); fd為前面的 socket 調(diào)用返回的文件描述符,參數(shù) nladdr 為 struct sockaddr_nl 類型的地址。為了發(fā)送一個 netlink 消息給內(nèi)核或其他用戶態(tài)應(yīng)用,需要填充目標(biāo) netlink socket 地址,此時,字段 nl_pid 和 nl_groups 分別表示接收消息者的進程 ID 和多播組。如果字段 nl_pid 設(shè)置為 0,表示消息接收者為內(nèi)核或多播組,如果 nl_groups為 0,表示該消息為單播消息,否則表示多播消息。使用函數(shù) sendmsg 發(fā)送 netlink 消息時還需要引用結(jié)構(gòu) struct msghdr、struct nlmsghdr 和 struct iovec,結(jié)構(gòu) struct msghdr 需如下設(shè)置: struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&(nladdr); msg.msg_namelen = sizeof(nladdr); 其中 nladdr 為消息接收者的 netlink 地址。 struct nlmsghdr 為 netlink socket 自己的消息頭,這用于多路復(fù)用和多路分解 netlink 定義的所有協(xié)議類型及其他一些控制,netlink 的內(nèi)核實現(xiàn)將利用這個消息頭來多路復(fù)用和多路分解已其他的一些控制,因此他也被稱為netlink 控制塊。因此,應(yīng)用在發(fā)送 netlink 消息時必須提供該消息頭。 struct nlmsghdr { __u32 nlmsg_len; /* Length of message */ __u16 nlmsg_type; /* Message type*/ __u16 nlmsg_flags; /* Additional flags */ __u32 nlmsg_seq; /* Sequence number */ __u32 nlmsg_pid; /* Sending process PID */ }; 字段 nlmsg_len 指定消息的總長度,包括緊跟該結(jié)構(gòu)的數(shù)據(jù)部分長度及該結(jié)構(gòu)的大小,字段 nlmsg_type 用于應(yīng)用內(nèi)部定義消息的類型,他對 netlink 內(nèi)核實現(xiàn)是透明的,因此大部分情況下設(shè)置為 0,字段 nlmsg_flags 用于設(shè)置消息標(biāo)志,可用的標(biāo)志包括: /* Flags values */ #define NLM_F_REQUEST 1 /* It is request message. */ #define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */ #define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ #define NLM_F_ECHO 8 /* Echo this request */ /* Modifiers to GET request */ #define NLM_F_ROOT 0x100 /* specify tree root */ #define NLM_F_MATCH 0x200 /* return all matching */ #define NLM_F_ATOMIC 0x400 /* atomic GET */ #define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) /* Modifiers to NEW request */ #define NLM_F_REPLACE 0x100 /* Override existing */ #define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ #define NLM_F_CREATE 0x400 /* Create, if it does not exist */ #define NLM_F_APPEND 0x800 /* Add to end of list */ 標(biāo)志NLM_F_REQUEST用于表示消息是個請求,所有應(yīng)用首先發(fā)起的消息都應(yīng)設(shè)置該標(biāo)志。 標(biāo)志NLM_F_MULTI 用于指示該消息是個多部分消息的一部分,后續(xù)的消息能通過宏NLMSG_NEXT來獲得。 宏NLM_F_ACK表示該消息是前一個請求消息的響應(yīng),順序號和進程ID能把請求和響應(yīng)關(guān)聯(lián)起來。 標(biāo)志NLM_F_ECHO表示該消息是相關(guān)的一個包的回傳。 標(biāo)志NLM_F_ROOT 被許多 netlink 協(xié)議的各種數(shù)據(jù)獲取操作使用,該標(biāo)志指示被請求的數(shù)據(jù)表應(yīng)當(dāng)整體返回用戶應(yīng)用,而不是個條目一個條目地返回。有該標(biāo)志的請求通常導(dǎo)致響應(yīng)消息設(shè)置NLM_F_MULTI標(biāo)志。注意,當(dāng)設(shè)置了該標(biāo)志時,請求是協(xié)議特定的,因此,需要在字段 nlmsg_type 中指定協(xié)議類型。 標(biāo)志 NLM_F_MATCH 表示該協(xié)議特定的請求只需要一個數(shù)據(jù)子集,數(shù)據(jù)子集由指定的協(xié)議特定的過濾器來匹配。 標(biāo)志 NLM_F_ATOMIC 指示請求返回的數(shù)據(jù)應(yīng)當(dāng)原子地收集,這預(yù)防數(shù)據(jù)在獲取期間被修改。 標(biāo)志 NLM_F_DUMP 未實現(xiàn)。 標(biāo)志 NLM_F_REPLACE 用于取代在數(shù)據(jù)表中的現(xiàn)有條目。 標(biāo)志 NLM_F_EXCL_ 用于和 CREATE 和 APPEND 配合使用,如果條目已存在,將失敗。 標(biāo)志 NLM_F_CREATE 指示應(yīng)當(dāng)在指定的表中創(chuàng)建一個條目。 標(biāo)志 NLM_F_APPEND 指示在表末尾添加新的條目。 內(nèi)核需要讀取和修改這些標(biāo)志,對于一般的使用,用戶把他設(shè)置為 0 就能,只是一些高級應(yīng)用(如 netfilter 和路由 daemon 需要他進行一些復(fù)雜的操作),字段 nlmsg_seq 和 nlmsg_pid 用于應(yīng)用追蹤消息,前者表示順序號,后者為消息來源進程 ID。下面是個示例: #define MAX_MSGSIZE 1024 char buffer[] = "An example message"; struct nlmsghdr nlhdr; nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_MSGSIZE)); strcpy(NLMSG_DATA(nlhdr),buffer); nlhdr->nlmsg_len = NLMSG_LENGTH(strlen(buffer)); nlhdr->nlmsg_pid = getpid(); /* self pid */ nlhdr->nlmsg_flags = 0; 結(jié)構(gòu) struct iovec 用于把多個消息通過一次系統(tǒng)調(diào)用來發(fā)送,下面是該結(jié)構(gòu)使用示例: struct iovec iov; iov.iov_base = (void *)nlhdr; iov.iov_len = nlh->nlmsg_len; msg.msg_iov = &iov; msg.msg_iovlen = 1; 在完成以上步驟后,消息就能通過下面語句直接發(fā)送: sendmsg(fd, &msg, 0); 應(yīng)用接收消息時需要首先分配一個足夠大的緩存來保存消息頭及消息的數(shù)據(jù)部分,然后填充消息頭,添完后就能直接調(diào)用函數(shù) recvmsg() 來接收。 #define MAX_NL_MSG_LEN 1024 struct sockaddr_nl nladdr; struct msghdr msg; struct iovec iov; struct nlmsghdr * nlhdr; nlhdr = (struct nlmsghdr *)malloc(MAX_NL_MSG_LEN); iov.iov_base = (void *)nlhdr; iov.iov_len = MAX_NL_MSG_LEN; msg.msg_name = (void *)&(nladdr); msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; recvmsg(fd, &msg, 0); 注意:fd為socket調(diào)用打開的netlink socket描述符。 在消息接收后,nlhdr指向接收到的消息的消息頭,nladdr保存了接收到的消息的目標(biāo)地址,宏NLMSG_DATA(nlhdr)返回指向消息的數(shù)據(jù)部分的指針。 在linux/netlink.h中定義了一些方便對消息進行處理的宏,這些宏包括: #define NLMSG_ALIGNTO 4 #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) 宏NLMSG_ALIGN(len)用于得到不小于len且字節(jié)對齊的最小數(shù)值。 #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr))) 宏NLMSG_LENGTH(len)用于計算數(shù)據(jù)部分長度為len時實際的消息長度。他一般用于分配消息緩存。 #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) 宏NLMSG_SPACE(len)返回不小于NLMSG_LENGTH(len)且字節(jié)對齊的最小數(shù)值,他也用于分配消息緩存。 #define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) 宏NLMSG_DATA(nlh)用于取得消息的數(shù)據(jù)部分的首地址,設(shè)置和讀取消息數(shù)據(jù)部分時需要使用該宏。 #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) 宏NLMSG_NEXT(nlh,len)用于得到下一個消息的首地址,同時len也減少為剩余消息的總長度,該宏一般在一個消息被分成幾個部分發(fā)送或接收時使用。 #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && (nlh)->nlmsg_len 宏NLMSG_OK(nlh,len)用于判斷消息是否有l(wèi)en這么長。 #define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) 宏NLMSG_PAYLOAD(nlh,len)用于返回payload的長度。 函數(shù)close用于關(guān)閉打開的netlink socket。 netlink內(nèi)核API netlink的內(nèi)核實目前.c文件net/core/af_netlink.c中,內(nèi)核模塊要想使用netlink,也必須包含頭文件linux/netlink.h。內(nèi)核使用netlink需要專門的API,這完全不同于用戶態(tài)應(yīng)用對netlink的使用。如果用戶需要增加新的netlink協(xié)議類型,必須通過修改linux/netlink.h來實現(xiàn),當(dāng)然,目前的netlink實現(xiàn)已包含了一個通用的協(xié)議類型NETLINK_GENERIC以方便用戶使用,用戶能直接使用他而不必增加新的協(xié)議類型。前面講到,為了增加新的netlink協(xié)議類型,用戶僅需增加如下定義到linux/netlink.h就能: #define NETLINK_MYTEST 17 只要增加這個定義之后,用戶就能在內(nèi)核的所有地方引用該協(xié)議。 在內(nèi)核中,為了創(chuàng)建一個netlink socket用戶需要調(diào)用如下函數(shù): struct sock * netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)); 參數(shù)unit表示netlink協(xié)議類型,如NETLINK_MYTEST,參數(shù)input則為內(nèi)核模塊定義的netlink消息處理函數(shù),當(dāng)有消息到達這個netlink socket時,該input函數(shù)指針就會被引用。函數(shù)指針input的參數(shù)sk實際上就是函數(shù)netlink_kernel_create返回的struct sock指針,sock實際是socket的一個內(nèi)核表示數(shù)據(jù)結(jié)構(gòu),用戶態(tài)應(yīng)用創(chuàng)建的socket在內(nèi)核中也會有一個struct sock結(jié)構(gòu)來表示。下面是個input函數(shù)的示例: void input (struct sock *sk, int len) { struct sk_buff *skb; struct nlmsghdr *nlh = NULL; u8 *data = NULL; while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { /* process netlink message pointed by skb->data */ nlh = (struct nlmsghdr *)skb->data; data = NLMSG_DATA(nlh); /* process netlink message with header pointed by * nlh and data pointed by data */ } } 函數(shù)input()會在發(fā)送進程執(zhí)行sendmsg()時被調(diào)用,這樣處理消息比較及時,不過,如果消息特別長時,這樣處理將增加系統(tǒng)調(diào)用sendmsg()的執(zhí)行時間,對于這種情況,能定義一個內(nèi)核線程專門負(fù)責(zé)消息接收,而函數(shù)input的工作只是喚醒該內(nèi)核線程,這樣sendmsg將非??旆祷亍?br>函數(shù)skb = skb_dequeue(&sk->receive_queue)用于取得socket sk的接收隊列上的消息,返回為一個struct sk_buff的結(jié)構(gòu),skb->data指向?qū)嶋H的netlink消息。 函數(shù)skb_recv_datagram(nl_sk)也用于在netlink socket nl_sk上接收消息,和skb_dequeue的不同指出是,如果socket的接收隊列上沒有消息,他將導(dǎo)致調(diào)用進程睡眠在等待隊列nl_sk->sk_sleep,因此他必須在進程上下文使用,剛才講的內(nèi)核線程就能采用這種方式來接收消息。 下面的函數(shù)input就是這種使用的示例: void input (struct sock *sk, int len) { wake_up_interruptible(sk->sk_sleep); } 當(dāng)內(nèi)核中發(fā)送netlink消息時,也需要設(shè)置目標(biāo)地址和源地址,而且內(nèi)核中消息是通過struct sk_buff來管理的, linux/netlink.h中定義了一個宏: #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) 來方便消息的地址設(shè)置。下面是個消息地址設(shè)置的例子: NETLINK_CB(skb).pid = 0; NETLINK_CB(skb).dst_pid = 0; NETLINK_CB(skb).dst_group = 1; 字段pid表示消息發(fā)送者進程ID,也即源地址,對于內(nèi)核,他為 0, dst_pid 表示消息接收者進程 ID,也即目標(biāo)地址,如果目標(biāo)為組或內(nèi)核,他設(shè)置為 0,否則 dst_group 表示目標(biāo)組地址,如果他目標(biāo)為某一進程或內(nèi)核,dst_group 應(yīng)當(dāng)設(shè)置為 0。 在內(nèi)核中,模塊調(diào)用函數(shù) netlink_unicast 來發(fā)送單播消息: int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int nonblock); 參數(shù)sk為函數(shù)netlink_kernel_create()返回的socket,參數(shù)skb存放消息,他的data字段指向要發(fā)送的netlink消息結(jié)構(gòu),而skb的控制塊保存了消息的地址信息,前面的宏NETLINK_CB(skb)就用于方便設(shè)置該控制塊, 參數(shù)pid為接收消息進程的pid,參數(shù)nonblock表示該函數(shù)是否為非阻塞,如果為1,該函數(shù)將在沒有接收緩存可利用時即時返回,而如果為0,該函數(shù)在沒有接收緩存可利用時睡眠。 內(nèi)核模塊或子系統(tǒng)也能使用函數(shù)netlink_broadcast來發(fā)送廣播消息: void netlink_broadcast(struct sock *sk, struct sk_buff *skb, u32 pid, u32 group, int allocation); 前面的三個參數(shù)和netlink_unicast相同,參數(shù)group為接收消息的多播組,該參數(shù)的每一個代表一個多播組,因此如果發(fā)送給多個多播組,就把該參數(shù)設(shè)置為多個多播組組ID的位或。參數(shù)allocation為內(nèi)核內(nèi)存分配類型,一般地為GFP_ATOMIC或GFP_KERNEL,GFP_ATOMIC用于原子的上下文(即不能睡眠),而GFP_KERNEL用于非原子上下文。 在內(nèi)核中使用函數(shù)sock_release來釋放函數(shù)netlink_kernel_create()創(chuàng)建的netlink socket: void sock_release(struct socket * sock); 注意函數(shù)netlink_kernel_create()返回的類型為struct sock,因此函數(shù)sock_release應(yīng)該這種調(diào)用: sock_release(sk->sk_socket); sk為函數(shù)netlink_kernel_create()的返回值。 在 原始碼包 中給出了一個使用 netlink 的示例,他包括一個內(nèi)核模塊 netlink-exam-kern.c 和兩個應(yīng)用程式 netlink-exam-user-recv.c, netlink-exam-user-send.c。內(nèi)核模塊必須先插入到內(nèi)核,然后在一個終端上運行用戶態(tài)接收程式,在另一個終端上運行用戶態(tài)發(fā)送程式,發(fā)送程式讀取參數(shù)指定的文本文件并把他作為 netlink 消息的內(nèi)容發(fā)送給內(nèi)核模塊,內(nèi)核模塊接受該消息保存到內(nèi)核緩存中,他也通過proc接口出口到 procfs,因此用戶也能夠通過 /proc/netlink_exam_buffer 看到全部的內(nèi)容,同時內(nèi)核也把該消息發(fā)送給用戶態(tài)接收程式,用戶態(tài)接收程式將把接收到的內(nèi)容輸出到屏幕上。 |
|