TCP是一個複雜的協議,這種複雜來源於對報文傳輸的可靠性承諾。對每條TCP鏈接來講,除了有獨立的狀態機、定時器以外,還有擁塞控制相關的一些運行變量,好比RTT、CWND、SSTHRESH等,這些運行參數一樣也是每鏈接(Per-Connection
)的linux
Per-Connection
意味着每條鏈接的這些參數互不影響,這是理所應當的!可是,想一想這個情景:A與B之間已經創建了一條穩定的TCP鏈接,此時若新建一條新的鏈接,它的參數該如何設置呢?顯然,和原鏈接保持一致是個快速達到穩定的辦法。這就比如一我的要去一個陌生的地方,殊不知道該選擇哪一種交通工具,也不知道該預估多少時間,對他來講,汲取去過的人的經驗老是一條捷徑。數組
這就是Linux內核中TCP Metrics
框架的做用,它能夠爲後續的鏈接提供指導。當主機之間須要頻繁創建和拆除TCP鏈接時,它帶來的好處更加明顯。網絡
TCP Metrics
顯然不能是Per-Connection
的,而應該是Per-Destination
的。也就是說,TCP Metrics
表項應該是基於<源IP,目的IP>
二元組的。從一臺主機的角度,到達另外一個特定地址主機的網絡鏈路情況應該是被兩臺主機之間的全部鏈接所共享的。框架
內核使用tcp_metrics_block
表示一條Metrics
表項,這些表項根據<源IP,目的IP>
組織在tcp_metrics_hash
衝突鏈表表中,記錄的值保存在內部tcpm_vals
數組tcp
struct tcp_metrics_block { struct tcp_metrics_block __rcu *tcpm_next; struct inetpeer_addr tcpm_saddr; struct inetpeer_addr tcpm_daddr; ...... u32 tcpm_vals[TCP_METRIC_MAX_KERNEL + 1]; ...... };
當新建TCP鏈接時,內核使用下面的接口來爲TCP套接字設置TCP Metrics
指導下的參數工具
void tcp_init_metrics(struct sock *sk)
當某條TCP鏈接收的運行參數發生變化時,好比從新計算RTT了,內核會使用下面的接口來更新它對應的TCP Metrics
表項。切記,TCP Metrics
表項是Per-Destination
的,所以,多條TCP鏈接的套接字可能會更新同一條表項。code
void tcp_update_metrics(struct sock *sk)
內核一樣提供
ip-tcp_metrics命令查看主機上的
TCP Metrics
表項.