Linux内核分析 - 网络[九]:邻居表
neigh_lookup 查找 ARP表项 查找函数很简单,以IP地址和网卡设备(即pkey和dev)计算哈希值hash_val,然后在tbl->hash_buckets查找相应 项。 hash_val = tbl->hash(pkey, dev); 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; } } 代理ARP 代理ARP的相关知识查阅google。要明确代理ARP功能是针对陆由器的(或者说是具有转发功能的主机)。开 启ARP代理后,会对查询不在本网段的ARP请求包回应。 回到之前的arp_process代码,处理代理ARP的情况,这实际就是进行 代理ARP的条件,IN_DEV_FORWARD是支持转发,RTN_UNICAST是与路由直连,arp_fwd_proxy表示设备支持代理行为, arp_fwd_pvlan表示支持代理同设备进出,pneigh_lookup表示目的地址的代理。这两种arp_fwd_proxy和arp_fwd_pvlan都只是网 卡设备的一种性质,pneigh_lookup则是一张代理邻居表,它的内容都是手动添加或删除的,三种策略任一一种满足都可以进行 代理ARP。 else if (IN_DEV_FORWARD(in_dev)) { if (addr_type == RTN_UNICAST && (arp_fwd_proxy(in_dev, dev, rt) || arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) pneigh_lookup 查找或添加代理邻居表项[proxy neighbour] 以[pkey=tip, key_len=4]计算hash值,执行__pneigh_lookup_1在phash_buckets中查找。 u32 hash_val = pneigh_hash(pkey, key_len); n = __pneigh_lookup_1(tbl->phash_buckets[hash_val], net, pkey, key_len, dev); 如果在phash_buckets中查 找到,或者不需要创建新表项,则函数返回,此时它的功能仅仅是lookup。 if (n || !creat) goto out; 而当传入参数create=1时,则它的功能不仅是lookup,还会在表项不存在时create。同neighbour结构一样 ,键值pkey存储在pneigh结构的后面,这样当pkey变化时,修改十分容易。创建操作很直观,为pneigh和pkey分配空间,初始化 些变量,最后插入phash_buckets。 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL); …… write_pnet(&n->net, hold_net(net)); memcpy(n->key, pkey, key_len); …… n->next = tbl->phash_buckets[hash_val]; tbl->phash_buckets[hash_val] = n; pneigh_enqueue 将报文加入代理队列 首先计算下次调度的时间,这是一 个随机值,记录到sched_next中;设置flags|=LOCALLY_ENQUEUED表明报文是本地加入的。 unsigned long sched_next = now + (net_random() % p->proxy_delay); …… NEIGH_CB(skb)->sched_next = sched_next; NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED; 然后将报文加入proxy_queue,并设置定时器proxy_timer,下次超 时时间为刚计算的值sched_next,这样,下次超时时就会处理proxy_queue队列中的报文。 __skb_queue_tail (&tbl->proxy_queue, skb); mod_timer(&tbl->proxy_timer, sched_next); 这里的tbl当然是arp_tbl,它的proxy_timer是在初始化时设置 的arp_init() -> neigh_table_init_no_netlink()中: setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); neigh_proxy_process 代理ARP的定时器 skb_queue_walk_safe如同 for循环一样,它遍历proxy_queue,一个个取出其中的报文skb,查看报文的调度时间sched_next与当前时间now的差值。 如 果tdif<=0则表明调度时间已到或已过,报文要被处理了,从proxy_queue上取出该报文,调用tbl->proxy_redo重新发送 报文,tbl->proxy_redo也是在arp初始化时赋值的,实际上就是arp_process()函数。结合上面的分析,它会执行 arp_process中代理ARP处理的else部分,发送响应报文。 如果tdif>0则表明调度时间还未到,else if部分的功能就是记 录下最近要过期的调度时间到sched_next。 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) { long tdif = NEIGH_CB(skb)->sched_next - now; if (tdif <= 0) { struct net_device *dev = skb->dev; __skb_unlink(skb, &tbl->proxy_queue); if (tbl->proxy_redo && netif_running(dev)) tbl->proxy_redo(skb); else kfree_skb(skb); dev_put(dev); } else if (!sched_next || tdif < sched_next) sched_next = tdif; } (编辑:应用网_丽江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |