9.2.1 Why
TCP服务器在收到SYN请求后发送SYN|ACK响应,然后等待对端的ACK到来以完成三次握手。如果没有收到ACK,TCP应该重传SYN|ACK,这个功能由SYN-ACK定时器完成。由于SYN|ACK发送后并没有放入发送队列中,故重传时必须重新构建SYN|ACK报文。
9.2.2 When
TCP在发送SYN|ACK响应后设置SYN-ACK定时器:
1465 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
1466 {
...
1598 skb_synack = tcp_make_synack(sk, dst, req,
1599 fastopen_cookie_present(&valid_foc) ? &valid_foc : NULL); //构建SYN|ACK
1600
1601 if (skb_synack) {
1602 __tcp_v4_send_check(skb_synack, ireq->loc_addr, ireq->rmt_addr);
1603 skb_set_queue_mapping(skb_synack, skb_get_queue_mapping(skb));
1604 } else
1605 goto drop_and_free;
1606
1607 if (likely(!do_fastopen)) {
1608 int err;
1609 err = ip_build_and_send_pkt(skb_synack, sk, ireq->loc_addr,
1610 ireq->rmt_addr, ireq->opt); //发送SYN|ACK
...
1617 /* Add the request_sock to the SYN table */
1618 inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); //将requese sock加入到SYN表中,并设置SYN-ACK定时器
...
inet_csk_reqsk_queue_hash_add函数:
521 void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
522 unsigned long timeout)
523 {
524 struct inet_connection_sock *icsk = inet_csk(sk);
525 struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
526 const u32 h = inet_synq_hash(inet_rsk(req)->rmt_addr, inet_rsk(req)->rmt_port,
527 lopt->hash_rnd, lopt->nr_table_entries);
528
529 reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout); //将request_sock放入syn_table中并记录超时时间
530 inet_csk_reqsk_queue_added(sk, timeout); //设置SYN-ACK定时器
531 }
reqsk_queue_hash_req函数会记录request_sock的超时时间:
262 static inline void reqsk_queue_hash_req(struct request_sock_queue *queue,
263 u32