• TCP的连接套接口哈希表初始化


    在tcp_init中,初始化已建立连接的套接口哈希列表ehash,其中e代表Established。

    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状态的其它所有状态的套接口。

    函数alloc_large_system_hash用来分配哈希表,其逻辑如下。首先如果参数中没有指定要分配的表项数量(numentries),则将其赋值为系统的内核页面数nr_kernel_pages,之后再减去特定处理器架构预留的内核页面。之后再将此页面数量按照每兆M字节所对应的页面数进行对其,即如果1M字节包括4个页面,则将numentries以4对其,至此,表项数量与页面数量还是相同的。

    接下来是scale比例缩放的处理,scale是以2的幂值给定,与PAGE_SHIFT相同(通常情况下为12,即4K大小页面),如果scale参数值大于PAGE_SHIFT,对于tcp_hashinfo.ehash而言即是这种情况,其传入的scale值为17(128K),二者差值为5(32),右移5位相当于除以32,32个页面的大小为32*PAGE_SHIFT,按照4K页面计算32个页面大小为128K。

    对于tcp_hashinfo.ehash哈希,意味着128K内存空间一个hash桶,此时numentries与页面数量不在相同,而是以2^scale次方为单位的数量。

        if (!numentries) {
            /* round applicable memory size up to nearest megabyte */
            numentries = nr_kernel_pages;
            numentries -= arch_reserved_kernel_pages();
     
            /* It isn't necessary when PAGE_SIZE >= 1MB */
            if (PAGE_SHIFT < 20)
                numentries = round_up(numentries, (1<<20)/PAGE_SIZE);
     
            /* limit to 1 bucket per 2^scale bytes of low memory */
            if (scale > PAGE_SHIFT)
                numentries >>= (scale - PAGE_SHIFT);
            else
                numentries <<= (PAGE_SHIFT - scale);
        }

    如果参数中指定了要分配的numentries表项数量,将其roundup到最相近的2的幂运算的结果值。对于以上自计算得到表项数量numentries同样执行以下操作。

        numentries = roundup_pow_of_two(numentries);
    在确定了哈希表项数量(numentries)之后,接下来分配所需的内存空间。对于tcp_hashinfo.ehash而言,其bucketsize为sizeof(struct inet_ehash_bucket)的大小。log2qty为表项数量的2的幂值,此值之后将用于计算函数回填的哈希表掩码值。实际分配空间的大小size,为bucketsize右移log2qty位得到,如果分配失败,递减log2qty的值,即将分配空间减少一半,直到分配成功或者size小到不足一个页面的大小为止。

        log2qty = ilog2(numentries);
     
        do {
            size = bucketsize << log2qty;
     
                if (get_order(size) < MAX_ORDER) {
                    table = alloc_pages_exact(size, gfp_flags);
                    kmemleak_alloc(table, size, 1, gfp_flags);
                }
        } while (!table && size > PAGE_SIZE && --log2qty);
    哈希的shift和掩码值的计算就很简单了,以下运算最终得到一个全F的掩码值。

        if (_hash_shift)
            *_hash_shift = log2qty;
        if (_hash_mask)
            *_hash_mask = (1 << log2qty) - 1;
    如下函数inet_ehash_bucket所示,hashinfo->ehash_mask(同_hash_mask)加上1实际上表示为哈希表的最大数量。

    static inline struct inet_ehash_bucket *inet_ehash_bucket(struct inet_hashinfo *hashinfo, unsigned int hash)
    {
        return &hashinfo->ehash[hash & hashinfo->ehash_mask];

     

  • 相关阅读:
    指数族分布与相关性质(1) 定义、联合分布、微分性质
    [8]xss你清楚吗
    如何做好测试?(五)性能测试(Performance Testing, PT)
    鲸探发布点评:9月8日发售《汝阳黄河巨龙》数字藏品
    SpringBoot项目 nohup启动运行日志过大问题
    第一章 作业【数据库原理】
    vue2学习之axios在项目中的优化
    Concanavalin A-N3,叠氮修饰刀豆球蛋白A,azide-Con A
    KestrelServer详解[3]: 自定义一个迷你版的KestrelServer
    centos7创建ramdisk
  • 原文地址:https://blog.csdn.net/wuyongmao/article/details/126285355