從上面的概念中可以得知,擁塞窗口可以間接反映網絡的狀況,進而去限制發送窗口的大小。擁塞窗口作為網絡擁塞控制中核心變量之一,對網絡擁塞控制起到關鍵作用。在Linux內核中,關于網絡的核心結構體在:[Linux內核網絡基礎-TCP相關的幾個關鍵結構體-小記]中進行了介紹,如下圖是四個核心結構體,四個結構的關系具有面向對象的特征,通過層層繼承,實現了類的復用;內核中網絡相關的很多函數,參數往往都是struct sock,函數內部依照不同的業務邏輯,將struct sock轉換為不同的業務結構。
struct tcp_sock
從struct inet_connection_sock
結構體的基礎上繼承而來,在struct inet_connection_sock
上增加了一些tcp協議相關的字段,如滑動窗口協議,擁塞算法等一些TCP專有的屬性。由于這種繼承關系,可以互相轉換,如下舉例兩種轉換方式,第一種是struct sock轉換為struct tcp_sock,第二種是struct sock轉換成struct inet_connection_sock。。下面將struct tcp_sock展開可以看到與網絡擁塞控制相關的字段。
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
{
return (struct tcp_sock *)sk;
}
static inline struct inet_connection_sock *inet_csk(const struct sock *sk)
{
return (struct inet_connection_sock *)sk;
}
struct tcp_sock中定義的關于網絡擁塞控制相關的字段如下所示:
struct tcp_sock {//在 inet_connection_sock 基礎上增加了 滑動窗口 擁塞控制算法等tcp 專有 屬性
__be32 pred_flags;/*首部預測標志 在接收到 syn 跟新窗口 等時設置此標志 ,
此標志和時間戳 序號等 用于判斷執行 快速還是慢速路徑*/
u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived
* sum(delta(rcv_nxt)), or how many bytes
* were acked.
*/
u32 segs_in; /* RFC4898 tcpEStatsPerfSegsIn
* total number of segments in.
*/
u32 rcv_nxt; /* What we want to receive next 等待接收的下一個序列號 */
u32 copied_seq; /* Head of yet unread data */
/* rcv_nxt on last window update sent最早接收但沒有確認的序號, 也就是接收窗口的左端,
在發送ack的時候, rcv_nxt更新 因此rcv_wup 更新比rcv_nxt 滯后一些 */
u32 rcv_wup;
u32 snd_nxt; /* Next sequence we send 等待發送的下一個序列號 */
u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut
* The total number of segments sent.
*/
u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked
* sum(delta(snd_una)), or how many bytes
* were acked.
*/
struct u64_stats_sync syncp; /* protects 64bit vars (cf tcp_get_info()) */
u32 snd_una; /* First byte we want an ack for 最早一個未被確認的序號 */
u32 snd_sml; /* Last byte of the most recently transmitted small packet 最近發送一個小于mss的最后 一個字節序列號
在成功發送, 如果報文小于mss,跟新這個字段 主要用來判斷是否啟用 nagle 算法*/
u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) 最近一次收到ack的時間 用于 tcp 保活*/
u32 lsndtime; /* timestamp of last sent data packet (for restart window) 最近一次發送 數據包時間*/
u32 last_oow_ack_time; /* timestamp of last out-of-window ACK */
u32 tsoffset; /* timestamp offset */
struct list_head tsq_node; /* anchor in tsq_tasklet.head list */
unsigned long tsq_flags;
/* Data for direct copy to user cp 數據到用戶進程的控制塊 有用戶緩存以及其長度 prequeue 隊列 其內存*/
struct {
struct sk_buff_head prequeue // tcp 段 緩沖到此隊列 知道進程主動讀取才真正的處理;
struct task_struct *task;
struct msghdr *msg;
int memory;// prequeue 當前消耗的內存
int len;// 用戶緩存中 當前可以使用的緩存大小
} ucopy;
u32 snd_wl1; /* Sequence for window update記錄跟新發送窗口的那個ack 段號 用來判斷是否 需要跟新窗口
如果后續收到ack大于snd_wll 則表示需要更新 窗口*/
u32 snd_wnd; /* The window we expect to receive 接收方 提供的窗口大小 也就是發送方窗口大小 */
u32 max_window; /* Maximal window ever seen from peer 接收方通告的最大窗口 */
u32 mss_cache; /* Cached effective mss, not including SACKS 發送方當前有效的mss*/
u32 window_clamp; /* Maximal window to advertise 滑動窗口最大值 */
u32 rcv_ssthresh; /* Current window clamp 當前接收窗口的閾值 */
......
u32 snd_ssthresh; /* Slow start size threshold 擁塞控制 滿啟動閾值 */
u32 snd_cwnd; /* Sending congestion window 當前擁塞窗口大小 ---發送的擁塞窗口 */
u32 snd_cwnd_cnt; /* Linear increase counter 自從上次調整擁塞窗口后 到目前位置接收到的
總ack段數 如果該字段為0 表示調整擁塞窗口但是沒有收到ack,調整擁塞窗口之后 收到ack段就回讓
snd_cwnd_cnt 加1 */
u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this snd_cwnd 的最大值*/
u32 snd_cwnd_used;//記錄已經從隊列發送而沒有被ack的段數
u32 snd_cwnd_stamp;//記錄最近一次檢驗cwnd 的時間; 擁塞期間 每次會檢驗cwnd而調節擁塞窗口 ,
//在非擁塞期間,為了防止應用層序造成擁塞窗口失效 因此在發送后 有必要檢測cwnd
u32 prior_cwnd; /* Congestion window at start of Recovery.在進入 Recovery 狀態時的擁塞窗口 */
u32 prr_delivered; /* Number of newly delivered packets to在恢復階段給接收者新發送包的數量
* receiver in Recovery. */
u32 prr_out; /* Total number of pkts sent during Recovery.在恢復階段一共發送的包的數量 */
u32 rcv_wnd; /* Current receiver window 當前接收窗口的大小 */
u32 write_seq; /* Tail(+1) of data held in tcp send buffer 已加入發送隊列中的最后一個字節序號*/
u32 notsent_lowat; /* TCP_NOTSENT_LOWAT */
u32 pushed_seq; /* Last pushed seq, required to talk to windows */
u32 lost_out; /* Lost packets丟失的數據報 */
u32 sacked_out; /* SACK'd packets啟用 SACK 時,通過 SACK 的 TCP 選項標識已接收到的段的數量。
不啟用 SACK 時,標識接收到的重復確認的次數,該值在接收到確認新數據段時被清除。 */
u32 fackets_out; /* FACK'd packets FACK'd packets 記錄 SND.UNA 與 (SACK 選項中目前接收方收到的段中最高序號段) 之間的段數。FACK
用 SACK 選項來計算丟失在網絡中上的段數 lost_out=fackets_out-sacked_out left_out=fackets_out */
/* from STCP, retrans queue hinting */
struct sk_buff* lost_skb_hint; /*在重傳隊列中, 緩存下次要標志的段*/
struct sk_buff *retransmit_skb_hint;/* 表示將要重傳的起始包*/
/* OOO segments go in this list. Note that socket lock must be held,
* as we do not use sk_buff_head lock.
*/
struct sk_buff_head out_of_order_queue;
/* SACKs data, these 2 need to be together (see tcp_options_write) */
struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
struct tcp_sack_block recv_sack_cache[4];
struct sk_buff *highest_sack; /* skb just after the highest
* skb with SACKed bit set
* (validity guaranteed only if
* sacked_out > 0)
*/
int lost_cnt_hint;/* 已經標志了多少個段 */
u32 retransmit_high; /* L-bits may be on up to this seqno 表示將要重傳的起始包 */
u32 prior_ssthresh; /* ssthresh saved at recovery start表示前一個snd_ssthresh得大小 */
u32 high_seq; /* snd_nxt at onset of congestion擁塞開始時,snd_nxt的大----開始擁塞的時候下一個要發送的序號字節*/
u32 retrans_stamp; /* Timestamp of the last retransmit,
* also used in SYN-SENT to remember stamp of
* the first SYN. */
u32 undo_marker; /* snd_una upon a new recovery episode. 在使用 F-RTO 算法進行發送超時處理,或進入 Recovery 進行重傳,
或進入 Loss 開始慢啟動時,記錄當時 SND.UNA, 標記重傳起始點。它是檢測是否可以進行擁塞控制撤銷的條件之一,一般在完成
擁塞撤銷操作或進入擁塞控制 Loss 狀態后會清零。*/
int undo_retrans; /* number of undoable retransmissions. 在恢復擁塞控制之前可進行撤銷的重傳段數。
在進入 FTRO 算法或 擁塞狀態 Loss 時,清零,在重傳時計數,是檢測是否可以進行擁塞撤銷的條件之一。*/
u32 total_retrans; /* Total retransmits for entire connection */
u32 urg_seq; /* Seq of received urgent pointer 緊急數據的序號 所在段的序號和緊急指針相加獲得*/
unsigned int keepalive_time; /* time before keep alive takes place */
unsigned int keepalive_intvl; /* time interval between keep alive probes */
int linger2;
/* Receiver side RTT estimation */
struct {
u32 rtt;
u32 seq;
u32 time;
} rcv_rtt_est;
/* Receiver queue space */
struct {
int space;
u32 seq;
u32 time;
} rcvq_space;
/* TCP-specific MTU probe information. */
struct {
u32 probe_seq_start;
u32 probe_seq_end;
} mtu_probe;
u32 mtu_info; /* We received an ICMP_FRAG_NEEDED / ICMPV6_PKT_TOOBIG
* while socket was owned by user.
*/
#ifdef CONFIG_TCP_MD5SIG
const struct tcp_sock_af_ops *af_specific;
struct tcp_md5sig_info __rcu *md5sig_info;
#endif
struct tcp_fastopen_request *fastopen_req;
struct request_sock *fastopen_rsk;
u32 *saved_syn;
};
-
Linux
+關注
關注
87文章
11304瀏覽量
209498 -
網絡
+關注
關注
14文章
7565瀏覽量
88788 -
控制算法
+關注
關注
4文章
166瀏覽量
21723
發布評論請先 登錄
相關推薦
評論