TCP系列10—連接管理—9、syncookie、fastopen與backlog


這部分內容涉及較多linux實現,可以跳過。

一、listen系統調用對backlog的處理

  1. 當socket處於LISTEN或者CLOSED狀態時,fastopen隊列的長度可以通過TCP_FASTOPEN選項進行設置。

  2. 對於listen的入參backlog,內核會限制backlog=min(backlog,/proc/sys/net/core/somaxconn)

  3. 如果當前打開了TFO的server端開關(tcp_fastopen的0x2有效),並且fastopen隊列的最大長度還沒通過選項設置,此時若tcp_fastopen的0x400有效,則初始化fastopenq.max_qlen=backlog,若tcp_fastopen的0x800有效,則初始化fastopenq.max_qlen=min(backlog,tcp_fastopen>>16)。fastopenq.max_qlen限制了fastopen邏輯隊列和fastopen的RST隊列的總長度

  4. 更新sk->sk_max_ack_backlog = backlog,sk_max_ack_backlog同時限制了半連接邏輯隊列和accept隊列的長度


Accetp隊列判斷條件是>,半連接邏輯隊列和fastopen判斷條件是>=


二、對SYN報文的處理

  1. 當內核編譯打開CONFIG_SYN_COOKIES選項的時候,只要滿足下面兩個條件中的一個則啟用syncookie:

    ①、tcp_syncookies為2。

    ②、tcp_syncookies為1,半連接邏輯隊列滿,SYN報文不是timewait轉過來的。

    如果半連接隊列滿,且這個SYN報文不是timewait轉過來的,這種場景下,如果tcp_syncookies=0,則會直接丟掉這個SYN報文。



  2. 如果全連接隊列滿,並且半連接邏輯隊列中還有未重傳的synack報文,那么直接丟掉這個syn報文。

  3. 當依據上面判斷不需要啟用syncookie的時候,則會判斷是否使能fastopen,其中當fastopen邏輯隊列和fastopen的RST隊列總長度超過fastopenq.max_qlen並且fast open的rst隊列沒有可以釋放的節點的時候,則不會啟用fastopen。

  4. 如果啟動了syncookie,那么req使用后會釋放,不會添加到半連接邏輯隊列也不會添加到accept隊列

  5. 如果啟用了fastopen,那么req將會直接添加到accept隊列,如果accept隊列滿,則啟動fastopen隊列失敗。

  6. 如果未啟動syncookie也未啟用fastopen,那么把req添加到半連接邏輯隊列


三、三次握手最后ACK的處理

如果在處理SYN報文的時候,啟用了syncookie,此時校驗syncookie通過,但是accept隊列滿的時候,丟棄報文。

fastopen在接收到SYN報文的時候就已經處理了半連接邏輯隊列和accept隊列。

如果對應的連接即沒有啟用syncookie,也沒有啟用fastopen,那么accept隊列滿的時候按照如下處理

tcp_abort_on_overflow=0場景下,直接丟掉這個報文

tcp_abort_on_overflow=1場景下,回復RST。


補充:

另外reqsk_timer_handler重傳函數中,如果(qlen << 1) > max(8U,sk_max_ack_backlog),即半連接隊列已經使用了一半以上的時候,則會對重傳次數進行回退。

另外還有一個設置參數:tcp_max_syn_backlog,當設置tcp_syncookies=0來關閉syncookie功能的時候,如果半連接請求隊列的長度超過了(3/4)*tcp_max_syn_backlog,那么新接收的SYN報文需要在tcp_metric緩存中驗證通過后才能接收這個連接,否則直接丟掉SYN報文。


四、wireshark示例

1、默認設置下tcp_syncookies=1、tcp_abort_on_overflow=0,listen入參backlog設置為5,場景如下圖所示,當啟用syncookie的時候,TSval的低四位表示接收到的window scale,第五位表示SACK,第六位表示ECN。

首先No1、No3、No5、No7、No9五個數據包填滿了半連接邏輯隊列,因此從下圖Timestamp value列可以看到No11、No13、No15、No17啟用了syncookie。

接着No19報文把20001端口對應的連接從半連接隊列轉移到了accept隊列。此時半連接邏輯隊列空閑出一個位置。

No20這個SYN報文對應的req重新添加到了半連接隊列,可以從圖中看到並沒有啟用syncookie。

No22-No25這幾個數據包對應的連接之前位於半連接對應,可以被server正常接收處理並建立連接。

No26:這個對應之前啟用了syncookie的No11,因為accept隊列滿的判斷標准是大於等於,因此accept隊列相比半連接隊列可以多接收一個連接,No26正常建立連接。

No27、No28、No29、No32:這幾個報文同樣因為accept隊列滿而不能建立連接。但是No32報文對應的連接保存於半連接隊列中,而No27-No29是通過syncookie響應的SYN報文。至此總共建立了6個連接,對應client端口號為20001-20006。

接着client嘗試發送數據的時候可以看到,對應端口20007-20010的client數據包No43-No46,server端都沒有響應,說明連接並沒有建立起來。

No47-No51:因為端口20010的連接存在於半連接隊列中,因此會觸發synack的重傳。而端口20007-20009的連接通過syncookie響應SYN連接請求,並不會觸發synack重傳。


2、設置tcp_syncookies=1、tcp_abort_on_overflow=1,重復上面的測試,唯一的差異就在於端口號為20010的連接。如下圖所示,因此該連接處於半連接邏輯隊列里面,而server端接收到三次握手的ACK報文的時候全連接隊列滿,因此直接回復RST,abort這個連接。















免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM