邻居子系统 之 邻居表的初始化neigh_table_init
概述
邻居子系统支持多种实现,例如ARP,ND等,这些实现需要在其初始化的时候,调用neigh_table_init将邻居表项添加到全局邻居子系统数组中,并对实例中的字段(如hash,定时器等)进行相关初始化;
源码分析
分析过程以ARP为例,引出邻居表的初始化,在arp_init初始化中,调用neigh_table_init来进行邻居表的初始化;其中NEIGH_ARP_TABLE为ARP在全局邻居表数组中的索引值,arp_table则是邻居表的一个实例,里面包含了部分字段的初始化;
1 void __init arp_init(void) 2 { 3 neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl); 4 5 dev_add_pack(&arp_packet_type); 6 arp_proc_init(); 7 #ifdef CONFIG_SYSCTL 8 neigh_sysctl_register(NULL, &arp_tbl.parms, NULL); 9 #endif 10 register_netdevice_notifier(&arp_netdev_notifier); 11 }
索引值是一个枚举类型,从中可见现在已经实现的邻居表项有哪些,其中NEIGH_ARP_TABLE排在第一位;
1 enum { 2 NEIGH_ARP_TABLE = 0, 3 NEIGH_ND_TABLE = 1, 4 NEIGH_DN_TABLE = 2, 5 NEIGH_NR_TABLES, 6 NEIGH_LINK_TABLE = NEIGH_NR_TABLES /* Pseudo table for neigh_xmit */ 7 };
下面为ARP表项实例;
1 struct neigh_table arp_tbl = { 2 .family = AF_INET, 3 .key_len = 4, 4 .protocol = cpu_to_be16(ETH_P_IP), 5 .hash = arp_hash, 6 .key_eq = arp_key_eq, 7 .constructor = arp_constructor, 8 .proxy_redo = parp_redo, 9 .id = "arp_cache", 10 .parms = { 11 .tbl = &arp_tbl, 12 .reachable_time = 30 * HZ, 13 .data = { 14 [NEIGH_VAR_MCAST_PROBES] = 3, 15 [NEIGH_VAR_UCAST_PROBES] = 3, 16 [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, 17 [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, 18 [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, 19 [NEIGH_VAR_GC_STALETIME] = 60 * HZ, 20 [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024, 21 [NEIGH_VAR_PROXY_QLEN] = 64, 22 [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, 23 [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, 24 [NEIGH_VAR_LOCKTIME] = 1 * HZ, 25 }, 26 }, 27 .gc_interval = 30 * HZ, 28 .gc_thresh1 = 128, 29 .gc_thresh2 = 512, 30 .gc_thresh3 = 1024, 31 };
每个邻居表实例都需要通过调用neigh_table_init进行初始化,并将其加入到全局邻居表数组中;函数首先对邻居表项中的参数进行初始化,其中包括了初始化邻居项hash和代理项hash,初始化垃圾回收GC任务和代理处理定时器任务,以及一些其他必要字段,最后将该邻居表项实例加入到全局数组neigh_tables中;
1 void neigh_table_init(int index, struct neigh_table *tbl) 2 { 3 unsigned long now = jiffies; 4 unsigned long phsize; 5 6 /* 初始化参数列表 */ 7 INIT_LIST_HEAD(&tbl->parms_list); 8 /* 将参数添加到参数列表 */ 9 list_add(&tbl->parms.list, &tbl->parms_list); 10 /* 设置net */ 11 write_pnet(&tbl->parms.net, &init_net); 12 /* 设置引用计数 */ 13 atomic_set(&tbl->parms.refcnt, 1); 14 /* 设置可达状态的超时时间 */ 15 tbl->parms.reachable_time = 16 neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME)); 17 /* 统计信息 */ 18 tbl->stats = alloc_percpu(struct neigh_statistics); 19 if (!tbl->stats) 20 panic("cannot create neighbour cache statistics"); 21 22 /* 初始化proc */ 23 #ifdef CONFIG_PROC_FS 24 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat, 25 &neigh_stat_seq_fops, tbl)) 26 panic("cannot create neighbour proc dir entry"); 27 #endif 28 29 /* 初始化邻居项hash */ 30 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3)); 31 32 /* 初始化代理项hash */ 33 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *); 34 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL); 35 36 if (!tbl->nht || !tbl->phash_buckets) 37 panic("cannot allocate neighbour cache hashes"); 38 39 /* 邻居项的结构大小 */ 40 if (!tbl->entry_size) 41 tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) + 42 tbl->key_len, NEIGH_PRIV_ALIGN); 43 else 44 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN); 45 46 rwlock_init(&tbl->lock); 47 /* gc任务初始化 */ 48 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work); 49 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work, 50 tbl->parms.reachable_time); 51 52 /* 代理定时器处理初始化 */ 53 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); 54 skb_queue_head_init_class(&tbl->proxy_queue, 55 &neigh_table_proxy_queue_class); 56 57 /* 初始化最近一次gc的时间 */ 58 tbl->last_flush = now; 59 /* 初始化最近一次可达状态reachable_time的更新时间 */ 60 tbl->last_rand = now + tbl->parms.reachable_time * 20; 61 62 /* 加入全局邻居项数组 */ 63 neigh_tables[index] = tbl; 64 }