TCP定时器 之 延迟确认定时器
TCP在收到数据段但是无需马上确认时设定,如果在超时时间之内有数据要发送到对端,则确认会随着数据一起发送,即捎带ACK,如果达到超时时间则执行定时器回调立即发送ack;
启动定时器:
延迟确认定时器调用inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, xx, xxx)函数进行启动,启动时间点包含以下三个;
1. 建立连接时,客户端的第三次握手可能会被延迟确认,如果有数据要输出、设置了TCP_DEFER_ACCEPT选项或者不在快速确认模式下,则启动延迟确认定时器;
1 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, 2 const struct tcphdr *th) 3 { 4 if (sk->sk_write_pending || 5 icsk->icsk_accept_queue.rskq_defer_accept || 6 icsk->icsk_ack.pingpong) { 7 /* Save one ACK. Data will be ready after 8 * several ticks, if write_pending is set. 9 * 10 * It may be deleted, but with this feature tcpdumps 11 * look so _wonderfully_ clever, that I was not able 12 * to stand against the temptation 8) --ANK 13 */ 14 inet_csk_schedule_ack(sk); 15 tcp_enter_quickack_mode(sk); 16 inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, 17 TCP_DELACK_MAX, TCP_RTO_MAX); 18 19 discard: 20 tcp_drop(sk, skb); 21 return 0; 22 } else { 23 tcp_send_ack(sk); 24 } 25 }
2. 在立即发送确认时,如果分配内存失败,则启动延迟确认定时器;
1 /* This routine sends an ack and also updates the window. */ 2 /* TCPTODO */ 3 void tcp_send_ack(struct sock *sk) 4 { 5 struct sk_buff *buff; 6 7 /* If we have been reset, we may not send again. */ 8 if (sk->sk_state == TCP_CLOSE) 9 return; 10 11 tcp_ca_event(sk, CA_EVENT_NON_DELAYED_ACK); 12 13 /* We are not putting this on the write queue, so 14 * tcp_transmit_skb() will set the ownership to this 15 * sock. 16 */ 17 buff = alloc_skb(MAX_TCP_HEADER, 18 sk_gfp_mask(sk, GFP_ATOMIC | __GFP_NOWARN)); 19 if (unlikely(!buff)) { 20 inet_csk_schedule_ack(sk); 21 inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN; 22 inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, 23 TCP_DELACK_MAX, TCP_RTO_MAX); 24 return; 25 } 26 27 /* Reserve space for headers and prepare control bits. */ 28 skb_reserve(buff, MAX_TCP_HEADER); 29 tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK); 30 31 /* We do not want pure acks influencing TCP Small Queues or fq/pacing 32 * too much. 33 * SKB_TRUESIZE(max(1 .. 66, MAX_TCP_HEADER)) is unfortunately ~784 34 */ 35 skb_set_tcp_pure_ack(buff); 36 37 /* Send it off, this clears delayed acks for us. */ 38 skb_mstamp_get(&buff->skb_mstamp); 39 tcp_transmit_skb(sk, buff, 0, (__force gfp_t)0); 40 }
3. 未启用tcp_low_latency情况下,当有进程正在读取TCP流时,此时prequeue队列存在TCP段且消耗的内存未达到上限,且没有ACK需要发送时,启动延迟确认定时器;
1 bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) 2 { 3 if (skb_queue_len(&tp->ucopy.prequeue) == 1) { 4 wake_up_interruptible_sync_poll(sk_sleep(sk), 5 POLLIN | POLLRDNORM | POLLRDBAND); 6 if (!inet_csk_ack_scheduled(sk)) 7 inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, 8 (3 * tcp_rto_min(sk)) / 4, 9 TCP_RTO_MAX); 10 } 11 return true; 12 }
定时器回调函数:
tcp_delack_timer函数进行必要的状态检查,处理队列中的数据包,如果有ack要发送,则使用即使ack模式立即发送ack;
1 /** 2 * tcp_delack_timer() - The TCP delayed ACK timeout handler 3 * @data: Pointer to the current socket. (gets casted to struct sock *) 4 * 5 * This function gets (indirectly) called when the kernel timer for a TCP packet 6 * of this socket expires. Calls tcp_delack_timer_handler() to do the actual work. 7 * 8 * Returns: Nothing (void) 9 */ 10 static void tcp_delack_timer(unsigned long data) 11 { 12 struct sock *sk = (struct sock *)data; 13 14 bh_lock_sock(sk); 15 /* 传输控制块未被锁定 */ 16 if (!sock_owned_by_user(sk)) { 17 /* 调用超时处理函数 */ 18 tcp_delack_timer_handler(sk); 19 } else { 20 /* 打阻塞标记告知ack要立即发送*/ 21 inet_csk(sk)->icsk_ack.blocked = 1; 22 __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); 23 /* deleguate our work to tcp_release_cb() */ 24 /* 交给tcp_release_cb处理超时回调 */ 25 if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags)) 26 sock_hold(sk); 27 } 28 bh_unlock_sock(sk); 29 sock_put(sk); 30 }
1 /* Called with BH disabled */ 2 void tcp_delack_timer_handler(struct sock *sk) 3 { 4 struct tcp_sock *tp = tcp_sk(sk); 5 struct inet_connection_sock *icsk = inet_csk(sk); 6 7 sk_mem_reclaim_partial(sk); 8 9 /* 关闭或者监听状态 || 未启动延迟ack定时器*/ 10 if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || 11 !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) 12 goto out; 13 14 /* 尚未达到超时时间,重新设定定时器 */ 15 if (time_after(icsk->icsk_ack.timeout, jiffies)) { 16 sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout); 17 goto out; 18 } 19 20 /* 清除延迟ack标记 */ 21 icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER; 22 23 /* prequeue队列不为空 */ 24 if (!skb_queue_empty(&tp->ucopy.prequeue)) { 25 struct sk_buff *skb; 26 27 __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSCHEDULERFAILED); 28 29 /* 数据包出队,调用接收函数tcp_v4_do_rcv处理包 */ 30 while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) 31 sk_backlog_rcv(sk, skb); 32 33 /* 消耗的内存清0 */ 34 tp->ucopy.memory = 0; 35 } 36 37 /* 有ack需要发送 */ 38 if (inet_csk_ack_scheduled(sk)) { 39 40 /* 即时ack模式 */ 41 if (!icsk->icsk_ack.pingpong) { 42 /* Delayed ACK missed: inflate ATO. */ 43 /* 计算超时时间 */ 44 icsk->icsk_ack.ato = min(icsk->icsk_ack.ato << 1, icsk->icsk_rto); 45 } 46 /* 延迟ack模式 */ 47 else { 48 /* Delayed ACK missed: leave pingpong mode and 49 * deflate ATO. 50 */ 51 /* 设置为即时ack模式 */ 52 icsk->icsk_ack.pingpong = 0; 53 54 /* 重置超时时间 */ 55 icsk->icsk_ack.ato = TCP_ATO_MIN; 56 } 57 58 /* 发送ack */ 59 tcp_send_ack(sk); 60 __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS); 61 } 62 63 out: 64 if (tcp_under_memory_pressure(sk)) 65 sk_mem_reclaim(sk); 66 }