邻居子系统 之 邻居项创建__neigh_create

概述

IP层输出数据包会根据路由的下一跳查询邻居项,如果不存在则会调用__neigh_create创建邻居项,然后调用邻居项的output函数进行输出;

__neigh_create完成邻居项的创建,进行初始化之后,加入到邻居项hash表,然后返回,其中,如果hash表中有与新建邻居项相同的项会复用该项,新建项会被释放;

neigh_alloc完成邻居项的分配,分配成功后会设定定时器来检查和更新邻居项的状态;

源码分析
  1 struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
  2                  struct net_device *dev, bool want_ref)
  3 {
  4     u32 hash_val;
  5     int key_len = tbl->key_len;
  6     int error;
  7     /* 分配邻居项n */
  8     struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
  9     struct neigh_hash_table *nht;
 10 
 11     if (!n) {
 12         rc = ERR_PTR(-ENOBUFS);
 13         goto out;
 14     }
 15 
 16     /* 拷贝主键值,ipv4为下一跳ip地址 */
 17     memcpy(n->primary_key, pkey, key_len);
 18     /* 设置输出设备 */
 19     n->dev = dev;
 20     dev_hold(dev);
 21 
 22     /* Protocol specific setup. */
 23     /* 执行邻居表的邻居项初始化函数,ARP为arp_constructor */
 24     if (tbl->constructor &&    (error = tbl->constructor(n)) < 0) {
 25         rc = ERR_PTR(error);
 26         goto out_neigh_release;
 27     }
 28 
 29     /* 执行设备的邻居项初始化 */
 30     if (dev->netdev_ops->ndo_neigh_construct) {
 31         error = dev->netdev_ops->ndo_neigh_construct(dev, n);
 32         if (error < 0) {
 33             rc = ERR_PTR(error);
 34             goto out_neigh_release;
 35         }
 36     }
 37 
 38     /* Device specific setup. */
 39     /* 老式设备的邻居项初始化 */
 40     if (n->parms->neigh_setup &&
 41         (error = n->parms->neigh_setup(n)) < 0) {
 42         rc = ERR_PTR(error);
 43         goto out_neigh_release;
 44     }
 45 
 46     /* 设置邻居项的确认时间 */
 47     n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
 48 
 49     write_lock_bh(&tbl->lock);
 50 
 51     /* 获取hash */
 52     nht = rcu_dereference_protected(tbl->nht,
 53                     lockdep_is_held(&tbl->lock));
 54 
 55     /* hash扩容 */
 56     if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
 57         nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
 58 
 59     /* 计算hash值 */
 60     hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
 61 
 62     /* 邻居项的配置参数正在被删除,不能继续初始化 */
 63     if (n->parms->dead) {
 64         rc = ERR_PTR(-EINVAL);
 65         goto out_tbl_unlock;
 66     }
 67 
 68     /* 遍历hash */
 69     for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
 70                         lockdep_is_held(&tbl->lock));
 71          n1 != NULL;
 72          n1 = rcu_dereference_protected(n1->next,
 73             lockdep_is_held(&tbl->lock))) {
 74         /* 找到相同的邻居项,则使用之 */
 75         if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
 76             if (want_ref)
 77                 neigh_hold(n1);
 78             rc = n1;
 79             /* 解锁,释放新的邻居项 */
 80             goto out_tbl_unlock;
 81         }
 82     }
 83 
 84     /* 不存在,则添加新邻居项到hash */
 85     n->dead = 0;
 86     if (want_ref)
 87         neigh_hold(n);
 88     rcu_assign_pointer(n->next,
 89                rcu_dereference_protected(nht->hash_buckets[hash_val],
 90                              lockdep_is_held(&tbl->lock)));
 91     rcu_assign_pointer(nht->hash_buckets[hash_val], n);
 92     write_unlock_bh(&tbl->lock);
 93     neigh_dbg(2, "neigh %p is created
", n);
 94 
 95     /* 返回新的邻居项 */
 96     rc = n;
 97 out:
 98     return rc;
 99 out_tbl_unlock:
100     write_unlock_bh(&tbl->lock);
101 out_neigh_release:
102     neigh_release(n);
103     goto out;
104 }
 1 static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
 2 {
 3     struct neighbour *n = NULL;
 4     unsigned long now = jiffies;
 5     int entries;
 6 
 7     /* 增加并返回邻居项数量 */
 8     entries = atomic_inc_return(&tbl->entries) - 1;
 9 
10     /* 超过限额,则进行回收 */
11     if (entries >= tbl->gc_thresh3 ||
12         (entries >= tbl->gc_thresh2 &&
13          time_after(now, tbl->last_flush + 5 * HZ))) {
14         if (!neigh_forced_gc(tbl) &&
15             entries >= tbl->gc_thresh3) {
16             net_info_ratelimited("%s: neighbor table overflow!
",
17                          tbl->id);
18             NEIGH_CACHE_STAT_INC(tbl, table_fulls);
19             goto out_entries;
20         }
21     }
22 
23     /* 分配邻居项 */
24     n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
25     if (!n)
26         goto out_entries;
27 
28     /* 成员初始化 */
29     __skb_queue_head_init(&n->arp_queue);
30     rwlock_init(&n->lock);
31     seqlock_init(&n->ha_lock);
32     n->updated      = n->used = now;
33     n->nud_state      = NUD_NONE;
34     n->output      = neigh_blackhole;
35     seqlock_init(&n->hh.hh_lock);
36     n->parms      = neigh_parms_clone(&tbl->parms);
37 
38     /* 设置定时器,检查和调整邻居项状态 */
39     setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
40 
41     NEIGH_CACHE_STAT_INC(tbl, allocs);
42 
43     /* 关联邻居表 */
44     n->tbl          = tbl;
45     atomic_set(&n->refcnt, 1);
46     n->dead          = 1;
47 out:
48     return n;
49 
50 out_entries:
51     atomic_dec(&tbl->entries);
52     goto out;
53 }
原文地址:https://www.cnblogs.com/wanpengcoder/p/11755385.html