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配置,创建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的答复,虽然没有解决我的问题。
nswcfd说的不错,就算没有tos的显式设置,也有隐式设置,其实就是为0。
不过如果当前所有fib_alias的tos都为0,或者都不为0且相同,则只比较fib_priority的大小才是有意义的,否则因为tos和fib_priority属于不同级别的属性,而该函数只按fib_priority进行比较就很令人费解,正因为如此,我才猜测此时tos不起任何作用。
然而,的确这个函数的逻辑太另类了,很难用文字描述清楚它究竟想干啥。
作者: jiufei19 时间: 2016-12-30 22:34
假设在进行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
似乎也不能看成是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。
priority的值越大,优先级越下,这个概念没有问题,但是默认路由的tos是无效的,这个结论出自哪里?而如果真无效,为啥在linux中还是可以给默认路由设置不同的tos,正如我之前给出的iproute2命令的实例所示。
欢迎光临 Chinaunix (http://bbs.chinaunix.net/) |
Powered by Discuz! X3.2 |