Linux 路由 学习笔记 之四 路由删除流程分析

上面几节分析了路由的添加与查找,本节开始分析路由的删除。

分析了这么多linuxkernel功能模块,对于功能模块的大致实现流程,我们也比较熟悉了,无非是状态机、数据结构(以及数据之间的关系,通过链表等实现)、垃圾处理等。但是对于ipv4来说,既有路由项相关的数据结构,也有路由缓存相关的数据结构,通过这两个数据结构的名称,我们也可以看出来,路由项应该是没有垃圾回收机制的,不然的话路由缓存应该就没有存在的必要了吧。因此对于路由项的删除,一般是应用层通过命令删除的,kernel不会自动删除路由项的。

对于应用层的删除命令,就是通过socket来实现的。例如通过SIOCDELRT删除路由项,应用层的命令基本上都是通过调用ip_rt_ioctl、inet_rtm_delroute来实现的。

1.路由删除的步骤

在分析相应的函数之前,我们先来分析一下,删除一个路由项需要哪些步骤呢?

a通过输入参数,找到相应的路由表

b在相应的路由表,找到相应的路由项

c删除该路由项,且需要将该路由项上相对应的路由缓存删除掉

下面我们就开始分析删除实现的流程。在函数ip_rt_ioctl、inet_rtm_delroute均会先调用函数fib_get_table找到对应的路由表,接着就调用路由表对应的删除函数,删除对应的路由项,即tb->tb_delete。对于ipv4即为函数fn_hash_delete

1.1fn_hash_delete

下面分析这个函数,这个函数即从路由表中删除一个路由项。

1.根据网络掩码长度获取相应的fn_zone变量,

若该变量为NULL,则程序返回错误;

若该变量不为0,则执行2。

2.对目的地址进行合法性检测,并调用函数fz_key构造查找关键字key

3.根据搜索关键字key与fn_zone,调用fib_find_node查找符合条件的fib_node

a)若没有查找到符合条件的fib_node结构变量,则程序返回错误

b)若查找到了,则执行4

4.调用函数fib_find_alias查找符合条件的fib_alias

a)若没有查找到,则程序返回错误

b)若查找到则执行5

5.从查找到的fib_alias处开始遍历余下所有的fib_alias,精确匹配要删除的路由项

查找到以后:

a)将该fib_alias从fib_node->fn_alias链表中删除

b)若从fib_node->fn_alias链表中删除当前fib_alias后,fib_node->fn_alias为空,则同时需要从fn_zone->fz_hash链表数组中删除该fib_node节点;若fib_node->fn_alias不为空,则执行

c)若该fib_alias在路由查找中,被查找匹配过,则需要调用函数rt_cache_flush刷新路由缓存

d)调用函数fn_free_alias释放该fib_alias变量占用的缓存,并调用函数fib_release_info准备释放该fib_alias变量包含的fib_info变量

e)在函数fib_release_info里,会结合fib_treeref与fib_prefsrc的值来决定是否释放fib_info占用的内存

staticintfn_hash_delete(structfib_table*tb,structfib_config*cfg)

{

structfn_hash*table=(structfn_hash*)tb->tb_data;

structfib_node*f;

structfib_alias*fa,*fa_to_delete;

structfn_zone*fz;

__be32key;

/*判断掩码的长度是否有效*/

if(cfg->fc_dst_len>32)

return-EINVAL;

if((fz=table->fn_zones[cfg->fc_dst_len])==NULL)

return-ESRCH;

key=0;

if(cfg->fc_dst){

if(cfg->fc_dst&~FZ_MASK(fz))

return-EINVAL;

key=fz_key(cfg->fc_dst,fz);

}

f=fib_find_node(fz,key);

if(!f)

fa=NULL;

else

fa=fib_find_alias(&f->fn_alias,cfg->fc_tos,0);

if(!fa)

return-ESRCH;

fa_to_delete=NULL;

fa=list_entry(fa->fa_list.prev,structfib_alias,fa_list);

list_for_each_entry_continue(fa,&f->fn_alias,fa_list){

structfib_info*fi=fa->fa_info;

if(fa->fa_tos!=cfg->fc_tos)

break;

if((!cfg->fc_type||

fa->fa_type==cfg->fc_type)&&

(cfg->fc_scope==RT_SCOPE_NOWHERE||

fa->fa_scope==cfg->fc_scope)&&

(!cfg->fc_protocol||

fi->fib_protocol==cfg->fc_protocol)&&

fib_nh_match(cfg,fi)==0){

fa_to_delete=fa;

break;

}

}

if(fa_to_delete){

intkill_fn;

fa=fa_to_delete;

rtmsg_fib(RTM_DELROUTE,key,fa,cfg->fc_dst_len,

tb->tb_id,&cfg->fc_nlinfo);

kill_fn=0;

write_lock_bh(&fib_hash_lock);

list_del(&fa->fa_list);

if(list_empty(&f->fn_alias)){

hlist_del(&f->fn_hash);

kill_fn=1;

}

fib_hash_genid++;

write_unlock_bh(&fib_hash_lock);

/*若fib_alias->fa_state的FA_S_ACCESSED位为1,则说明该fib_alias被访问过,

因此需要调用函数rt_cache_flush,刷新路由缓存,以便删除该路

由项对应的路由缓存*/

if(fa->fa_state&FA_S_ACCESSED)

rt_cache_flush(-1);

fn_free_alias(fa);

if(kill_fn){

fn_free_node(f);

fz->fz_nent–;

}

return0;

}

return-ESRCH;

}

这个函数调用了几个查找函数,下面分析下这几个函数

1.2fib_find_node

功能:根据搜索关键字,在fn_zone变量fz中查找符合条件的fib_node变量

1.调用fn_hash,根据搜索关键字与fn_zone变量计算hash值为hash_index

2.根据hash值hash_index获取到hash链表的头部

3.调用函数hlist_for_each_entry遍历该链表,查找fib_node->fn_key等于传入的fn_zone,

若查找到则返回该fib_node变量;若没有找到返回NULL

staticstructfib_node*fib_find_node(structfn_zone*fz,__be32key)

{

structhlist_head*head=&fz->fz_hash[fn_hash(key,fz)];

structhlist_node*node;

structfib_node*f;

hlist_for_each_entry(f,node,head,fn_hash){

if(f->fn_key==key)

returnf;

}

returnNULL;

}

1.3fib_find_alias

功能:根据tos、priority查找符匹配的fib_alias变量

1.遍历链表fah,查找tos小于传递的tos,且fib_priority大于或等于传递的prio的fib_alias变量

structfib_alias*fib_find_alias(structlist_head*fah,u8tos,u32prio)

{

if(fah){

structfib_alias*fa;

list_for_each_entry(fa,fah,fa_list){

if(fa->fa_tos>tos)

continue;

if(fa->fa_info->fib_priority>=prio||

fa->fa_tos<tos)

returnfa;

}

}

returnNULL;

}

1.4fn_free_alias

功能:释放一个fib_alias结构的变量占用的缓存,并释放其关联的fib_info结构的变量

staticinlinevoidfn_free_alias(structfib_alias*fa)

{

fib_release_info(fa->fa_info);

kmem_cache_free(fn_alias_kmem,fa);

}

1.5fn_free_node

功能:释放一个fib_node结构的变量占用的缓存

staticinlinevoidfn_free_node(structfib_node*f)

{

kmem_cache_free(fn_hash_kmem,f);

}

以上就是路由删除的主要分析流程,路由删除相关的流程函数比较简单的,只要理解了路由项相关的数据结构,基本上对于路由删除的操作,就一目了然了。

后面准备先分析策略规则相关的流程,分析策略规则后,则开始分析路由缓存模块,等到这些功能模块都分析完了以后,对于kernel协议栈的分析也就算告一段落了。

而是他们在同伴们都睡着的时候,一步步艰辛地

Linux 路由 学习笔记 之四 路由删除流程分析

相关文章:

你感兴趣的文章:

标签云: