共计 1049 个字符,预计需要花费 3 分钟才能阅读完成。
TCP 是一个复杂的协议,这种复杂来源于对报文传输的可靠性承诺。对每条 TCP 连接来说 ,除了有独立的状态机、定时器之外,还有拥塞控制相关的一些运行变量,比如RTT、CWND、SSTHRESH 等,这些运行参数同样也是每连接 (Per-Connection
) 的
Per-Connection
意味着每条连接的这些参数互不影响,这是理所应当的!但是,想想这个情景:A 与 B 之间已经建立了一条稳定的 TCP 连接,此时若新建一条新的连接,它的参数该如何设置呢?显然,和原连接保持一致是个快速达到稳定的办法。这就好比一个人要去一个陌生的地方,却不知道该选择哪种交通工具,也不知道该预估多少时间,对他来说,汲取去过的人的经验总是一条捷径。
这就是 Linux 内核中 TCP Metrics
框架的作用,它可以为后续的连接提供指导 。当主机之间需要频繁 建立 和拆除TCP 连接时,它带来的好处更加明显。
TCP Metrics
显然不能是 Per-Connection
的,而应该是 Per-Host
的。也就是说,TCP Metrics
表项应该是基于 < 源 IP, 目的 IP>
二元组的。从一台主机的角度,到达另一个特定地址主机的网络链路状况应该是被两台主机之间的所有连接所 共享 的。
内核使用 tcp_metrics_block
表示一条 Metrics
表项,这些表项根据 < 源 IP, 目的 IP>
组织在 tcp_metrics_hash
冲突链表表中,记录的值保存在内部 tcpm_vals
数组
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-Host
的,因此,多条 TCP 连接的套接字可能会更新同一条表项。
void tcp_update_metrics(struct sock *sk)
内核同样提供 ip-tcp_metrics 命令查看主机上的
TCP Metrics
表项.