TCP套接口的最大SYN队列长度

发布于:2023-01-22 ⋅ 阅读:(185) ⋅ 点赞:(0)

通过PROC文件查看队列长度,可见对于4G内存的系统,tcp_max_syn_backlog的值为128;对于8G内存的系统,其值为256。

# cat /proc/sys/net/ipv4/tcp_max_syn_backlog
128

/ # cat /proc/sys/net/ipv4/tcp_max_syn_backlog 
256
PROC文件tcp_max_syn_backlog控制处在TCP_SYN_RECV状态的TCP连接最大数,默认值为128。即接收到SYN报文并且已发送SYN+ACK但还未收到对端ACK响应的连接最大数,此数值为基于单个socket的控制。128为最小值,对于内存较大的机器,可适当调高此值。PROC文件变量定义如下:

static struct ctl_table ipv4_net_table[] = { 
    {
        .procname   = "tcp_max_syn_backlog",
        .data       = &init_net.ipv4.sysctl_max_syn_backlog,
    },
}

一、队列长度初始化
在函数tcp_sk_init中,初始化sysctl_max_syn_backlog,赋值为128与cnt的256分之一两个值之间的最大值。

static int __net_init tcp_sk_init(struct net *net)
{
    cnt = tcp_hashinfo.ehash_mask + 1;
    net->ipv4.sysctl_max_syn_backlog = max(128, cnt / 256);
}
其中cnt的值由tcp_hashinfo.ehash_mask决定,其在tcp_init函数中初始化。ehash_mask哈希掩码值为inet_ehash_bucket类型哈希表最大表项值减1,此处hash表的表项数值为2的幂值,其减一得到的掩码为一个全F的值。

void __init tcp_init(void)
{
    tcp_hashinfo.ehash =
        alloc_large_system_hash("TCP established",
                    sizeof(struct inet_ehash_bucket),
                    thash_entries,
                    17, /* one slot per 128 KB of memory */
                    0,
                    NULL,
                    &tcp_hashinfo.ehash_mask,
                    0,
                    thash_entries ? 0 : 512 * 1024);
}
需要注意的是tcp_hashinfo.ehash不仅包括已建立连接的TCP套接口,还包括除了在LISTEN状态的其它所有套接口。

/* This is for all connections with a full identity, no wildcards.
 * The 'e' prefix stands for Establish, but we really put all sockets
 * but LISTEN ones.
 */
struct inet_ehash_bucket {
    struct hlist_nulls_head chain;
};

二、队列长度判断逻辑
 
参见tcp_conn_request函数中的判断条件,在SYN Cookies功能未开启,并且当前请求套接口的队列长度(inet_csk_reqsk_queue_len)已经超过最大SYN队列长度值(sysctl_max_syn_backlog)的3/4后,仅接收已知客户端的SYN连接(tcp_peer_is_proven)。意味着最后1/4的额度保留给了最近连接过的客户端,未连接过的客户端在到达最大值的3/4后,就已经不能接入了。

int tcp_conn_request(struct request_sock_ops *rsk_ops, const struct tcp_request_sock_ops *af_ops, struct sock *sk, struct sk_buff *skb)
{
    __u32 isn = TCP_SKB_CB(skb)->tcp_tw_isn;
    bool want_cookie = false;
 
    if (!want_cookie && !isn) {
        if (!net->ipv4.sysctl_tcp_syncookies &&
            (net->ipv4.sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < (net->ipv4.sysctl_max_syn_backlog >> 2)) &&
            !tcp_peer_is_proven(req, dst)) {
            goto drop_and_release;
        }
    }
}
如果开启了TCP的SYN cookies功能并且检测到SYN flood行为,又或者SYN请求对应到一个之前处于TIME-WAIT状态的套接口,此两种情况不对新连接做SYN队列超限判断。

本文含有隐藏内容,请 开通VIP 后查看