genl-netlink 协议 Linux kernel 实现 欣赏
2017-04-09 19:31
190 查看
先看一幅图
设备驱动模型中查找请参考我下面的一片博文
http://blog.csdn.net/leesagacious/article/details/46486995
源码欣赏
当注册一个genl_ops时,会根据genl_ops->cmd 到链表上查找有没有同名的genl_ops. 比较: 在设备驱动模型中,当你添加一个device的时候,需要到device链表来查找有无同名的device, 添加deviec_driver的时候,也是一样利用name来查找有没有同名的device_driver(具体的是driver_find() 函数), 添加genl_ops原理一样,只不过这里是利用cmd来判断的.Linu内核中重要的结构体大部分都是这样组织成链表(另一部分是数组), 然后对该链表进行增加、删除、遍历.. list_entry()取出一个 然后调用该节点中的回调函数,
设备驱动模型中查找请参考我下面的一片博文
http://blog.csdn.net/leesagacious/article/details/46486995
源码欣赏
/* @family 通用netlink家族 在调用该函数前,需要构造结构体struct genl_family,然后调用函数genl_register_family()来注册 这个函数很丰富,最终还是把构造的genl_family 添加到散列表上,下面会说 注意, 它的pre_doit()函数比 genl_ops 的 doit()函数调用还要早, post_doit()函数在doit()函数调用后调用 这样的设计 比 ioctl 要好多了 @ops 这个参数很重要,而且对该参数的校验也是很严格的 必需提供回调函数 doit()或 dumpit(),不然,你就别想注册成功了 */ int genl_register_ops(struct genl_family *family, struct genl_ops *ops) { int err = -EINVAL; /** 这里对传入的参数进行校验,不合法的别想进来,如果不提供过doit、dupit 就会错误, 其实,这里校验不是最严重的地方,最严重的是对 注册的组播组的名字进行校验,连续用了两个BUG_ON(), 这是Linux kernel中为数不多的一次 源码 : int genl_register_mc_group() { ...... BUG_ON(grp->name[0] == '\0'); BUG_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL); */ if (ops->dumpit == NULL && ops->doit == NULL) goto errout; /** 该函数就是上图说的了,遍历整条链表,发现有相同命令的,就在这儿返回了 源码: static struct genl_ops *genl_get_cmd() { struct genl_ops *ops; 遍历链表吧 list_for_each_entry(ops, &family->ops_list, ops_list) if (ops->cmd == cmd) 比较CMD return ops; return NULL; } */ if (genl_get_cmd(ops->cmd, family)) { err = -EEXIST; goto errout; } /* #define GENL_ADMIN_PERM 0x01 #define GENL_CMD_CAP_DO 0x02 #define GENL_CMD_CAP_DUMP 0x04 #define GENL_CMD_CAP_HASPOL 0x08 如果你注册的genl_ops提供了dumpit、doit、policy时,会改变ops中的flags的位, 以后的函数 会检查这个flags的位吗 ? 内核中仅有一处检查这个flags的位,而且检查的是 #define GENL_CMD_CAP_DUMP 0x04 那么 netlink内核 用这个flags字段 又有哪些含义呢! 使用通用netlink套接字从user space 发送的数据,会交给这个函数处理 genl_rcv() { ↓ genl_rcv_msg() { ↓ genl_family_rcv_msg() { if ((ops->flags & GENL_ADMIN_PERM) &&!netlink_capable(skb,CAP_NET_ADMIN)) } } } */ if (ops->dumpit) // 转储回调函数 ops->flags |= GENL_CMD_CAP_DUMP; if (ops->doit) // 命令回调函数 ops->flags |= GENL_CMD_CAP_DO; if (ops->policy) // 属性有效性策略 ops->flags |= GENL_CMD_CAP_HASPOL; /* 这里用了两把锁,保护临界区 down_write(&cb_lock); mutex_lock(&genl_mutex); 读写锁、互斥锁 同时用上了, */ genl_lock_all(); /* 添加到链表上去把 */ list_add_tail(&ops->ops_list, &family->ops_list); genl_unlock_all(); /** 在这里函数中有一个 大的switch case, if (!init_net.genl_sock) return 0; switch (event) { case CTRL_CMD_NEWFAMILY: case CTRL_CMD_DELFAMILY: case CTRL_CMD_NEWMCAST_GRP: default: return -EINVAL; } 看该函数的第一个参数 CTRL_CMD_NEWOPS 没有匹配任何一个,直接 return 了 */ genl_ctrl_event(CTRL_CMD_NEWOPS, ops); err = 0; errout: return err; }
相关文章推荐
- uevent内核事件与netlink机制的交互 -Linux Kernel实现欣赏
- Driver 分层的思想 -- Linux Kernel 内核实现欣赏
- Process scheduling - Linux Kernel 实现 欣赏
- Interrupt 架构之美 -- Linux Kernel 实现欣赏
- Linux Kernel 调度实现 -----欣赏
- Device Tree --- Linux Kernel 实现欣赏
- 往process group 发送signal - linux kernel 实现浅欣赏
- Usb + Serial + Net --- Linux Kernel 实现欣赏
- RFC1867协议客户端实现
- RTP协议和MPEG-4的流媒体分析与实现
- Gnutella协议的相关介绍(Peercast实现P2P传输所使用的协议)
- 在Java中实现UDP协议编程的方法
- 用UDP实现广播协议
- 协议与实现的关系,仅对XMPP
- 基于RTP协议和MPEG-4的流媒体系统分析与实现
- 网络协议恶补心得笔记(一)& Sniffer实现
- 用UDP协议实现广播通信
- RFC1867协议客户端实现
- MSN P2P 协议实现 msmp2p.h
- 如何实现自定义的URL协议