9.5.1 Why
在9.4節中,我們瞭解到如果擁塞窗口較小且數據的最後一段數據丟失時,快速重傳算法會因爲無法收到足夠數量的ACK而無法及時重傳丟失的報文。尾部丟失探測(Tail Loss Probe)定時器就是爲了解決這個問題而設計的。
9.5.2 When
TLP在tcp_schedule_loss_probe函數中安裝:
1913 bool tcp_schedule_loss_probe(struct sock *sk)
1914 {
1915 struct inet_connection_sock *icsk = inet_csk(sk);
1916 struct tcp_sock *tp = tcp_sk(sk);
1917 u32 timeout, tlp_time_stamp, rto_time_stamp;
1918 u32 rtt = tp->srtt >> 3;
1919
1920 if (WARN_ON(icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS))
1921 return false;
1922 /* No consecutive loss probes. */
1923 if (WARN_ON(icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)) {
1924 tcp_rearm_rto(sk);
1925 return false;
1926 }
1927 /* Don't do any loss probe on a Fast Open connection before 3WHS
1928 * finishes.
1929 */
1930 if (sk->sk_state == TCP_SYN_RECV)
1931 return false;
1932
1933 /* TLP is only scheduled when next timer event is RTO. */
1934 if (icsk->icsk_pending != ICSK_TIME_RETRANS)
1935 return false;
1936
1937 /* Schedule a loss probe in 2*RTT for SACK capable connections
1938 * in Open state, that are either limited by cwnd or application.
1939 */
1940 if (sysctl_tcp_early_retrans < 3 || !rtt || !tp->packets_out ||
1941 !tcp_is_sack(tp) || inet_csk(sk)->icsk_ca_state != TCP_CA_Open)
1942 return false;
1943
1944 if ((tp->snd_cwnd > tcp_packets_in_flight(tp)) &&
1945 tcp_send_head(sk))
1946 return false;
1947
1948 /* Probe timeout is at least 1.5*rtt + TCP_DELACK_MAX to account
1949 * for delayed ack when there's one outstanding packet.
1950 */
1951 timeout = rtt << 1;
1952 if (tp->packets_out == 1)
1953 timeout = max_t(u32, timeout,
1954 (rtt + (rtt >> 1) + TCP_DELACK_MAX));
1955 timeout = max_t(u32, timeout, msecs_to_jiffies(10));
1956
1957 /* If RTO is shorter, just schedule TLP in its place. */
1958 tlp_time_stamp = tcp_time_stamp + timeout;
1959 rto_time_stamp = (u32)inet_csk(sk)->icsk_timeout;
1960 if ((s32)(tlp_time_stamp - rto_time_stamp) > 0) {
1961 s32 delta = rto_time_stamp - tcp_time_stamp;
1962 if (delta > 0)
1963 timeout = delta;
1964 }
1965
1966 inet_csk_reset_xmit_timer(sk, ICSK_TIME_LOSS_PROBE, timeout,
1967 TCP_RTO_MAX);
1968 return true;
1969 }
TCP在收到ACK時會調用tcp_schedule_loss_probe:3325 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3326 {
...
3439 if (icsk->icsk_pending == ICSK_TIME_RETRANS)
3440 tcp_schedule_loss_probe(sk);
...
發送最後一個數據時也會調用tcp_schedule_loss_probe嘗試安裝TLP:
1811 static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
1812 int push_one, gfp_t gfp)
1813 {
...
1900 if (likely(sent_pkts)) {
...
1904 /* Send one loss probe per tail loss episode. */
1905 if (push_one != 2) //不是在TLP定時器超時函數中發送的數據
1906 tcp_schedule_loss_probe(sk);
下面總結一下TLP安裝的條件:
(1)安裝了重傳定時器,這時可能需要拆除重傳定時器,改裝TLP;如果沒有安裝重傳定時器,說明沒有數據需要重傳,也就不需要TLP了
(2)沒有安裝ER定時器;ER定時器負責重傳丟失的中間數據,只有將中間數據補全了才能重傳尾部數據
(3)沒有安裝TLP定時器;重新安裝TLP定時器相當於延長定時器超時時間
(4)在TFO模式下server端會在發送SYN|ACK後設置重傳定時器以便重傳SYN|ACK,但在三次握手完成之前不能進行丟失探測
(5)net.ipv4.tcp_early_retrans內核參數 < 3
(6)tp->srtt >= 8
(7)有包在網絡中
(8)開啓SACK
(9)擁塞狀態爲TCP_CA_Open
(10)網絡中的包的長度 <= 擁塞窗口大小或沒有數據等待發送
TCP在安裝重傳定時器、ER定時器或堅持定時器時的同時TLP就會被拆除。
TLP的超時時間是根據RTT動態計算的。
9.5.3 What
TLP的超時函數是tcp_send_loss_probe:
1974 void tcp_send_loss_probe(struct sock *sk)
1975 {
1976 struct tcp_sock *tp = tcp_sk(sk);
1977 struct sk_buff *skb;
1978 int pcount;
1979 int mss = tcp_current_mss(sk);
1980 int err = -1;
1981
1982 if (tcp_send_head(sk) != NULL) { //如果還有數據發送
1983 err = tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); //則發送之
1984 goto rearm_timer;
1985 }
1986
1987 /* At most one outstanding TLP retransmission. */
1988 if (tp->tlp_high_seq) //已經有一個由TLP定時器發送的報文在網絡中了
1989 goto rearm_timer;
1990
1991 /* Retransmit last segment. */
1992 skb = tcp_write_queue_tail(sk); //得到發送隊列最後一個skb,即已發送的最後一個skb
1993 if (WARN_ON(!skb))
1994 goto rearm_timer;
1995
1996 pcount = tcp_skb_pcount(skb);
1997 if (WARN_ON(!pcount))
1998 goto rearm_timer;
1999
2000 if ((pcount > 1) && (skb->len > (pcount - 1) * mss)) {
2001 if (unlikely(tcp_fragment(sk, skb, (pcount - 1) * mss, mss)))
2002 goto rearm_timer;
2003 skb = tcp_write_queue_tail(sk);
2004 }
2005
2006 if (WARN_ON(!skb || !tcp_skb_pcount(skb)))
2007 goto rearm_timer;
2008
2009 /* Probe with zero data doesn't trigger fast recovery. */
2010 if (skb->len > 0)
2011 err = __tcp_retransmit_skb(sk, skb); //重傳最後一個數據段
2012
2013 /* Record snd_nxt for loss detection. */
2014 if (likely(!err))
2015 tp->tlp_high_seq = tp->snd_nxt;
2016
2017 rearm_timer:
2018 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
2019 inet_csk(sk)->icsk_rto,
2020 TCP_RTO_MAX); //設置重傳定時器
2021
2022 if (likely(!err))
2023 NET_INC_STATS_BH(sock_net(sk),
2024 LINUX_MIB_TCPLOSSPROBES);
2025 return;
2026 }
2000-2003:如果skb使用了GSO導致其由多個段構成且其數據過長,則將其分割後再取最後一個skb可見TLP定時器的超時動作主要是重傳最後一個報文段並設置重傳定時器。