9.3.1 Why
TCP在发送SYN、FIN以及数据包时为了保证可靠传输,会先将它们放入发送队列再发送副本到网络中,一旦发现数据丢失(比如连续收到多个ack_seq号相同的ACK)则重传发送队列中的skb。如果丢失发现机制失效了呢(比如ACK丢失),这时就需要重传定时器在指定的时间内重传数据,否则数据传输就可能会阻塞。
9.3.2 When
设置重传定时器的时机有:
(1)调用tcp_check_sack_reneging处理虚假SACK事件时:
1906 static bool tcp_check_sack_reneging(struct sock *sk, int flag)
1907 {
1908 if (flag & FLAG_SACK_RENEGING) {
1909 struct inet_connection_sock *icsk = inet_csk(sk);
1910 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING);
1911
1912 tcp_enter_loss(sk, 1);
1913 icsk->icsk_retransmits++;
1914 tcp_retransmit_skb(sk, tcp_write_queue_head(sk));
1915 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
1916 icsk->icsk_rto, TCP_RTO_MAX);
1917 return true;
1918 }
1919 return false;
1920 }
虚假SACK是指:最新收到的ACK的ack_seq指向已记录的SACK块,这说明记录的SACK并没有反应接收方的真实的状态,也就是说接收方现在已经处于严重拥塞的状态或者在处理上有bug,从而删除了乱序队列中的数据(这些数据之前是在SACK选项中发送过来的)。因为按照正常的逻辑流程,接收的ACK不应该指向已记录的SACK,而应该指向SACK后面未接收的地方(因为被SACK的报文是已经放入接收方的乱序队列中,如果收到缺失的段正常情况下会与乱序报文一起交付接收队列,从而使ack_seq指向被SACK的报文的后面)。所以接下来就按照超时重传的方式去处理。
(2)调用tcp_rearm_rto更新RTO时:
2926 void tcp_rearm_rto(struct sock *sk)
2927 {
2928 const struct inet_connection_sock *icsk = inet_csk(sk);
2929 struct tcp_sock *tp = tcp_sk(sk);
2930
2931 /* If the retrans timer is currently being used by Fast Open
2932 * for SYN-ACK retrans purpose, stay put.
2933 */
2934 if (tp->fastopen_rsk)
2935 return;
2936
2937 if (!tp->packets_out) { //网络中没有已发送的数据
2938 inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
2939 } else {
2940 u32 rto = inet_csk(sk)->icsk_rto;
2941 /* Offset the time elapsed after installing regular RTO */
2942 if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
2943 icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
2944 struct sk_buff *skb = tcp_write_queue_head(sk);
2945 const u32 rto_time_stamp = TCP_SKB_CB(skb)->when + rto;
2946 s32 delta = (s32)(rto_time_stamp - tcp_time_stamp);
2947 /* delta may not be positive if the socket is locked
2948 * when the retrans timer fires and is rescheduled.
2949 */
2950 if (delta > 0)
2951 rto = delta;
2952 }
2953 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto,
2954 TCP_RTO_MAX);
2955 }
2956 }
而调用tcp_rearm_rto并安装重传定时器的常见条件有:
1)收到ACK并确认掉数据时且仍然有未确认的数据时:
3001 static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
3002 u32 prior_snd_una)
3003 {
...
3095 if (flag & FLAG_ACKED) {
...
3105 tcp_rearm_rto(sk);
2)收到合法ACK并安装了ER定时器或丢失探测定时器时:
3325 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3326 {
...
3358 if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
3359 icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)
3360 tcp_rearm_rto(sk);
...
3)发送了新数据并调用tcp_event_new_data_sent函数时:
72 static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb)
73 {
74 struct inet_connection_sock *icsk = inet_csk(sk);
75 struct tcp_sock *tp = tcp_sk(sk);
76 unsigned int prior_packets = tp->packets_out;
77
78 t