好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

(精品)NetLink使用实例(YGM).doc

6页
  • 卖家[上传人]:大米
  • 文档编号:418536140
  • 上传时间:2024-01-12
  • 文档格式:DOC
  • 文档大小:77KB
  • / 6 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • 如何使用Netlink ConnectorAuthor: Yang gongming杨燚,计算机科学硕士,毕业于中科院计算技术研究所,有5年的Linux内核编程经验,目前从事Linux的内核和应用开发您可以通过 yang.y.yi@ 与作者联系简介: 本文详细介绍了 Linux 2.6.34.14 内核引入的内核空间与用户空间通信的新机制连接器,并通过典型示例讲解了它的使用一、概述连接器是一种新的用户态与内核态的通信方式,它使用起来非常方便本质上,连接器是一种netlink,它的 netlink 协议号为 NETLINK_CONNECTOR,与一般的 netlink 相比,它提供了更容易的使用接口,使用起来更方便netlink本质上是socket,不过它可用于用户程序和内核程序的通信1.内核模块使用方法注册一个标识 ID 和回调函数,即可使用连接器cn_msg结构://标识netlink的IDstruct cb_id{ __u32 idx; __u32 val;};//netlink控制信息头struct cn_msg{ struct cb_id id; __u32 seq; __u32 ack; __u32 len;/* Length of the following data */ __u8 data[0];};三个内核模块常用的API。

      int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));void cn_del_callback(struct cb_id *id);void cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask);结构 cb_id 是连接器实例的标识 ID,它用于确定 netlink 消息与回调函数的对应关系当连接器接收到标识 ID 为 {idx,val} 的 netlink 消息时,注册的回调函数 void (*callback) (void *) 将被调用该回调函数的参数为结构 struct cn_msg 的指针接口函数 cn_add_callback 用于向连接器注册新的连接器实例以及相应的回调函数,参数 id 指定注册的标识 ID,参数 name 指定连接器回调函数的符号名,参数 callback 为回调函数接口函数 cn_del_callback 用于卸载回调函数,参数 id 为注册函数 cn_add_callback 注册的连接器标识 ID。

      接口函数 cn_netlink_send 用于向给定的组发送消息,它可以在任何上下文安全地调用但是,如果内存不足,可能会发送失败在具体的连接器实例中,该函数用于向用户态发送 netlink 消息参数 msg 为发送的 netlink 消息的消息头参数 __group 为接收消息的组用户侧接收消息,不需要注册idx和val,所以,内核调用cn_add_callback时的idx和val对将数据报文发送到那个用户没有任何影响如果它为 0,那么连接器将搜索所有注册的连接器用户,也不会发送给用户 ID 与在 msg 中的 ID 相同的组在__group==0时,甚至不会发送给=0的用户组但如果 __group 不为 0,消息将发送给 __group 指定的组参数 gfp_mask 指定页分配标志用户接收方,通过:socket()函数和bind函数,以及setsockopt()函数,设置接收组只通过组来接收当bind函数中sockaddr_nl中的group设置为0xffff或大于该值,将接收到所有的组的消息,也不管是否在setsockopt()函数中设置的组参数是多少对于非0xffff参数,bind的sockaddr_nl的goup必须和setsockopt()的组保持一致。

      这样才能收到内核发送到指定组(__group)的消息cn_msg 是连接器定义的消息头,字段 seq 和 ack 用于确保消息的可靠传输,刚才已经提到,netlink 在内存紧张的情况下可能丢失消息,因此该头使用顺序号和响应号来满足要求可靠传输用户的需求当发送消息时,用户需要设置独一无二的顺序号和随机的响应号,顺序号也应当设置到 nlmsghdr->nlmsg_seq注意 nlmsghdr 是类型为结构 struct nlmsghdr 的变量,它用于设置或保存 netlink 的消息头每发送一个消息,顺序号应当加 1,如果需要发送响应消息,那么响应消息的顺序号应当与被响应的消息的顺序号相同,同时响应消息的响应号应当为被响应消息的顺序号加1如果接收到的消息的顺序号不是期望的顺序号,那表明该消息是一个新的消息,如果接收到的消息的顺序号是期望的顺序号,但它的响应号不等于上次发送消息的顺序号加1,那么它也是新消息用户层接收到消息后,对序号以及idx和val的处理,需要接收后进行比较,以判断丢弃或其他处理2.用户态使用方法用户层绑定一个接收用户组int group = 5;s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);l_local.nl_family = AF_NETLINK;l_local.nl_groups = group;l_local.nl_pid = getpid();if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) { perror("bind"); close(s); return -1;}setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));在不需要使用该连接器时使用语句setsockopt(s, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group));---如上红色部分是非常重要的参数。

      二、下面从几个维度来分析netlink connect的使用方法1.内核发送://首先注册回调函数不管是收还是发,都必须注册cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);cn_test_id: idx和Val是接收数据的参数cn_test_callback是接收的回调函数这几个参数和发送无关//buffer结构为: cn_msg结构体+纯数据 纯数据长度由m->len指定cn_msg * m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC); m->id.idx = 11;//any m->id.val =234;//any m->seq =0;//any m->len = sizeof("Hi 美女?");//必须为附加数据的长度 memcpy(m + 1,"Hi 美女?", m->len);// //发送到指定的组 group=13; cn_netlink_send(m,group, GFP_ATOMIC);如上程序,即完成netlink 的发送。

      一定要关注好group的含义,否则无法被用户层接收到报文2.用户层接收://netlink是socket,所以必须socket一下红色字体必须正确使用//如果没有定义NETLINK_CONNECTOR ,可直接用11来指定是connector memset(buf, 0, sizeof(buf)); s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);//将socket和netlink绑定 l_local.nl_family = AF_NETLINK; l_local.nl_groups = 0; l_local.nl_pid = 3;//any bind(s, (struct sockaddr *)&l_local,sizeof(struct sockaddr_nl)) int group= 0; setsockopt(s,270,1,&group,sizeof(group));如上代码: nl_groups在linux文档中描述为掩码,具体如何算法不清楚,也没有精力去分析如果要广播,就设置nl_groups=0xffffffff即可。

      否则,就设置改组和group一样这样只有发送到group的消息才会被接收对于内核到用户层要实现组播,个人觉得没有必要从实验结果来看,2.6.34.14内核还有待完善如上代码完成后,就可接收报文了 memset(buf, 0, sizeof(buf)); len = recv(s, buf, sizeof(buf), 0); reply = (struct nlmsghdr *)buf; data = (struct cn_msg *)(reply+1);接收代码很简单,数据的结构为: nlmsghdr+cn_msg+datalen的长度 = nlmsghdr+cn_msg+data+addlen(四字节对齐所长出来的长度如果恰巧是4的整数倍,addlen=0);reply->nlmsg_len =len;data->len =data(发送的数据包)的长度2.用户层发送用户层发送是个体力活,方法如下: sd = socket(PF_NETLINK,SOCK_RAW,NETLINK_CONNECTOR); saddr.nl_family = AF_NETLINK; saddr.nl_pid = 0; //任意 saddr.nl_groups = -1;//-1=0xfffff,表示都接收。

      bind(sd,(struct sockaddr*)&saddr, sizeof(struct sockaddr_nl)); int x=8; setsockopt(sd,270,1,&x,sizeof(x)); //开始发送;当然,先要申请buffer[1024],足够大 //size为带字节对齐的总长度,最好用NLMSG_SPACE size = NLMSG_SPACE(sizeof(struct cn_msg) + 68); nlh=(struct nlmsghdr *)buffer; nlh->nlmsg_seq = sid++;//自定义 nlh->nlmsg_pid = getpid();//自定义 nlh->nlmsg_type = 3;//固定为3 nlh->nlmsg_len = NLMSG_LENGTH(size-sizeof(*nlh));//总长度 nlh->nlmsg_flags = 0; data = NLMSG_DATA(nlh);//找到存放cn_msg的地方 data->id.idx =0x11;//内核程序在cn。

      点击阅读更多内容
      关于金锄头网 - 版权申诉 - 免责声明 - 诚邀英才 - 联系我们
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.