TCP 之 TCP_NEW_SYN_RECV状态
概述
以前的TCP请求控制块没有独立的状态,而是依赖于他们的父控制块的状态,也就是TCP_LISTEN状态,现在要把请求控制块加入到全局的ehash中,所以需要一个状态,而TCP_SYN_RECV状态被fast open sokets使用了,所以新加了一个TCP_NEW_SYN_RECV状态;
以下截取在kernel git,地址:https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/log/?qt=grep&q=TCP_NEW_SYN_RECV
TCP_SYN_RECV state is currently used by fast open sockets. Initial TCP requests (the pseudo sockets created when a SYN is received) are not yet associated to a state. They are attached to their parent, and the parent is in TCP_LISTEN state. This commit adds TCP_NEW_SYN_RECV state, so that we can convert TCP stack to a different schem gradually. ------------------------ We need to identify request sock when they'll be visible in global ehash table. ireq_state is an alias to req.__req_common.skc_state. Its value is set to TCP_NEW_SYN_RECV
代码分析
以下代码以服务器端处于LISTEN状态,等待接收syn为前提;
接收SYN
在服务器接收了syn之后,会调用tcp_conn_request来处理连接请求,其中调用inet_reqsk_alloc来创建请求控制块,可见请求控制块的ireq_state被初始化为TCP_NEW_SYN_RECV;
1 struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops, 2 struct sock *sk_listener, 3 bool attach_listener) 4 { 5 struct request_sock *req = reqsk_alloc(ops, sk_listener, 6 attach_listener); 7 8 if (req) { 9 struct inet_request_sock *ireq = inet_rsk(req); 10 11 kmemcheck_annotate_bitfield(ireq, flags); 12 ireq->opt = NULL; 13 #if IS_ENABLED(CONFIG_IPV6) 14 ireq->pktopts = NULL; 15 #endif 16 atomic64_set(&ireq->ir_cookie, 0); 17 ireq->ireq_state = TCP_NEW_SYN_RECV; 18 write_pnet(&ireq->ireq_net, sock_net(sk_listener)); 19 ireq->ireq_family = sk_listener->sk_family; 20 } 21 22 return req; 23 }
该部分详细分析请移步:<TCP被动打开 之 第一次握手-接收SYN>;
接收ACK
tcp_v4_rcv函数中会对TCP_NEW_SYN_RECV进行处理,如果连接检查成功,则需要新建控制块来处理连接,这个新建控制块的状态将会使用TCP_SYN_RECV状态;
该部分详细分析请移步:<TCP被动打开 之 第三次握手-接收ACK>;