邻居节点相关的操作:
查找到路由后,会调用arp_bind_neighbour绑定一个邻居项
int
arp_bind_neighbour(struct dst_entry *dst)
{
struct net_device *dev = dst->dev;
struct neighbour *n = dst->neighbour;
if (dev == NULL)
return -EINVAL;
//如果这个邻居不存在,则执行__neigh_lookup_errno
if (n == NULL) {
__be32 nexthop = ((struct
rtable*)dst)->rt_gateway;
if
(dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
nexthop = 0;
n = __neigh_lookup_errno(
//ATM网络和以太网络调用了不同的neigh_table,作为以太网络将调用&arp_tbl作为neigh_table的入口
#if
defined(CONFIG_ATM_CLIP) ||
defined(CONFIG_ATM_CLIP_MODULE)
dev->type == ARPHRD_ATM ? clip_tbl_hook :
#endif
&arp_tbl, &nexthop,
dev);
if (IS_ERR(n))
return PTR_ERR(n);
dst->neighbour = n;
}
return 0;
}
__neigh_lookup_errno函数
static
inline struct neighbour *
__neigh_lookup_errno(struct neigh_table *tbl, const void
*pkey,
struct net_device
*dev)
{
//在邻居表中查找邻居项,如果不存在,则新建一项
struct neighbour *n = neigh_lookup(tbl, pkey, dev);
if (n)
return n;
//新建邻居项
return neigh_create(tbl, pkey, dev);
}
neigh_lookup函数
struct neighbour *neigh_lookup(struct neigh_table
*tbl, const void *pkey,
struct net_device *dev)
{
struct neighbour *n;
int key_len = tbl->key_len;
u32 hash_val = tbl->hash(pkey, dev);
NEIGH_CACHE_STAT_INC(tbl, lookups);
read_lock_bh(&tbl->lock);
//以下代码可以看出,通过指定的neigh_table入口,找到hash_buckets,
//因为所有的neighbour链表是经过哈希的,所以再通过传入的哈希值作为
//下标最后找到链表头,然后在往下遍历,直到找到相对应的neighbour结构
//为止
for (n = tbl->hash_buckets[hash_val
& tbl->hash_mask]; n; n =
n->next) {
if (dev == n->dev &&
!memcmp(n->primary_key, pkey, key_len)) {
neigh_hold(n);
NEIGH_CACHE_STAT_INC(tbl, hits);
break;
}
}
read_unlock_bh(&tbl->lock);
return n;
}
如果到邻居表中寻找对应的邻居项,如果不存在,则新建一项。继续跟进调用neigh_create函数
struct
neighbour *neigh_create(struct neigh_table *tbl, const void
*pkey,
struct net_device *dev)
{
u32 hash_val;
int key_len = tbl->key_len;
int error;
struct neighbour *n1, *rc, *n = neigh_alloc(tbl);
if (!n) {
rc = ERR_PTR(-ENOBUFS);
goto out;
}
//每个neighbour的哈希就是在这里计算的,实际上我们可以看出,
//所谓的哈希值就是目的IP
memcpy(n->primary_key, pkey, key_len);
n->dev = dev;
dev_hold(dev);
if (tbl->constructor
&& (error =
tbl->constructor(n)) < 0)
{
rc = ERR_PTR(error);
goto out_neigh_release;
}
if (n->parms->neigh_setup
&&
(error = n->parms->neigh_setup(n))
< 0) {
rc = ERR_PTR(error);
goto out_neigh_release;
}
n->confirmed = jiffies -
(n->parms->base_reachable_time
<< 1);
write_lock_bh(&tbl->lock);
if (atomic_read(&tbl->entries)
> (tbl->hash_mask + 1))
neigh_hash_grow(tbl, (tbl->hash_mask + 1)
<< 1);
hash_val = tbl->hash(pkey, dev) &
tbl->hash_mask;
if (n->parms->dead) {
rc = ERR_PTR(-EINVAL);
goto out_tbl_unlock;
}
//查找所添加的邻居是否已经存在
for (n1 = tbl->hash_buckets[hash_val]; n1; n1 =
n1->next) {
if (dev == n1->dev
&&
!memcmp(n1->primary_key, pkey, key_len))
{
neigh_hold(n1);
rc = n1;
goto out_tbl_unlock;
}
}
n->next =
tbl->hash_buckets[hash_val];
tbl->hash_buckets[hash_val] = n;
n->dead = 0;
neigh_hold(n);
write_unlock_bh(&tbl->lock);
NEIGH_PRINTK2("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;
}