Linux kernel 3.6正式去除了路由cache,原因正如作者所说,它并不适合作为路由表的一部分存在,它是和流量patterns高度相关的,应该作为一种优化在外部实现,比如基于Asic硬卡的转发表中实现,况且,现有的路由cache在大多数情况下并不会带来显著的性能提升,如果你频繁flush cache后带来了性能下降的话,其中很多因素是flush操作本身以及lookup的read lock造成的。然而如果你使用的是低于3.6版本的内核,你将不得不面对路由cache,既然它给不了你太多的好处,那么如果它反而给你带来了坏处,你对它的态度就不仅仅是诅咒了!
面临的一个路由cache带来的危害
路由cache和基于mark的policy routing之间的不配合造成了产品的一个bug,让我连续几日陷入了烦恼!我们知道,mark目前只能靠Netfilter的钩子来在标记,而PREROUTING处的标记在ROUTING之前,在Linux中,不管是iptables rule还是一条policy routing item,都是配置后立即生效的,两个操作不能合并为一个单独的原子操作,这就造成了问题:
1.现在需要一条rule为packet做mark,一条policy routing item基于该mark做路由,于是就有两条Linux命令;
2.执行上述两条命令前,有感兴趣数据包持续通过BOX,造成了路由cache;
3.先执行了mark rule,此时在policy routing item还未执行时进来一个感兴趣packet匹配到了mark,然而没有匹配到policy routing;
4.如果你的policy routing table配置的是fall though,问题就来了,lookup进入main table,配置到原始的路由,被cache住;
5.如果一直有持续的感兴趣流,那么上述的mark-policy routing将永远不会生效。
可能你会说,将mark rule和policy routing item的设置顺序互换一下即可,然而即使那样,如果你的实现是有状态的,你还要面临另外一个cache,即conntrack cache的问题。可能你还会说,fall though换成default unreachable去掉即可,但是那样就会和实现的语义有很大的差别。因此禁用路由cache势在必行!
如何禁用路由cache
又是一段艰难的旅程!/proc/sys/net/ipv4/route/下面的参数调了个遍也没有成功,route -C -n还是显示出了一大堆恶心的乱七八糟的东西。于是还是google以及看代码,发现了以下的参数:
rt_cache_rebuild_count – INTEGER
The per net-namespace route cache emergency rebuild threshold.
Any net-namespace having its route cache rebuilt due to
a hash bucket chain being too long more than this many times
will have its route caching disabled
作为确认,在route.c中的IP的input/output中,查找cache之前有一个判断:
if (!rt_caching(net))
goto skip_cache;
这样就跳过了cache查找,而rt_caching的实现超级简单:
static inline bool rt_caching(const struct net *net)
{
return net->ipv4.current_rt_cache_rebuild_count <=
net->ipv4.sysctl_rt_cache_rebuild_count;
}
加之sysctl_rt_cache_rebuild_count是int型的,只要保证上述函数永远返回0即可,于是将sysctl_rt_cache_rebuild_count设置为-1,成功禁用了路由cache!
总结
不要天真地认为什么cache都会提高效率,在Linux路由cache的例子中,查找路由表是hash/trie查表,查找cache也是一个hash表,另外如果你的路由表只有一条默认路由,cache项的数量要远远大于路由表项的数量,此时cache仅仅就是直接使用了dst_entry,而不用从result里面把路由表项的字段抠出来设置进新申请的dst_entry中,浪费的查表时间得到这个一点收益…其实,只要路由表中有前缀小于32位的路由表项,都有可能出现上述情况,因此在cache查找机制和路由表查找机制没有本质区别的情况下,路由cache并没有达到预期的效果!相反,路由cache应该在PREROUTING的时候做,而不是到ROUTING的时候再做,在PREROUTING中,可以方便地使用Netfilter将cache实现在硬卡中。
在确定行为的情况下,cache会提高效率,在行为模式不固定的情况下,cache的作用就是浪费资源,扰乱视听!老师罚你把“猪血”连续写10遍,此时你就可以连续写10个“猪”,再连续写10个“血”,肯定比连续写10个“猪血”要快一些,然而如果你是一位同声传译员或者一位速记员,你千万别把刚刚听到的记在脑子里…