cache老化时间的思考--以nat为例

局域网越来越大,于是有人提出了vlan,vlan越来越依赖多而快的端口,于是有人做出了三层交换机,实际上三层交换机仅仅对直接下挂的主机性能有较大的提升,对远端的主机效果要么不大,要么根本没有,说白了三层交换机就是在学以太网交换机的样子,本质上就是加了一个cahce功能,使得ip地址直接与端口保持映射,这样就不必再解包,路由,封包了,因此三层交换机是基于流的,并且只要是基于流的都会有老化机制。在cache的作用下,三层交换机轻松实现快速转发,就像二层交换机一样,拥有学习功能,所谓的学习功能其实就是一个cache功能。
     有必要提一下老化机制,该机制丰富了cache,增加了公平性,但是有的时候行为却不是很严格,比如nat实现中,nat在linux中是基于netfilter的conntrack的,conntrack模块会侦测过来的每一个数据包,如果它已经属于一个流,那么就放过,如果不属于任何流,那么就建立一个新的流,将之放入一个哈希,这里就有了两个问题。
     第一个问题是由于tcp和udp的行为有很大的不同,那么连接管理模块有必要将之分开管理,那么就需要在prerouting的时候知道该数据包是tcp的还是udp的,但是我们知道ip会分片的,所以当时到来的数据包可能仅仅是一个ip片段,我们无法从一个片断看得出该片断是udp还是tcp的,除非该片断是第一个,于是conntrack要做的一件事就是重组分片,然后在forward的时候再将之分片。
     第二个问题就是流的老化时间问题,为了使得内核不频繁的对流cache进行修改和替换,每个连接的每个状态都有个老化时间,这些时间根据协议和协议的状态有所不同,比如tcp的ESTABLISHED的状态的流的老化时间就会特别长,而udp的未回答状态的老化时间会特别短,于是问题出来了,如果我配置错了一个nat,那么当我尝试连接的时候肯定是失败的,因为nat将会把目的地址转为一个错误的地址,此时流已经建立了,虽然可能不通,但是路由存在,访问允许,流建立了,并且在确认路由存在访问允许之后查nat表找到了错误的rule,由于对端还没有回答,所以这个状态的流的老化时间很短,虽然时间老化很短,可毕竟建立了,然后我随即将nat配置正确,可是在刚才那个已经建立的流为老化之前,我还是无法连接,这说明一旦流匹配了,在下面经过nat表的时候就会将nat信息复制进这个流,于是后面的数据包一旦命中这个流,将会一直使用这个nat信息,直到该流老化或者被挤出哈希表;另外一个反面的例子是如果nat是配置正确的,那么在改错了的一会时间内还是可以通信的,原因就是流还没有老化,并且新的nat信息没有被刷新。
     另外,nat依赖conntrack的设计本身也许很脆弱,在出现大量连接的情况下,conntrack的哈希表很快就会满,接下来的连接就无法加入哈希表了,于是nat就会失败。脆弱的本质就是nat几乎完全依赖了一个用于效率优先容量有限的哈希表,而不是公平优先绝对精确的容器,我们在受到cache的恩惠的同时也要主要它会引起的问题,正如cpu的cache有cache一致性一样,任何用到cache的地方都要注意这个一致性,除此之外还必须实现公平性。

你可能感兴趣的:(linux,cache,tcp)