邻居子系统 之 邻居表的初始化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 }
原文地址:https://www.cnblogs.com/wanpengcoder/p/11755380.html