对于通用邻居层,我认为主要可以分为三个方面:

1、邻居项处理函数,包括邻居项创建、更新、删除等

2、邻居项的状态机机制,主要是处理邻居项中状态的改变,其中包括几个邻居状态的定时器机制,也包括发送solicit请求等

3、邻居项的垃圾回收机制,主要是负责回收一个邻居表里长时间不用的邻居项,已节省邻居缓存空间。这三个方面需要相互协调工作,才能完成通用邻居层的功能,这一节就分析邻居项的垃圾回收机制。

对于垃圾回收,主要分为2个方面:同步垃圾回收和异步垃圾回收。

异步垃圾回收就是周期的进行垃圾回收,这个是周期性的。而同步垃圾回收机制主要是在创建邻居项而又没有缓存空间时,会调用同步垃圾回收,强制回收无效的邻居缓存。下面介绍

同步垃圾回收处理函数neigh_forced_gc。

       这个函数的逻辑流程还是比较简单的。

该函数的功能是遍历邻接表中hash散列数组中的每一个hash表项中的所有邻接表,

对于邻居项的引用计数为1且状态不是NUD_PERMANENT时,则设置neigh->dead为1,并调用neigh_cleanup_and_release释放

该邻居项占用的缓存。

static int neigh_forced_gc(structneigh_table *tbl)

{

       intshrunk = 0;

       inti;

 

       NEIGH_CACHE_STAT_INC(tbl,forced_gc_runs);

 

       write_lock_bh(&tbl->lock);

       for(i = 0; i <= tbl->hash_mask; i++) {

              structneighbour *n, **np;

 

              np= &tbl->hash_buckets[i];

              while((n = *np) != NULL) {

                     /*Neighbour record may be discarded if:

                      * - nobody refers to it.

                      * - it is not permanent

                      */

                     write_lock(&n->lock);

                     if(atomic_read(&n->refcnt) == 1 &&

                         !(n->nud_state & NUD_PERMANENT)) {

                            *np  = n->next;

                            n->dead= 1;

                            shrunk     = 1;

                            write_unlock(&n->lock);

                            neigh_cleanup_and_release(n);

                            continue;

                     }

                     write_unlock(&n->lock);

                     np= &n->next;

              }

       }

 

       tbl->last_flush= jiffies;

 

       write_unlock_bh(&tbl->lock);

 

       returnshrunk;

}

 

对于异步垃圾回收,在2.6.34里,对于异步垃圾回收的函数实现机制上,进行了调整,

在2.6.21里,是直接使用定时器来实现异步清理的,而在2.6.34里,则是

使用带有定时器功能的工作队列来实现邻居项的内存异步清理的。

 

在2.6.1里,对于异步清理函数,每次定时器到期后,即会扫描邻居表项

中的邻居项hash数组中的一个hash表中的所有邻居表项,对于符合删除条件

的邻居项,则会调用函数neigh_release,释放该邻居项。

符合删除的条件为:

1、neigh->dead == 1

2、neigh->state == NUD_FAILED或者闲置时间超过了指定上限gc_staletime

 

 

而在2.6.34里,异步清理函数neigh_periodic_work每次清理时,会清理邻居表里的邻居

hash数组里所有hash表里的所有邻居项,而不是仅搜索一个hash表里的所有邻居项。

下面介绍同步清理的实际处理函数neigh_periodic_work

1、每隔5分钟,重置一次reachable_time的值,并更新邻居表的last_rand,以便于下次执行更新reach_time操作(而reachable_time用于处于reach状态的邻居项的超时

    时间,这个就是用于NUD_REACHABLE状态下的定时器超时时间,是邻居项状态转换中的定时器处理)

2、遍历邻居表里的邻居hash数组里的每一个hash表里的所有邻居项,执行以下操作:

    a)对于邻居项状态为NUD_PERMANENT或者NUD_IN_TIMER,则遍历下一个邻居项

 b)当邻居项的引用计数为1且状态为NUD_FAILED时,则调用

neigh_cleanup_and_release释放该邻居项占用的缓存

c)当邻居项的引用计数为1且闲置时间超过gc_staletime时,调用neigh_cleanup_and_release释放该邻居项所占用的缓存

3、调用schedule_delayed_work,重启定时器,待定时器超时后则调用queue_work,调用

neigh_periodic_work进行新一轮的异步垃圾回收。

static void neigh_periodic_work(structwork_struct *work)

{

       structneigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);

       structneighbour *n, **np;

       unsignedint i;

 

       NEIGH_CACHE_STAT_INC(tbl,periodic_gc_runs);

 

       write_lock_bh(&tbl->lock);

 

       /*

        *    periodicallyrecompute ReachableTime from random function

        */

 

       if(time_after(jiffies, tbl->last_rand + 300 * HZ)) {

              structneigh_parms *p;

              tbl->last_rand= jiffies;

              for(p = &tbl->parms; p; p = p->next)

                     p->reachable_time=

                            neigh_rand_reach_time(p->base_reachable_time);

       }

 

       for(i = 0 ; i <= tbl->hash_mask; i++) {

              np= &tbl->hash_buckets[i];

 

              while((n = *np) != NULL) {

                     unsignedint state;

 

                     write_lock(&n->lock);

 

                     state= n->nud_state;

                     if(state & (NUD_PERMANENT | NUD_IN_TIMER)) {

                            write_unlock(&n->lock);

                            gotonext_elt;

                     }

 

                     if(time_before(n->used, n->confirmed))

                            n->used= n->confirmed;

 

                     if(atomic_read(&n->refcnt) == 1 &&

                         (state == NUD_FAILED ||

                          time_after(jiffies, n->used +n->parms->gc_staletime))) {

                            *np= n->next;

                            n->dead= 1;

                            write_unlock(&n->lock);

                            neigh_cleanup_and_release(n);

                            continue;

                     }

                     write_unlock(&n->lock);

 

next_elt:

                     np= &n->next;

              }

              /*

               * It's fine to release lock here, even if hashtable

               * grows while we are preempted.

               */

              write_unlock_bh(&tbl->lock);

              cond_resched();

              write_lock_bh(&tbl->lock);

       }

       /*Cycle through all hash buckets every base_reachable_time/2 ticks.

        * ARP entry timeouts range from 1/2base_reachable_time to 3/2

        * base_reachable_time.

        */

       schedule_delayed_work(&tbl->gc_work,

                           tbl->parms.base_reachable_time>> 1);

       write_unlock_bh(&tbl->lock);

}

 

 

至此,完成了通用邻居层的垃圾回收机制的处理功能。

Logo

更多推荐