歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

linux協議棧之鄰居子系統(相關流程三)

在前面已經分析過,查找到路由後,會調用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;

//如果鄰居項不存在

if (n == NULL) {

u32 nexthop = ((struct rtable*)dst)->rt_gateway;

if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))

nexthop = 0;

n = __neigh_lookup_errno(

#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()

__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);

}

從上面可以看到,它會先到鄰居表中尋找對應的鄰居項,如果不存在,則新建一項。繼續跟進

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;

}

//從此可以看到,哈希鍵值就是目的IP

memcpy(n->primary_key, pkey, key_len);

n->dev = dev;

dev_hold(dev);



/* Protocol specific setup. */

//初始化函數

if (tbl->constructor && (error = tbl->constructor(n)) < 0) {

rc = ERR_PTR(error);

goto out_neigh_release;

}



/* Device specific setup. */

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);



//如果總數超過了hash_mask +1,則增長哈希表

if (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;

}

在函數裡,會調用tbl->constructor()進行初始化。在arp_tbl結構中,為constructor賦值為arp_constructor。

static int arp_constructor(struct neighbour *neigh)

{

u32 addr = *(u32*)neigh->primary_key;

struct net_device *dev = neigh->dev;

struct in_device *in_dev;

struct neigh_parms *parms;



neigh->type = inet_addr_type(addr);



rcu_read_lock();

in_dev = rcu_dereference(__in_dev_get(dev));

if (in_dev == NULL) {

rcu_read_unlock();

return -EINVAL;

}



parms = in_dev->arp_parms;

__neigh_parms_put(neigh->parms);

Copyright © Linux教程網 All Rights Reserved