Linux中与内核通信的Netlink机制Word文档下载推荐.docx
《Linux中与内核通信的Netlink机制Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Linux中与内核通信的Netlink机制Word文档下载推荐.docx(23页珍藏版)》请在冰豆网上搜索。
只有当内核空间中的input()函数返回时,用户调用的sendmsg()函数才会返回。
对于这种情况,可以定义一个内核线程专门负责消息接收,而函数input的工作只是唤醒该内核线程,这样sendmsg将很快返回。
(这里网上的的说明)不过在查看Linux2.6.37版本的内核时并没有发现这种处理过程,一般都是按下面的方法进行处理。
这里注册的netlink协议为NETLINK_XFRM。
nlsk=netlink_kernel_create(net,NETLINK_XFRM,XFRMNLGRP_MAX,
xfrm_netlink_rcv,NULL,THIS_MODULE);
staticvoidxfrm_netlink_rcv(structsk_buff*skb)
{
mutex_lock(&
xfrm_cfg_mutex);
netlink_rcv_skb(skb,&
xfrm_user_rcv_msg);
mutex_unlock(&
}
在netlink_rcv_skb()函数中进行接收处理。
intnetlink_broadcast(structsock*ssk,structsk_buff*skb,u32pid,
u32group,gfp_tallocation)
前面的三个参数与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。
下面是参考网上使用netlink写的和内核通信的两个程序,一个是用户空间,一个是内核空间。
内核空间:
#include<
linux/init.h>
linux/module.h>
linux/timer.h>
linux/time.h>
linux/types.h>
net/sock.h>
net/netlink.h>
#defineNETLINK_TEST25
#defineMAX_MSGSIZE1024
intstringlength(char*s);
voidsendnlmsg(char*message);
intpid;
interr;
structsock*nl_sk=NULL;
intflag=0;
voidsendnlmsg(char*message)
structsk_buff*skb_1;
structnlmsghdr*nlh;
intlen=NLMSG_SPACE(MAX_MSGSIZE);
intslen=0;
if(!
message||!
nl_sk)
{
return;
}
skb_1=alloc_skb(len,GFP_KERNEL);
skb_1)
printk(KERN_ERR"
my_net_link:
alloc_skb_1error\n"
);
slen=stringlength(message);
nlh=nlmsg_put(skb_1,0,0,0,MAX_MSGSIZE,0);
NETLINK_CB(skb_1).pid=0;
NETLINK_CB(skb_1).dst_group=0;
message[slen]='
\0'
;
memcpy(NLMSG_DATA(nlh),message,slen+1);
printk("
sendmessage'
%s'
.\n"
(char*)NLMSG_DATA(nlh));
netlink_unicast(nl_sk,skb_1,pid,MSG_DONTWAIT);
intstringlength(char*s)
for(;
*s;
s++){
slen++;
returnslen;
voidnl_data_ready(structsk_buff*__skb)
structsk_buff*skb;
charstr[100];
structcompletioncmpl;
inti=10;
skb=skb_get(__skb);
if(skb->
len>
=NLMSG_SPACE(0))
nlh=nlmsg_hdr(skb);
memcpy(str,NLMSG_DATA(nlh),sizeof(str));
Messagereceived:
%s\n"
str);
pid=nlh->
nlmsg_pid;
while(i--)
init_completion(&
cmpl);
wait_for_completion_timeout(&
cmpl,3*HZ);
sendnlmsg("
Iamfromkernel!
"
flag=1;
kfree_skb(skb);
//Initializenetlink
intnetlink_init(void)
nl_sk=netlink_kernel_create(&
init_net,NETLINK_TEST,1,
nl_data_ready,NULL,THIS_MODULE);
nl_sk){
createnetlinksocketerror.\n"
return1;
my_net_link_3:
createnetlinksocketok.\n"
return0;
staticvoidnetlink_exit(void)
if(nl_sk!
=NULL){
sock_release(nl_sk->
sk_socket);
selfmoduleexited\n"
module_init(netlink_init);
module_exit(netlink_exit);
MODULE_AUTHOR("
frankzfz"
MODULE_LICENSE("
GPL"
下面是用户空间的程序:
sys/stat.h>
unistd.h>
stdio.h>
stdlib.h>
sys/socket.h>
sys/types.h>
string.h>
asm/types.h>
linux/netlink.h>
linux/socket.h>
errno.h>
#defineMAX_PAYLOAD1024//maximumpayloadsize
intmain(intargc,char*argv[])
intstate;
structsockaddr_nlsrc_addr,dest_addr;
structnlmsghdr*nlh=NULL;
structioveciov;
structmsghdrmsg;
intsock_fd,retval;
intstate_smg=0;
//Createasocket
sock_fd=socket(AF_NETLINK,SOCK_RAW,NETLINK_TEST);
if(sock_fd==-1){
printf("
errorgettingsocket:
%s"
strerror(errno));
return-1;
//Topreparebinding
memset(&
msg,0,sizeof(msg));
src_addr,0,sizeof(src_addr));
src_addr.nl_family=AF_NETLINK;
src_addr.nl_pid=getpid();
//selfpid
src_addr.nl_groups=0;
//multicast
retval=bind(sock_fd,(structsockaddr*)&
src_addr,sizeof(src_addr));
if(retval<
0){
bindfailed:
close(sock_fd);
//Topreparerecvmsg
nlh=(structnlmsghdr*)malloc(NLMSG_SPACE(MAX_PAYLOAD));
nlh){
mallocnlmsghdrerror!
\n"
dest_addr,0,sizeof(dest_addr));
dest_addr.nl_family=AF_NETLINK;
dest_addr.nl_pid=0;
dest_addr.nl_groups=0;
nlh->
nlmsg_len=NLMSG_SPACE(MAX_PAYLOAD);
nlmsg_pid=getpid();
nlmsg_flags=0;
strcpy(NLMSG_DATA(nlh),"
Helloyou!
iov.iov_base=(void*)nlh;
iov.iov_len=NLMSG_SPACE(MAX_PAYLOAD);
//iov.iov_len=nlh->
nlmsg_len;
msg,0,sizeof(msg));
msg.msg_name=(void*)&
dest_addr;
msg.msg_namelen=sizeof(dest_addr);
msg.msg_iov=&
iov;
msg.msg_iovlen=1;
state_smg\n"
state_smg=sendmsg(sock_fd,&
msg,0);
if(state_smg==-1)
geterrorsendmsg=%s\n"
strerror(errno));
memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
waitingreceived!
//Readmessagefromkernel
while
(1){
Inwhilerecvmsg\n"
state=recvmsg(sock_fd,&
msg,0);
if(state<
0)
state<
1"
Inwhile\n"
Receivedmessage:
%s\n"
(char*)NLMSG_DATA(nlh));
下面是Makefile文件:
obj-m:
=netlink_k.o
KERNELBUILD:
=/lib/modules/`uname-r`/build
default:
@echo"
BUILEKmod"
@make-C$(KERNELBUILD)M=$(shellpwd)modules
gcc-onetlink_2netlink_2.c
clean:
CLEANkmod"
@rm-rf*.o
@rm-rf.depend.*.cmd*.ko*.mod.c.tmp_versions*.symvers.*.d
其中,netlink_k.c为内核的空间的程序。
先运行内核代码netlink_k.ko,也就是在执行完makefile文件后,会生成一个netlink_k.ko文件,可以使用下面的命令进行安装,insmodnetlink_k.ko,使用lsmod查看,当安装成功后,然后,执行./netlink用户空间程序,可以在另一个终端下执行dmesg命令,查看内核通信的情况。
这里netlink程序向内核空间发送一个helloyou!
内核返回给一个Iamfromkernel!
在这里使用了一个定时器,也就是每3秒中发送一次Iamfromkernel!
只有内核把10个字符串全部发送完毕后,用户空间的sendmsg()才会返回,也就是在用户空间的netlink才会输出内核空间发送过来的数据,这里只有一个简单的程序,并没有什么实际的意义,因为,正如前面所说的一般情况下不会在回调函数中处理太多的东西,以免sendmsg()函数返回不及时。
下面是使用dmesg命令输出的信息。
[873791.498039]my_net_link_3:
createnetlinksocketok.
[873810.263676]Messagereceived:
Hello
[873813.260848]my_net_link_4:
'
.
[873816.260821]my_net_link_4:
[873819.260860]my_net_link_4:
[873822.260762]my_net_link_4:
[873825.260883]my_net_link_4:
[873828.260669]my_net_link_4:
[873831.260714]my_net_link_4:
[873834.260683]my_net_link_4:
[873837.260666]my_net_link_4:
[873840.260632]my_net_link_4:
2.6.24以上内核中netlink使用方法
测试环境:
2.6.28
Netlink在2.6内核的不同版本中发生了很大变化,具体请参考(注意其中的版本号不一定确切):
0.综述
以下程序基本流程如下:
运行netlink内核模块;
运行用户态程序,向内核发送连接消息,通知内核自身进程id;
内核接收用户消息,记录其进程id;
内核向用户进程id发送netlink消息;
用户接收内核发送的netlink消息。
1.内核部分
1.1相关的数据结构变量:
44//---------Thesearefornetlink---------//
45#defineNETLINK_REALNET26
46structsock*g_nl_sk=NULL;
48structsockaddr_nlsrc_addr,dest_addr;
50structioveciov;
52intpid;
53structmsghdrmsg;
55//-----------------------------------------//
44//---------Thesearefornetlink---------//
45#defineNETLINK_REALNET26
46structsock*g_nl_sk=NULL;
48structsockaddr_nlsrc_addr,dest_addr;
50structioveciov;
52intpid;
53structmsghdrmsg;
55//-----------------------------------------//
45#defineNETLINK_REALNET26
定义协议族。
该变量在ne