日期:2014-05-16 浏览次数:20611 次
1. 前言 netlink协议族是Linux内核网络部分的一个固定部分, 一旦在内核配置中选了网络支持就自动带了而不能单独去掉。 netlink的实现源码在net/netlink目录下,主要是net/netlink/af_netlink.c文件。 以下内核代码版本为2.6.19.2, 如无特别说明代码取自net/netlink/af_netlink.c。 2. 数据结构 netlink套接口结构: /* net/netlink/af_netlink.c */ struct netlink_sock { /* struct sock has to be the first member of netlink_sock */ struct sock sk; u32 pid; // 自己的pid, 通常是0 u32 dst_pid; // 对方的pid u32 dst_group; // 对方的组 u32 flags; u32 subscriptions; u32 ngroups; // 多播组数量 unsigned long *groups; // 多播组号 unsigned long state; wait_queue_head_t wait; // 等待队列,用于处理接收发送包时的top half struct netlink_callback *cb; // 回调结构,包含回调函数 spinlock_t cb_lock; void (*data_ready)(struct sock *sk, int bytes); // 数据到达时 //的操作, netlink可有不同类型, 如ROUTE, FIREWALL, ARPD等, //每种类型都自己定义的data_ready处理 struct module *module; }; 这个结构先是包含一个标准的struct sock结构,后面又跟和netlink相关的特有相关数据,内核中其他协议的sock也是类似定义的, 注意sock结构必须放在第一位,这是为了可以直接将sock的指针转为netlink_sock的指针。 netlink sock的表: struct netlink_table { struct nl_pid_hash hash; // 根据pid进行HASH的netlink sock链表, 相当于客户端链表 struct hlist_head mc_list; // 多播的sock链表 unsigned long *listeners; // 监听者标志 unsigned int nl_nonroot; unsigned int groups; // 每个netlink的协议类型可以定义多个组, 8的倍数,最小是32 struct module *module; int registered; }; 最大可有MAX_LINKS(32)个表,处理不同协议类型的netlink套接口, 注意由于是自身的通信, 本机同时作为服务器和客户端, 服务端需要一个套接口对应, 每个客户端也要有一个套接口对应, 多个客户端的套接口形成一个链表. struct nl_pid_hash { struct hlist_head *table; // 链表节点 unsigned long rehash_time; // 重新计算HASH的时间间隔 unsigned int mask; unsigned int shift; unsigned int entries; // 链表节点数 unsigned int max_shift; // 最大幂值 u32 rnd; // 随机数 }; 其他和netlink数据相关的数据结构在include/linux/netlink.h中定义, 不过这些结构更多用在各具体的netlink对象的实现中, 在基本netlink套接口中到是用得不多。 3. af_netlink协议初始化 static int __init netlink_proto_init(void) { struct sk_buff *dummy_skb; int i; unsigned long max; unsigned int order; // 登记netlink_proto结构, 该结构定义如下: // static struct proto netlink_proto = { // .name = "NETLINK", // .owner = THIS_MODULE, // .obj_size = sizeof(struct netlink_sock), // }; // 最后一个参数为0, 表示不进行slab的分配, 只是简单的将netlink_proto结构 // 挂接到系统的网络协议链表中,这个结构最主要是告知了netlink sock结构的大小 int err = proto_register(&netlink_proto, 0); if (err != 0) goto out; BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)); // 分配MAX_LINKS个netlink表结构 nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); if (!nl_table) goto panic; // 以下根据系统内存大小计算最大链表元素个数 // PAGE_SHIFT是每页大小的2的幂,对i386是12,即每页是4K,2^12 // 对于128M内存的机器,max计算值是(128*1024) >> (21-12) = 256 // 对于64M内存的机器,max计算值是(64*1024) >> (23-12) = 32 if (num_physpages >= (128 * 1024)) max = num_physpages >> (21 - PAGE_SHIFT); else max = num_physpages >> (23 - PAGE_SHIFT); // 根据max再和PAGE_SHIFT计算总内存空间相应的幂值order order = get_bitmask_order(max) - 1 + PAGE_SHIFT; // max是最大节点数 max = (1UL << order) / sizeof(struct hlist_head); // order是max对于2的幂数 order = get_bitmask_order(max > UINT_MAX ? UINT_MAX : max) - 1; for (i = 0; i < MAX_LINKS; i++) { struct nl_pid_hash *hash = &nl_table[i].hash; // 为netlink的每个协议类型分配HASH表链表头 hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table)); if (!hash->table) { while (i-- > 0) nl_pid_hash_free(nl_table[i].hash.table, 1 * sizeof(*hash->table)); kfree(nl_table); goto panic; } // 初始化HASH表参数 memset(hash->table, 0, 1 * sizeof(*hash->table)); // 最大幂数 hash->max_shift = order; hash->shift = 0; hash->mask = 0; hash->rehash_time = jiffies; } // 登记netlink协议族的的操作结构 sock_register(&netlink_family_ops); #ifdef CONFIG_PROC_FS proc_net_fops_create("netlink", 0, &netlink_seq_fops); #endif /* The netlink device handler may be needed early. */ // 初始化路由netlink rtnetlink_init(); ou