注意:本文档中的内核代码的版本:linux-4.0.5 /************************************************* * Author : Samson * Date : 07/14/2015 * Test platform: * gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 * GNU bash, 4.3.11(1)-release (x86_64-pc-linux-gnu) * Nginx version: * Nginx 1.6.2 * Nginx 1.8.0 * ***********************************************/
两者的关系net.ipv4.tcp_tw_recycle是与net.ipv4.tcp_timestamps是密切相关的,而net.ipv4.tcp_timestamps默认是开启的,当tcp_tw_recycle和tcp_timestamps同时打开时会激活TCP的一种隐藏属性:缓存连接的时间戳。60秒内,同一源IP的后续请求的时间戳小于缓存中的时间戳,内核就会丢弃该请求。
那么在内核中对应的代码是怎样处理的呢?在内核代码中net/ipv4/tcp_input.c中的tcp_conn_request函数的代码:
if (tcp_death_row.sysctl_tw_recycle) { bool strict;
dst = af_ops->route_req(sk, &fl, req, &strict);
if (dst && strict && !tcp_peer_is_proven(req, dst, true, tmp_opt.saw_tstamp)) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); goto drop_and_release; } }
//tcp_peer_is_proven函数的实现
bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool paws_check, bool timestamps){ struct tcp_metrics_block *tm; bool ret; if (!dst) return false; rcu_read_lock(); tm = __tcp_get_metrics_req(req, dst); if (paws_check) { if (tm && (u32)get_seconds() – tm->tcpm_ts_stamp < TCP_PAWS_MSL && ((s32)(tm->tcpm_ts – req->ts_recent) > TCP_PAWS_WINDOW || !timestamps)) ret = false; else ret = true; } else { if (tm && tcp_metric_get(tm, TCP_METRIC_RTT) && tm->tcpm_ts_stamp) ret = true; else ret = false; } rcu_read_unlock();
return ret;}
主要参数说明tmp_opt.saw_tstamp:该socket支持tcp_timestamp, tcp_death_row.sysctl_tw_recycle:本机系统开启tcp_tw_recycle选项 TCP_PAWS_MSL:/* Per-host timestamps are invalidated * after this time. It should be equal * (or greater than) TCP_TIMEWAIT_LEN * to provide reliability equal to one * provided by timewait state. */ 60s,该条件判断表示该源ip的上次tcp通讯发生在60s内;
TCP_PAWS_WINDOW:/* Replay window for per-host * timestamps. It must be less than * minimal timewait lifetime. */ 1,该条件判断表示该源ip的上次tcp通讯的timestamp 大于本次tcp;
丢弃请求的关键代码(u32)get_seconds() – tm->tcpm_ts_stamp < TCP_PAWS_MSL表示若当前请求的时间戳小于60S,则返回false,则跳转到goto drop_and_release;进行连接请求的丢弃及资源的回收;
drop_and_release: dst_release(dst); drop_and_free: reqsk_free(req); drop: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return 0;
本文永久更新链接地址:
,我们首先去了象鼻山,那里景色秀丽神奇,