1. 現象
第二個現象:不同主機上的模塊C(開啓timestamp),通過NAT網關(1個出口ip)訪問同一服務S,主機C1connect成功,而主機C2 connect失敗;
2. 分析
根據現象上述問題明顯和tcp timestmap有關;查看linux2.6.32內核源碼,發現tcp_tw_recycle/tcp_timestamps都開啓的條件下,60s內同一源ip主機的socketconnect請求中的timestamp必須是遞增的。
源碼函數:tcp_v4_conn_request(),該函數是tcp層三次握手syn包的處理函數(服務端);
源碼片段:
if (tmp_opt.saw_tstamp&&
tcp_death_row.sysctl_tw_recycle&&
(dst =inet_csk_route_req(sk, req)) != NULL&&
(peer =rt_get_peer((struct rtable *)dst)) != NULL&&
peer->v4daddr == saddr) {
if(get_seconds()< peer->tcp_ts_stamp +TCP_PAWS_MSL &&
(s32)(peer->tcp_ts -req->ts_recent) >
TCP_PAWS_WINDOW) {
NET_INC_STATS_BH(sock_net(sk),LINUX_MIB_PAWSPASSIVEREJECTED);
gotodrop_and_release;
}
}
tmp_opt.saw_tstamp:該socket支持tcp_timestamp
sysctl_tw_recycle:本機系統開啓tcp_tw_recycle選項
TCP_PAWS_MSL:60s,該條件判斷表示該源ip的上次tcp通訊發生在60s內
TCP_PAWS_WINDOW:1,該條件判斷表示該源ip的上次tcp通訊的timestamp 大於本次tcp
分析:主機client1和client2通過NAT網關(1個ip地址)訪問serverN,由於timestamp時間爲系統啓動到當前的時間,因此,client1和client2的timestamp不相同;根據上述syn包處理源碼,在tcp_tw_recycle和tcp_timestamps同時開啓的條件下,timestamp大的主機訪問serverN成功,而timestmap小的主機訪問失敗;
參數:/proc/sys/net/ipv4/tcp_timestamps -控制timestamp選項開啓/關閉
/proc/sys/net/ipv4/tcp_tw_recycle - 減少timewait socket釋放的超時時間
3. 解決方法
echo 0> /proc/sys/net/ipv4/tcp_tw_recycle;
tcp_tw_recycle默認是關閉的,有不少服務器,爲了提高性能,開啓了該選項;
爲了解決上述問題,個人建議關閉tcp_tw_recycle選項,而不是timestamp;因爲 在tcptimestamp關閉的條件下,開啓tcp_tw_recycle是不起作用的;而tcptimestamp可以獨立開啓並起作用。
源碼函數: tcp_time_wait()
源碼片段:
if (tcp_death_row.sysctl_tw_recycle&&tp->rx_opt.ts_recent_stamp)
recycle_ok =icsk->icsk_af_ops->remember_stamp(sk);
......
if (timeo< rto)
timeo = rto;
if(recycle_ok) {
tw->tw_timeout = rto;
} else{
tw->tw_timeout = TCP_TIMEWAIT_LEN;
if (state ==TCP_TIME_WAIT)
timeo = TCP_TIMEWAIT_LEN;
}
inet_twsk_schedule(tw, &tcp_death_row, timeo,