TCP的初始cwnd和ssthresh
概述
linux 3.0以前,内核默认的initcwnd比较小,MSS为1460时,初始的拥塞控制窗口为3。
linux3.0以后,采取了Google的建议,把初始拥塞控制窗口调到了10。
Google's advice :《An Argument for Increasing TCP's Initial Congestion Window》
The recommended value of initcwnd is 10*MSS.
内核版本:linux-2.6.37
dst_entry
目的入口dst_entry反映了相邻的外部主机在主机内部的一种映像。
A dst_entry corresponds to the destination host bound to the socket.
A dst_entry object stores a lot of data used by the kernel whenever it sends a packet to
the corresponding remote host.
__u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst) { /* 取出路由中的initcwnd */ __u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0); /* 如果没有路由信息的话 */ if (! cwnd) cwnd = rfc3390_bytes_to_packets(tp->mss_cache); /* 不能超过snd_cwnd的最大值:snd_cwnd_clamp */ return min_t(__u32, cwnd, tp->snd_cwnd_clamp); }
根据MSS来决定initcwnd:
(1)MSS <= 1095,initcwnd = 4
(2)1095 < MSS <= 2190,initcwnd = 3
(3)MSS > 2190,initcwnd = 2
/* Convert RFC3390 larger initial window into an equivalent number of packets. * This is based on the numbers specified in RFC 6861, 3.1. */ static inline u32 rfc3390_bytes_to_packets(const u32 smss) { return smss <= 1095 ? 4 : (smss > 2190 ? 2 : 3); }
一般我们的MSS为1460,所以内核默认的TCP初始拥塞控制窗口为3。
内核版本:linux 3.2.12
内核初始的慢启动阈值(ssthresh)
/* 初始的慢启动阈值为无穷大*/ #define TCP_INFINITE_SSTHRESH 0x7fffffff /* 根据慢启动阈值来判断是否处于初始的慢启动阶段*/ static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp) { return tp->snd_ssthresh >= TCP_INFINITE_SSTHRESH; }
内核初始的拥塞窗口(initcwnd)
#define TCP_INIT_CWND 10 __u32 tcp_init_cwnd(const struct tcp_sock *tp, const struct dst_entry *dst) { /* 取出路由中的initcwnd */ __u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0); /* 如果没有相关的路由,则把初始值设为10 */ if (! cwnd) cwnd = TCP_INIT_CWND; /* 不能超过snd_cwnd的最大值:snd_cwnd_clamp */ return min_t(__u32, cwnd, tp->snd_cwnd_clamp); }
设置初始的ssthresh和cwnd
(1)ip route方法,对通过此路由的TCP连接有效。
设置:ip route change default via <gateway> dev <eth0> initcwnd <value1> ssthresh <value2>
查看:ip route show
注意:In order to make it effective after a reboot, you can place above line in /etc/rc.local.
(2)sysctl方法,对所有的TCP连接有效。
在内核中增加一个控制initcwnd的proc参数,/proc/sys/net/ipv4/tcp_initcwnd。
ip route是通过netlink来修改dst_entry中RTAX_INITCWND对应的值,而sysctl则可以直接在内核中
增加一个变量,它们都需要通过tcp_init_cwnd()来改变initcwnd。