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。

原文地址:https://www.cnblogs.com/aiwz/p/6333380.html