linux 内核与用户空间通信之netlink使用方法.docx

上传人:b****2 文档编号:375938 上传时间:2022-10-09 格式:DOCX 页数:9 大小:19.30KB
下载 相关 举报
linux 内核与用户空间通信之netlink使用方法.docx_第1页
第1页 / 共9页
linux 内核与用户空间通信之netlink使用方法.docx_第2页
第2页 / 共9页
linux 内核与用户空间通信之netlink使用方法.docx_第3页
第3页 / 共9页
linux 内核与用户空间通信之netlink使用方法.docx_第4页
第4页 / 共9页
linux 内核与用户空间通信之netlink使用方法.docx_第5页
第5页 / 共9页
点击查看更多>>
下载资源
资源描述

linux 内核与用户空间通信之netlink使用方法.docx

《linux 内核与用户空间通信之netlink使用方法.docx》由会员分享,可在线阅读,更多相关《linux 内核与用户空间通信之netlink使用方法.docx(9页珍藏版)》请在冰豆网上搜索。

linux 内核与用户空间通信之netlink使用方法.docx

linux内核与用户空间通信之netlink使用方法

linux内核与用户空间通信之netlink使用方法

1 引言

Linux中的进程间通信机制源自于Unix平台上的进程通信机制。

Unix的两大分支AT

其中net参数是网络设备命名空间指针,input函数是netlinksocket在接受到消息时调用的回调函数指针,module默认为THIS_MODULE.

然后用户空间进程使用标准SocketAPI来创建套接字,将进程ID发送至内核空间,用户空间创建使用socket()创建套接字,该函数的原型如下:

intsocket(intdomain,inttype,intprotocol);

其中domain值为PF_NETLINK,即Netlink使用协议族。

protocol为Netlink提供的协议或者是用户自定义的协议,Netlink提供的协议包括NETLINK_ROUTE,NETLINK_FIREWALL,NETLINK_ARPD,NETLINK_ROUTE6和NETLINK_IP6_FW。

接着使用bind函数绑定。

Netlink的bind()函数把一个本地socket地址(源socket地址)与一个打开的socket进行关联。

完成绑定,内核空间接收到用户进程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;pck->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!

!

!

\n",__FUNCTION__);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("nh->nlmsg_type==NLMSG_ERROR");return;}#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:

\n");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!

!

!

\n");return-1;}if(g_debug_level>0){printk("Datafromuserspace:

\n");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));return0;}

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然后,内核和用户态应用就可以立

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1