最近遇到了一个与linux内核选项tcp_tw_recycle的坑, 在此记录一下相关知识点。
TIME_WAIT状态的作用
如图,TIME_WAIT状态主要用来处理数据的错误传输,比如一个连接,在断开后,又新建了相同的连接(IP和端口的四元组),上一次断开的连接中某些数据可能由于网络拥塞而延迟到来,显然延迟的数据不是属于这一个新建的连接的,为了防止这种情况,TIME_WAIT状态会等待2MSL,即两倍最大报文生存时间。
如图的黄色箭头所代表的即为不正确的数据。
tcp_tw_recycle
当在连接量较大的服务器上时,如果大量的TIME_WAIT状态会影响服务器的性能,因此,RFC6191提出使用TCP Timestamp来减少这样的TIME_WAIT状态。
在内核中的代码实现如下:
536 bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool paws_check)
537 {
538 struct tcp_metrics_block *tm;
539 bool ret;
540
541 if (!dst)
542 return false;
543
544 rcu_read_lock();
545 tm = __tcp_get_metrics_req(req, dst);
546 if (paws_check) {
547 if (tm &&
548 (u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL &&
549 (s32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW)
550 ret = false;
551 else
552 ret = true;
553 } else {
554 if (tm && tcp_metric_get(tm, TCP_METRIC_RTT) && tm->tcpm_ts_stamp)
555 ret = true;
556 else
557 ret = false;
558 }
559 rcu_read_unlock();
560
561 return ret;
562 }
563 EXPORT_SYMBOL_GPL(tcp_peer_is_proven);
在代码中,547-552行主要确保在TCP_PAWS_MSL时间内请求的时间戳是递增的(TCP_PAWS_WINDOW为1)。
ipatbles NAT
所以当后端机器在NAT后面时,由于NAT并没有改时间戳,连接中的时间戳来自不同的机器,时间戳(机器启动时间)不一定是递增的,所以就会出现后端机器drop SYN包的情况.
在NAT后的机器,关闭tcp_tw_recycle检查即可,一般该选项为disable的。