邻居子系统 之 邻居项创建__neigh_create
2024-10-06 22:53:23
概述
IP层输出数据包会根据路由的下一跳查询邻居项,如果不存在则会调用__neigh_create创建邻居项,然后调用邻居项的output函数进行输出;
__neigh_create完成邻居项的创建,进行初始化之后,加入到邻居项hash表,然后返回,其中,如果hash表中有与新建邻居项相同的项会复用该项,新建项会被释放;
neigh_alloc完成邻居项的分配,分配成功后会设定定时器来检查和更新邻居项的状态;
源码分析
struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
struct net_device *dev, bool want_ref)
{
u32 hash_val;
int key_len = tbl->key_len;
int error;
/* 分配邻居项n */
struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
struct neigh_hash_table *nht; if (!n) {
rc = ERR_PTR(-ENOBUFS);
goto out;
} /* 拷贝主键值,ipv4为下一跳ip地址 */
memcpy(n->primary_key, pkey, key_len);
/* 设置输出设备 */
n->dev = dev;
dev_hold(dev); /* Protocol specific setup. */
/* 执行邻居表的邻居项初始化函数,ARP为arp_constructor */
if (tbl->constructor && (error = tbl->constructor(n)) < ) {
rc = ERR_PTR(error);
goto out_neigh_release;
} /* 执行设备的邻居项初始化 */
if (dev->netdev_ops->ndo_neigh_construct) {
error = dev->netdev_ops->ndo_neigh_construct(dev, n);
if (error < ) {
rc = ERR_PTR(error);
goto out_neigh_release;
}
} /* Device specific setup. */
/* 老式设备的邻居项初始化 */
if (n->parms->neigh_setup &&
(error = n->parms->neigh_setup(n)) < ) {
rc = ERR_PTR(error);
goto out_neigh_release;
} /* 设置邻居项的确认时间 */
n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << ); write_lock_bh(&tbl->lock); /* 获取hash */
nht = rcu_dereference_protected(tbl->nht,
lockdep_is_held(&tbl->lock)); /* hash扩容 */
if (atomic_read(&tbl->entries) > ( << nht->hash_shift))
nht = neigh_hash_grow(tbl, nht->hash_shift + ); /* 计算hash值 */
hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> ( - nht->hash_shift); /* 邻居项的配置参数正在被删除,不能继续初始化 */
if (n->parms->dead) {
rc = ERR_PTR(-EINVAL);
goto out_tbl_unlock;
} /* 遍历hash */
for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
lockdep_is_held(&tbl->lock));
n1 != NULL;
n1 = rcu_dereference_protected(n1->next,
lockdep_is_held(&tbl->lock))) {
/* 找到相同的邻居项,则使用之 */
if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
if (want_ref)
neigh_hold(n1);
rc = n1;
/* 解锁,释放新的邻居项 */
goto out_tbl_unlock;
}
} /* 不存在,则添加新邻居项到hash */
n->dead = ;
if (want_ref)
neigh_hold(n);
rcu_assign_pointer(n->next,
rcu_dereference_protected(nht->hash_buckets[hash_val],
lockdep_is_held(&tbl->lock)));
rcu_assign_pointer(nht->hash_buckets[hash_val], n);
write_unlock_bh(&tbl->lock);
neigh_dbg(, "neigh %p is created\n", n); /* 返回新的邻居项 */
rc = n;
out:
return rc;
out_tbl_unlock:
write_unlock_bh(&tbl->lock);
out_neigh_release:
neigh_release(n);
goto out;
}
static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
{
struct neighbour *n = NULL;
unsigned long now = jiffies;
int entries; /* 增加并返回邻居项数量 */
entries = atomic_inc_return(&tbl->entries) - ; /* 超过限额,则进行回收 */
if (entries >= tbl->gc_thresh3 ||
(entries >= tbl->gc_thresh2 &&
time_after(now, tbl->last_flush + * HZ))) {
if (!neigh_forced_gc(tbl) &&
entries >= tbl->gc_thresh3) {
net_info_ratelimited("%s: neighbor table overflow!\n",
tbl->id);
NEIGH_CACHE_STAT_INC(tbl, table_fulls);
goto out_entries;
}
} /* 分配邻居项 */
n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
if (!n)
goto out_entries; /* 成员初始化 */
__skb_queue_head_init(&n->arp_queue);
rwlock_init(&n->lock);
seqlock_init(&n->ha_lock);
n->updated = n->used = now;
n->nud_state = NUD_NONE;
n->output = neigh_blackhole;
seqlock_init(&n->hh.hh_lock);
n->parms = neigh_parms_clone(&tbl->parms); /* 设置定时器,检查和调整邻居项状态 */
setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n); NEIGH_CACHE_STAT_INC(tbl, allocs); /* 关联邻居表 */
n->tbl = tbl;
atomic_set(&n->refcnt, );
n->dead = ;
out:
return n; out_entries:
atomic_dec(&tbl->entries);
goto out;
}
最新文章
- opencart邮件模板
- first root
- MyBatis 多表联合查询及优化 以及自定义返回结果集
- Android Service with Delphi 10 Seattle
- [综合|基础|语法] 最新的皮肤帮助类 UI_Misc_Helper (转载)
- elasticsearch中国字(mmseg)——手动添加字典
- jquery层次选择器:空格 > next + nextAll ~ siblings
- win10 删除设备和驱动器中你不要的图标
- 彻底理解线程同步与同步代码块synchronized
- Dynamics CRM2016 WebApi查询之alternate key
- Inno Setup打包带有MSI文件的程序
- 对比JavaScript中的Continue和Break
- Redis 5种数据结构
- Bi-shoe and Phi-shoe (欧拉函数)
- esp8266(2) 智能配置
- mysql替换字符串
- css-文字和图片在容器内垂直居中的简单方法
- xcode调试查看变量的值
- System.DateTime.Now.ToString(";yyyy-MM-dd HH:mm:ss";) 显示24小时制;System.DateTime.Now.ToString(";yyyy-MM-dd hh:mm:ss";)显示12小时制
- Strings in the Pocket(马拉车+字符串判断)