• 邻居子系统 之 邻居项创建__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 }
  • 相关阅读:
    无序数组求第K大/第K小的数
    [洛谷][二分搜索]进击的奶牛
    [015]向下类型转换和向上类型转换
    [014]析构函数为虚函数的注意事项
    [013]函数重载--int*和void*的匹配优先级
    [012]链表笔记--在链表中插入一个节点
    [011]链表笔记--删除一个链表节点
    [002]链表笔记--编程实现一个单链表的创建/测长/打印
    [C++]对象的销毁机制
    [011]默认实参
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11755385.html
Copyright © 2020-2023  润新知