linux内核协议栈之tcp connect流程(二)
tcp三次握手服务端处理流程,如图1-1所示。
图1-1:函数tcp_v4_rcv代码流程图
- 网卡驱动收到数据后,会触发NET_RX_SOFTIRQ软中断,软中断处理函数
net_rx_action通过调用网卡驱动注册的poll函数来进行收包处理,最终通过netif_receive_skb->ip_rcv ip_rcv_finish->dst_input->ip_local_deliver->ip_local_deliver_finish->tcp_v4_rcv来进行tcp收包处理。tcp_v4_do_rcv首先根据目标ip与端口查找已经建立连接的sock,如果以前没有建立连接则在listen端口中查找,找到以后首先,将tcp头中的相关信息填入skb私有数据区cb中。然后调用tcp_v4_do_rcv进行真正的syn请求处理。 __inet_lookup_skb函数主要是sk查找函数,它首先在tcp_hashinfo实例的ehash链表中查找,找不到就会在监听sock所在的hash表中查找,对于第一次同步请求,返回的结果是listen sk,此时sk->sk_state状态是TCP_LISTEN。tcp_v4_fill_cb函数主要是将tcp头中的start seq、end seq、ark seq等信息填入skbcb中。- 由于此时
sk->sk_state状态是TCP_LISTEN,因此进入tcp_v4_do_rcv流程,它根据sk_state会继续调用tcp_rcv_state_process函数。 tcp_rcv_state_process函数根据sk->sk_state状态,来查看是否是syn请求消息,如是则继续调用icsk->icsk_af_ops->conn_request,icsk->icsk_af_ops指针的初使化是在tcp_prot: tcp_v4_init_sock函数中,此初使化函数将icsk->icsk_af_ops 赋值为 &ipv4_specific,因此,icsk->icsk_af_ops->conn_request函数对应ipv4_specific:tcp_v4_conn_request函数。- 对于
ipv4_specific:tcp_v4_conn_request函数,它会调用真正的处理函数tcp_conn_request,如图1-2所示。图1-2:函数tcp_v4_conn_request代码流程图 - 主要调用
tcp_conn_request来进行真正处理。 Syn请求真正的处理函数,它首先判断syn请求队列是否已达最大值,通过检查后,会分配一个req(struct request_sock *req)实例,且req->rsk_listener 赋值为 listener sk,req->rsk_ops赋值为tcp_request_sock_ops,req_to_sk(req)->sk_prot 赋值为 sk_listener->sk_prot,ireq->ireq_state 赋值为 TCP_NEW_SYN_RECV,接着赋值tcp_rsk(req)->af_specific 为tcp_request_sock_ipv4_ops,然后调用tcp_openreq_init继续初使化req相关结构,包括源端口与目标端口,调用af_ops->init_req设置源ip与目标ip,接着需给对端响应syn ack,因此调用af_ops->route_req查找目标路由,调用tcp_openreq_init_rwin初使化syn ack相关字段,接着调用inet_csk_reqsk_queue_hash_add将req保存到tcp_hashinfo实例的ehash链表中,最后调用af_ops->send_synack给对端响应syn ack。inet_reqsk_alloc分配syn ack实例req,并初使化部分成员,如:req->rsk_listener 赋值为 listener sk,req->rsk_ops赋值为tcp_request_sock_ops,req_to_sk(req)->sk_prot 赋值为 sk_listener->sk_prot,ireq->ireq_state 赋值为 TCP_NEW_SYN_RECV。tcp_openreq_init函数继续为req实例赋值,主要有:ireq->ir_rmt_port赋值为syn请求的源端口,ireq->ir_num赋值为同步请求的目的端口,tcp_rsk(req)->rcv_isn赋值为syn请求的start seq等。af_ops->init_req函数对应tcp_request_sock_ipv4_ops:tcp_v4_init_req,它主要是设置同步请求的源ip与目标ip。- 接着需根据
syn请求源ip查找syn ack消息的路由。 tcp_openreq_init_rwin主要是生成syn ack响应消息中的tcp windows字段。- 将
req请求插入到tcp_hashinfo实例的ehash链表中。 af_ops->send_synack函数主要是回复syn ack,此处对应函数tcp_request_sock_ipv4_ops:tcp_v4_send_synack。它首先调用tcp_make_synack生成syn ack的skb并记录当前时间到skb->skb_mstamp_ns中,然后调用ip_build_and_send_pkt->ip_local_out将其发送出去。
参考
linux内核版本:5.7.8