一、介紹
FACK的全稱是forward acknowledgement,FACK通過記錄SACK塊中系列號最大(forward-most)的SACK塊來推測丟包信息,在linux中使用fackets_out這個狀態變量來記錄FACK信息。我們之前介紹SACK重傳時候說過在SACK下需要3個dup ACK來觸發快速重傳(3個為默認值),而SACK下的dup ACK的定義與傳統的非SACK下定義又略有不同(詳細請參考前面的文章和示例)。當使能FACK的時候,實際上我們可以通過一個SACK塊信息來推測丟包情況進而觸發快速重傳。比如server端依次發出P1(0-9)、P2(10-19)、P3(20-29)、P4(30-39)、P5(40-49),假設client端正常收到了P1包並回復了ACK確認包,P2、P3、P4則由於網絡擁塞等原因丟失,client在收到P5時候回復一個Ack=10的確認包,並攜帶P5有SACK塊信息(40-50),這樣server在收到P1的確認包和P5的dup ACK時候,就可以根據dup ACK中的SACK信息得知client端收到了P1報文和P5報文,計算出P1和P5兩個數據包中間間隔了3個數據包,達到了dup ACK門限(默認為3),進而推測出P2報文丟失。
SACK reneging我們在前面SACK中已經介紹了,下面我們通過示例來一起看一下FACK和SACK reneging下的重傳。
二、wireshark示例
1、tcp_early_retrans=0,tcp_retrans_collapse=0,tcp_discard_on_port =9877,tcp_sack=1,tcp_fack=1;場景下的重傳如下圖所示:
-
server端依次發送No6-No10五個數據包
-
client收到No6后回復一個不帶有SACK選項的ACK確認包(No11),server端正常接收到這個ACK確認包
-
接着client模擬No7-No9數據包丟包,在收到No10亂序包的時候,回復一個dup ACK,其中包含SACK信息(33-41),
-
server端收到這個dup ACK后推測處client端已經收到No6和No10報文,中間間隔的報文個數為3個,達到dup ACK門限,進而觸發快速重傳。
-
client繼續模擬丟包,接着server端RTO超時,進行指數回退過程。
-
直到No16重傳后,client開始回復不帶有SACK選項的ACK(partial ACK),但是因為ack number並沒有落在33-40之間,此時linux並不會確認發生了SACK reneging。這個ACK觸發快速重傳(No18)。受限與擁塞控制,這個時候只能發送一個重傳包,發送完這個重傳報文后根據收到的ACK更新擁塞窗口,擁塞窗口自增1,因此此時可以發送一個新的數據包,但是因為緩存中沒有新的待發送數據因此並沒有新數據包傳出。
-
接收client回復No19的ACK確認包(partial ACK),這個ACK報文雖然不帶有SACK選項,但是linux同樣不會確認發生了SACK reneging,server端根據這個partial ACK觸發快速重傳,在上一步中擁塞窗口已經自增了1,因此實際上快速重傳可以重傳兩個TCP報文但是因為重傳完No20后,只剩下一個報文待重傳,而這個報文之前又被SACK過,因此快速重傳不會重傳這個報文
-
接着client回復不帶有SACK選項的No21確認包,Ack=33,注意之前觸發FACK快速重傳的時候反饋的SACK塊信息是(33-41)告訴server端收到了No10數據包,而這個新回復的No21確認包又告訴server沒有收到No10確認包。此時就是發生了SACK reneging。在這個ACK確認包觸發快速重傳時候,就會檢測是否發生了SACK seneging,如果發生SACK reneging,linux會初始化一個RTO定時器,定時器的定時時間為RTT/2。快速重傳時候檢測到了SACK seneging就會直接退出。
-
接着上一步的RTO定時器超時,觸發了No22的RTO超時重傳,client回復對應的ACK確認包,整個傳輸過程結束。
2、tcp_early_retrans=0,tcp_retrans_collapse=0,tcp_discard_on_port =9877,tcp_sack=1,tcp_fack=0;這里我們關閉FACK功能,其他設置不變重新進行類似上面的測試
可以看到這個示例與上面示例的主要差異就是No12的dup ACK雖然同樣反饋了No10的SACK信息,但是並沒有觸發快速重傳。其他內容與上面示例基本一致不再重復介紹。
3、tcp_early_retrans=0,tcp_retrans_collapse=0,tcp_discard_on_port =9877,tcp_sack=1,tcp_fack=1;低於dup ACK門限
這個示例和示例1不同的地方在於No12的dup ACK確認包攜帶的SACK信息為(25-33),也就是通過SACK確認了No9報文,No9與No6報文之間間隔了2個報文沒有達到dup ACK的門限,因此並不會觸發快速重傳。注意server端在收到No19確認包時候觸發了快速重傳流程,但是快速重傳前檢測到SACK seneging,重啟了RTO定時器並退出快速重傳。
補充說明:
1、SACK seneging的檢測和RTO定時器的設置參考linux內核tcp_check_sack_reneging函數



