linux 内核与用户空间通信之netlink使用方法Word格式.docx
《linux 内核与用户空间通信之netlink使用方法Word格式.docx》由会员分享,可在线阅读,更多相关《linux 内核与用户空间通信之netlink使用方法Word格式.docx(9页珍藏版)》请在冰豆网上搜索。
完成绑定,内核空间接收到用户进程ID之后便可以进行通讯。
用户空间进程发送数据使用标准socketAPI中sendmsg()函数完成,使用时需添加structmsghdr消息和nlmsghdr消息头。
一个netlink消息体由nlmsghdr和消息的payload部分组成,输入消息后,内核会进入nlmsghdr指向的缓冲区。
内核空间发送数据使用独立创建的sk_buff缓冲区,Linux定义了如下宏方便对于缓冲区地址的设置,如下所示:
#defineNETLINK_CB(skb)(*(structnetlink_skb_parms*)
参数sk为函数netlink_kernel_create()返回的socket,参数skb存放消息,它的data字段指向要发送的netlink消息结构,而skb的控制块保存了消息的地址信息,前面的宏NETLINK_CB(skb)就用于方便设置该控制块,参数pid为接收消息进程的pid,参数nonblock表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回,而如果为0,该函数在没有接收缓存可利用时睡眠。
内核模块或子系统也可以使用函数netlink_broadcast来发送广播消息:
voidnetlink_broadcast(structsock*sk,structsk_buff*skb,u32pid,u32group,intallocation);
前面的三个参数与netlink_unicast相同,参数group为接收消息的多播组,该参数的每一个代表一个多播组,因此如果发送给多个多播组,就把该参数设置为多个多播组组ID的位或。
参数allocaTIon为内核内存分配类型,一般地为GFP_ATOMIC或GFP_KERNEL,GFP_ATOMIC用于原子的上下文(即不可以睡眠),而GFP_KERNEL用于非原子上下文。
接收数据时程序需要申请足够大的空间来存储netlink消息头和消息的payload部分。
然后使用标准函数接口recvmsg()来接收netlink消息
4Netlink通信过程
调试平台:
Vmware5.5+FedoraCore10(两台,一台作为host机,一台作为target机)。
调试程序:
分为内核模块和用户空间程序两部分,当内核模块被加载后,运行用户空间程序,由用户空间发起Netlink会话,和内核模块进行数据交换。
被加载的内核模块无法通过外加的调试器进行调试,KGDB提供了一种内核源码级别的调试机制。
Linux内核自2.6.26版本之后在内核中内置了KGDB选项,编译内核时需要选择与之相关的选项,调试时host端需使用带有符号表的vmlinz内核,target端使用gdb调试用户空间的程序。
用户空间程序关键代码如下:
intsend_pck_to_kern(u8op,constu8*data,u16data_len){structuser_data_*pck;
intret;
pck=(structuser_data_*)calloc(1,sizeof(*pck)+data_len);
if(!
pck){printf("
callocin%sfailed!
!
\n"
__FUNCTION__);
return-1;
}pck->
magic_num=MAGIC_NUM_RNQ;
pck->
op=op;
data_len=data_len;
memcpy(pck->
data,data,data_len);
ret=send_to_kern((constu8*)pck,sizeof(*pck)+data_len);
if(ret)printf("
send_to_kernin%sfailed!
free(pck);
returnret?
-1:
0;
}staticvoidrecv_from_nl(){charbuf[1000];
intlen;
structioveciov={buf,sizeof(buf)};
structsockaddr_nlsa;
structmsghdrmsg;
structnlmsghdr*nh;
memset(msg.msg_name=(void*)msg.msg_namelen=sizeof(sa);
msg.msg_iov=msg.msg_iovlen=1;
//len=recvmsg(nl_sock,len=recvmsg(nl_sock,for(nh=(structnlmsghdr*)buf;
NLMSG_OK(nh,len);
nh=NLMSG_NEXT(nh,len)){//Theendofmultipartmessage.if(nh->
nlmsg_type==NLMSG_DONE){puts("
nh->
nlmsg_type==NLMSG_DONE"
);
return;
}if(nh->
nlmsg_type==NLMSG_ERROR){//Dosomeerrorhandling.puts("
nlmsg_type==NLMSG_ERROR"
}#if1puts("
Datareceivedfromkernel:
"
hex_dump((u8*)NLMSG_DATA(nh),NLMSG_PAYLOAD(nh,0));
#endif}}
内核模块需要防止资源抢占,保证Netlink资源互斥占有,内核模块部分关键代码如下:
staTIcvoidnl_rcv(structsk_buff*skb){mutex_lock(netlink_rcv_skb(skb,mutex_unlock(}staTIcintnl_send_msg(constu8*data,intdata_len){structnlmsghdr*rep;
u8*res;
structsk_buff*skb;
if(g_pid0){printk("
Datatobesendtouserspace:
hex_dump((void*)data,data_len);
}rep=__nlmsg_put(skb,g_pid,0,NLMSG_NOOP,data_len,0);
res=nlmsg_data(rep);
memcpy(res,data,data_len);
netlink_unicast(g_nl_sk,skb,g_pid,MSG_DONTWAIT);
return0;
}staTIcintnl_rcv_msg(structsk_buff*skb,structnlmsghdr*nlh){constu8res_data[]="
Hello,user"
;
size_tdata_len;
u8*buf;
structuser_data_*pck;
structuser_req*req,*match=NULL;
g_pid=NETLINK_CB(skb).pid;
buf=(u8*)NLMSG_DATA(nlh);
data_len=nlmsg_len(nlh);
if(data_lenmagic_num!
=MAGIC_NUM_RNQ){printk("
Magicnumbernotmatched!
}if(g_debug_level>
0){printk("
Datafromuserspace:
hex_dump(buf,data_len);
}req=user_reqs;
while(req->
op){if(req->
op==pck->
op){match=req;
break;
}req++;
}if(match){match->
handler(buf,data_len);
}nl_send_msg(res_data,sizeof(res_data));
}
5.其他相关说明
Netlink是一种特殊的socket,它是Linux所特有的,类似于BSD中的AF_ROUTE但又远比它的功能强大,目前在最新的Linux内核(2.6.14)中使用netlink进行应用与内核通信的应用很多,包括:
路由daemon(NETLINK_ROUTE),1-wire子系统(NETLINK_W1),用户态socket协议(NETLINK_USERSOCK),防火墙(NETLINK_FIREWALL),socket监视(NETLINK_INET_DIAG),netfilter日志(NETLINK_NFLOG),ipsec安全策略(NETLINK_XFRM),SELinux事件通知(NETLINK_SELINUX),iSCSI子系统(NETLINK_ISCSI),进程审计(NETLINK_AUDIT),转发信息表查询(NETLINK_FIB_LOOKUP),netlinkconnector(NETLINK_CONNECTOR),netfilter子系统(NETLINK_NETFILTER),IPv6防火墙(NETLINK_IP6_FW),DECnet路由信息(NETLINK_DNRTMSG),内核事件向用户态通知(NETLINK_KOBJECT_UEVENT),通用netlink(NETLINK_GENERIC)。
Netlink是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的socketAPI就可以使用netlink提供的强大功能,内核态需要使用专门的内核API来使用netlink。
Netlink相对于系统调用,ioctl以及/proc文件系统而言具有以下优点:
1,为了使用netlink,用户仅需要在include/linux/netlink.h中增加一个新类型的netlink协议定义即可,如#defineNETLINK_MYTEST17然后,内核和用户态应用就可以立