概述
以前的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>;