Chinaunix

标题: fn_hash_select_default函数的疑问2 [打印本页]

作者: jiufei19    时间: 2016-12-26 17:09
标题: fn_hash_select_default函数的疑问2
本帖最后由 jiufei19 于 2016-12-28 17:01 编辑

前一篇帖子http://bbs.chinaunix.net/thread-4257706-1-1.html,我谈到了一个问题,后来基本解决,下面我再谈谈这个函数的逻辑处理中我无法理解的问题。

首先,无论有多少个缺省路由设置,在内核路由表中始终都只有一个fib_node结点对应缺省路由。然后我们假定该fib_node下有3个fib_alias结点,分别为fib_alias2~fib_alias4,并且假设每个fib_alias都有自己的独立fib_info对象,而每个fib_info中都有一个fib_nh对象。

其次,fib_alias结点按其fa_tos的降序进行排序,而具有相同fa_tos的fib_alias按各自下属fib_info的fib_priority的升序排列。

再次,假定fib_alias2~fib_alias4的tos分别为:tos2,tos2,tos4,即fib_alias2和fib_alias3的tos相同。
再次,由于每次路由查询fib_lookup总是返回首个符合要求的res,而由于fib_alias按tos降序排列,并在tos相同时按fib_priority升序排列,因此这里的res应该对应fib_alias2结点。

再次,假定每个fib_info的优先级分别为fib_priority2~fib_priority4,并且有fib_priority3大于fib_priority2。

再次,假定执行fn_hash_select_default之前,其他线程刚好添加了一条新的缺省路由器,即fib_alias1,我们假定fib_alias1的tos大于fib_alias2~fib_alias4,并包含下属fib_info1,其优先级为fib_priority1。

下面,fn_hash_select_default函数的如下红色代码就很难理解了:

   298     hlist_for_each_entry(f, node, &fz->fz_hash[0], fn_hash) {
   299         struct fib_alias *fa;
   300
   301         list_for_each_entry(fa, &f->fn_alias, fa_list) {
   302             struct fib_info *next_fi = fa->fa_info;
   303
   304             if (fa->fa_scope != res->scope ||
   305                 fa->fa_type != RTN_UNICAST)
   306                 continue;
   307
   308             if (next_fi->fib_priority > res->fi->fib_priority)
   309                 break;
   310             if (!next_fi->fib_nh[0].nh_gw ||
   311                 next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
   312                 continue;
   313             fa->fa_state |= FA_S_ACCESSED;
   314
   315             if (fi == NULL) {
   316                 if (next_fi != res->fi)        
   317                     break;



  我们以第308-309行为例进行说明,由于在第301行是按当前fib_node的下属fib_alias结点链表进行遍历的,所以应该从首个fib_alias1开始进行处理,而不是从fib_alias2进行处理,而我们假设fib_alias1的优先级属性,即next_fi->fib_priority比res->fi->fib_priority大,那么这里就立刻break了,即跳出第301行的遍历,不再检查后续fib_alias2~fib_alias4,显然这个处理逻辑太让人费解了,这到底是啥意思???





作者: jiufei19    时间: 2016-12-27 10:49
本帖最后由 jiufei19 于 2016-12-27 22:41 编辑

回复 1# jiufei19

昨天仔细思考了下,这个问题看来只能有一个理由可以解释,即对于缺省路由,是没有tos设置的,如果我的这个猜测正确的话,则可以解释fn_hash_select_default函数不对tos进行判断,而直接就是对fib_priority进行检查的原因了。



假设第301的遍历操作找到一个fib_alias,并且next_fi->fib_priority小于res->fi->fib_priority,则此时第316行的if条件必然不成立,如下红色代码所示:

301         list_for_each_entry(fa, &f->fn_alias, fa_list) {
   302             struct fib_info *next_fi = fa->fa_info;
   ...                ...
   307
   308             if (next_fi->fib_priority > res->fi->fib_priority)
   309                 break;

   ...               ...
   315             if (fi == NULL) {
  316                 if (next_fi != res->fi)         
   317                     break;
   318             } else if (!fib_detect_death(fi, order, &last_resort,
   319                              &last_idx, &fn_hash_last_dflt)) {
   320                 if (res->fi)
   321                     fib_info_put(res->fi);
   322                 res->fi = fi;                  
   323                 atomic_inc(&fi->fib_clntref);
   324                 fn_hash_last_dflt = order;
   325                 goto out;
   326             }
   327             fi = next_fi;
   328             order++;
   329         }// end of list_for_each_entry

这里next_fi不等于res->fi的原因是在fib_lookup后,系统又添加了一条缺省路由,且其优先级别高于之前fib_lookup所查询到的res所对应的旧的缺省路由,但是为啥明明找到了一条新的更高优先级的缺省路由(fib_priority值更小)后,就立刻break,不再继续查找余下的fib_alias了,相反,当next_fi等于res->fi时,表明自从上次fib_lookup查询到某个缺省路由后,此时尚无新的更高优先级的缺省路由被加入,因此第327行将next_fi保存在fi中,随后返回到第301行继续遍历下一个fib_alias,这到底是什么逻辑?

这个fn_hash_select_default函数的逻辑实在让人摸不清头脑呢,还望各位大侠能解惑!




作者: _nosay    时间: 2016-12-27 12:00
回复 2# jiufei19


都放假了,谁还回答你问题
作者: jiufei19    时间: 2016-12-27 12:20
回复 3# _nosay

_nosay能回答我这个疑问吗?
作者: _nosay    时间: 2016-12-27 12:50
回复 4# jiufei19


我不会,我知道有几位版主和nswcfd他们,功力深厚,不过要等他们看到你的帖子。
作者: nswcfd    时间: 2016-12-30 11:47
即对于缺省路由,是没有tos设置的,

暂时不能回答楼主的问题,不过这个逻辑似乎不太成立。
就算没有显式的进行tos配置,创建fib/alias的时候也是有tos值的,只不过是默认值。
除非存在对这个默认值进行特殊处理的代码,否则大概不是这个原因吧。
作者: nswcfd    时间: 2016-12-30 19:58
select_default是在不开启MULTIPATH的情况下启用的,估计是早期的多路径的解决方案(并且只针对默认路由)?

由于fib-lookup只返回(满足tos/scope/oif)的第一个alias(某个默认路由),其它的alias被屏蔽了。
不知道使用select_default_route的初衷,是不是给其它alias一个机会?

之前好像真没怎么关注这一点呢……

作者: jiufei19    时间: 2016-12-30 22:24
nswcfd 发表于 2016-12-30 11:47
暂时不能回答楼主的问题,不过这个逻辑似乎不太成立。
就算没有显式的进行tos配置,创建fib/alias的时候 ...

非常感谢nswcfd的答复,虽然没有解决我的问题。
nswcfd说的不错,就算没有tos的显式设置,也有隐式设置,其实就是为0。

不过如果当前所有fib_alias的tos都为0,或者都不为0且相同,则只比较fib_priority的大小才是有意义的,否则因为tos和fib_priority属于不同级别的属性,而该函数只按fib_priority进行比较就很令人费解,正因为如此,我才猜测此时tos不起任何作用。

然而,的确这个函数的逻辑太另类了,很难用文字描述清楚它究竟想干啥。


作者: jiufei19    时间: 2016-12-30 22:34
nswcfd 发表于 2016-12-30 19:58
select_default是在不开启MULTIPATH的情况下启用的,估计是早期的多路径的解决方案(并且只针对默认路由) ...

假设在进行fn_hash_select_default之前,另外一个线程插入了一个新的缺省路由,且其对应的fib_alias排在之前fib_lookup所查找到的res对应的fib_alias之前,则按此函数逻辑,第316行立刻break,那么就跳到第334行goto out处,则此函数处理完毕。似乎想表达这样一个意思,即因为又找到了一个有更高优先级的缺省路由,则就可以暂时继续使用之前那个res对应的缺省路由,哪怕该res对应的缺省路由网关最终不可达也没有关系,因为毕竟已经有一个新的更高优先级缺省路由存在了。反之,如果没有找到有更高优先级的,则原来res对应的那个仍然是目前最高优先级的,则我们需要继续判断其的确是否仍然可用,如果不可用,就继续遍历和其同级的或者较低优先级的其他缺省路由。

该函数的逻辑大体如此,不过虽然我大概知道其逻辑是这样,但是仍然感到很困惑,例如之前那个对tos缺乏检查的问题。



作者: jiufei19    时间: 2017-01-03 11:29
回复 9# jiufei19

烦请各位大侠帮助我解决此问题
作者: jiufei19    时间: 2017-01-04 11:00
回复 10# jiufei19

求解答啊,各位大侠
作者: nswcfd    时间: 2017-01-05 17:31
这算是某种legacy代码吧,

http://lxr.free-electrons.com/source/net/ipv4/fib_hash.c?v=2.2.26
里面的select_default跟现在长的模样没有太大的变化。

注意个CONFIG_IP_ROUTE_TOS选项,是不是说早期的路由是不考虑tos的?
作者: nswcfd    时间: 2017-01-05 17:49
本帖最后由 nswcfd 于 2017-01-05 17:50 编辑

更早的版本 http://lxr.free-electrons.com/source/net/ipv4/route.c?v=2.0.40 好像没有看到类似的逻辑。

PS,netlink出现的好早呀…… 不过早期的netlink好像是个char-device而不是socket。
作者: jiufei19    时间: 2017-01-05 18:09
本帖最后由 jiufei19 于 2017-01-05 18:17 编辑

回复 12# nswcfd

直到v2.6.38.8,还有该函数,只不过换了个名字叫fib_table_select_default,我现在虽然就是感到它那段代码似乎是在tos不起作用下才行,但是内核代码不可能这样来兼容,否则一旦配置缺省路由时设置了tos的话,则代码就有问题了,所以我猜测它这种写法在逻辑上可能等效于没有tos的情况,或者说,它这个不考虑tos的写法不改变这个函数想要实现的功能。
作者: jiufei19    时间: 2017-01-07 11:08
nswcfd 发表于 2017-01-05 17:31
这算是某种legacy代码吧,

http://lxr.free-electrons.com/source/net/ipv4/fib_hash.c?v=2.2.26

似乎也不能看成是legacy代码,因为在v2.6.23~38等发行版中,可以通过如下命令添加2条带有指定tos的缺省路由:

ip route add default via 192.168.93.129 dev eth1 tos 2f
ip route add default via 192.168.93.129 dev eth1 tos 2e

之后通过ip route show命令查看,可以看到3条缺省路由,2条有tos,另外1条无tos设置:

default tos 0x2f via 192.168.93.129 dev eth1
default tos 0x2e via 192.168.93.129 dev eth1
default via 192.168.93.2 dev eth1





作者: sditmaner    时间: 2017-01-07 13:20
回复 4# jiufei19
作者: jiufei19    时间: 2017-01-07 15:06
回复 16# sditmaner

请问sditmaner,没有看到你的具体答复呢
作者: plt2007plt    时间: 2017-01-13 17:27
默认路由TOS是无效的,还有就是priority值越大优先级越小
作者: jiufei19    时间: 2017-01-16 15:59
本帖最后由 jiufei19 于 2017-01-16 16:00 编辑
plt2007plt 发表于 2017-01-13 17:27
默认路由TOS是无效的,还有就是priority值越大优先级越小

感谢plt2007plt。
priority的值越大,优先级越下,这个概念没有问题,但是默认路由的tos是无效的,这个结论出自哪里?而如果真无效,为啥在linux中还是可以给默认路由设置不同的tos,正如我之前给出的iproute2命令的实例所示。









欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2