TCP發送窗口更新tcp_ack_update_window


在tcp_ack接收ACK處理函數中,如果確認當前走慢速路徑,那么會調用tcp_ack_update_window函數檢查窗口是否需要更新並更新之,並且更新未確認數據的位置,即更新窗口左邊沿;

 1 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 2 {
 3     /* 快速路徑&& ack確認了新數據 */
 4     if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
 5                  ;
 6     } 
 7     /* 慢速路徑 */
 8     else {
 9         /* 更新發送窗口 */
10         flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
11         }
12 }

 

tcp_ack_update_window執行窗口更新主流程,函數首先根據窗口擴大因子計算實際的窗口大小,然后判斷是否需要更新窗口,若需要則對窗口進行更新,注意,只有當窗口不相等的情況下才會實際更新窗口,否則只更新最后一次窗口更新ack序號;窗口更新需要更新窗口,同步MSS,檢查是否開啟快速路徑等;函數最后還將設置未確認數據位置,即窗口左邊沿;

 1 /* Update our send window.
 2  *
 3  * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2
 4  * and in FreeBSD. NetBSD's one is even worse.) is wrong.
 5  */
 6 static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 ack,
 7                  u32 ack_seq)
 8 {
 9     struct tcp_sock *tp = tcp_sk(sk);
10     int flag = 0;
11     u32 nwin = ntohs(tcp_hdr(skb)->window);
12 
13     /* 根據擴大因子計算窗口大小 */
14     if (likely(!tcp_hdr(skb)->syn))
15         nwin <<= tp->rx_opt.snd_wscale;
16 
17     /* 需要更新窗口的話 */
18     if (tcp_may_update_window(tp, ack, ack_seq, nwin)) {
19         /* 窗口更新標記 */
20         flag |= FLAG_WIN_UPDATE;
21 
22         /* 記錄窗口更新的ack序號 */
23         tcp_update_wl(tp, ack_seq);
24 
25 
26         /* 發送窗口與通告窗口不等時 */
27         if (tp->snd_wnd != nwin) {
28 
29             /* 更新發送窗口*/
30             tp->snd_wnd = nwin;
31 
32             /* Note, it is the only place, where
33              * fast path is recovered for sending TCP.
34              */
35             /* 判斷是否開啟快路標志 */
36             tp->pred_flags = 0;
37             tcp_fast_path_check(sk);
38 
39             /* 有數據要發送 */
40             if (tcp_send_head(sk))
41                 tcp_slow_start_after_idle_check(sk);
42 
43             /* 窗口大於以前記錄的最大窗口 */
44             if (nwin > tp->max_window) {
45                 /* 更新最大窗口 */
46                 tp->max_window = nwin;
47                 /* 更新mss */
48                 tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie);
49             }
50         }
51     }
52 
53     /* 更新未確認的數據位置,即窗口左邊沿 */
54     tcp_snd_una_update(tp, ack);
55 
56     return flag;
57 }

 

tcp_may_update_window用於判斷窗口是否需要更新,滿足以下條件之一則更新:

(1) ACK確認了新的數據;

(2) 未滿足(1),ACK未確認數據,通過上面snd_una<=ack的條件,此時只能是snd_una=ack,即未確認新數據,是個重復ack,但是這個ack的序號比之前更新窗口的序號要新,則需要更新snd_wl1;

(3) 未滿足(1)(2),未確認數據,ack需要也未更新,但是窗口有所改變,則說明單單發送了一個窗口更新通知;

 1 /* Check that window update is acceptable.
 2  * The function assumes that snd_una<=ack<=snd_next.
 3  */
 4 static inline bool tcp_may_update_window(const struct tcp_sock *tp,
 5                     const u32 ack, const u32 ack_seq,
 6                     const u32 nwin)
 7 {
 8     /* 
 9         更新條件
10         ack確認序號確認了數據,意味着窗口要收縮
11         ack確認序號未確認新數據,ack序號比上一個更新窗口ack序號要新
12         ack序號與上一個更新裝ack序號一致,但是窗口比以前的窗口大
13     */
14     return    after(ack, tp->snd_una) ||
15         after(ack_seq, tp->snd_wl1) ||
16         (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd);
17 }

 


免責聲明!

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



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