邻居子系统 之 邻居项创建__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", 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!\n", 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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!