高性能网络I/O框架-netmap源码分析(3)

简介: 高性能网络I/O框架-netmap源码分析(3) 作者:gfree.wind@gmail.com 博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net 微博:weibo.com/glinuxer QQ技术群:4367710 前面学习了netmap对e1000网卡驱动的修改,今天开始进入netmap的核心代码。

高性能网络I/O框架-netmap源码分析(3)

作者:gfree.wind@gmail.com
博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
微博:weibo.com/glinuxer
QQ技术群:4367710

前面学习了netmap对e1000网卡驱动的修改,今天开始进入netmap的核心代码。一切从init开始。。。

netmap_init

Linux环境下,netmap使用动态模块加载,由linuxnetmapinit调用netmap_init。

static int
netmap_init(void)
{
    int error;

    /* 
    申请netmap的各个内存池,包括netmap_if,netmap_ring,netmap_buf以及内存池的管理结构
    */
    error = netmap_memory_init();
    if (error != 0) {
        printf("netmap: unable to initialize the memory allocator.\n");
        return (error);
    }
    printf("netmap: loaded module with %d Mbytes\n",
        (int)(nm_mem->nm_totalsize >> 20));

    /* 
    在Linux上,调用的实际上是misc_register。make_dev为一共宏定义。
    创建一个名为netmap的misc设备,作为userspace和kernel的接口
    */
    netmap_dev = make_dev(&netmap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660,
                  "netmap");

#ifdef NM_BRIDGE
    {
        int i;
        for (i = 0; i 

netmapmemoryinit

netmap目前有两套内存分配管理代码,一个是netmapmem1.c,另一个是netmapmem2.c。默认使用的是后者。

static int
netmap_memory_init(void)
{
    struct netmap_obj_pool *p;

    /* 先申请netmap内存管理结构 */
    nm_mem = malloc(sizeof(struct netmap_mem_d), M_NETMAP,
                  M_WAITOK | M_ZERO);
    if (nm_mem == NULL)
        goto clean;

    /* netmap_if的内存池 */
    p = netmap_new_obj_allocator("netmap_if",
        NETMAP_IF_MAX_NUM, NETMAP_IF_MAX_SIZE);
    if (p == NULL)
        goto clean;
    nm_mem->nm_if_pool = p;

    /* netmap_ring的内存池 */
    p = netmap_new_obj_allocator("netmap_ring",
        NETMAP_RING_MAX_NUM, NETMAP_RING_MAX_SIZE);
    if (p == NULL)
        goto clean;
    nm_mem->nm_ring_pool = p;

    /* netmap_buf的内存池 */
    p = netmap_new_obj_allocator("netmap_buf",
        NETMAP_BUF_MAX_NUM, NETMAP_BUF_SIZE);
    if (p == NULL)
        goto clean;

    /* 对于netmap_buf,为了以后的使用方便,将其中的一些信息保存到其它明确的全局变量中 */
    netmap_total_buffers = p->objtotal;
    netmap_buffer_lut = p->lut;
    nm_mem->nm_buf_pool = p;
    netmap_buffer_base = p->lut[0].vaddr;


    mtx_init(&nm_mem->nm_mtx, "netmap memory allocator lock", NULL,
         MTX_DEF);

    nm_mem->nm_totalsize =
        nm_mem->nm_if_pool->_memtotal +
        nm_mem->nm_ring_pool->_memtotal +
        nm_mem->nm_buf_pool->_memtotal;

    D("Have %d KB for interfaces, %d KB for rings and %d MB for buffers",
        nm_mem->nm_if_pool->_memtotal >> 10,
        nm_mem->nm_ring_pool->_memtotal >> 10,
        nm_mem->nm_buf_pool->_memtotal >> 20);
    return 0;

clean:
    if (nm_mem) {
        netmap_destroy_obj_allocator(nm_mem->nm_ring_pool);
        netmap_destroy_obj_allocator(nm_mem->nm_if_pool);
        free(nm_mem, M_NETMAP);
    }
    return ENOMEM;
} 

netmapnewobj_allocator

进入内存池的申请函数——这是netmap中比较长的函数了。

static struct netmap_obj_pool *
netmap_new_obj_allocator(const char *name, u_int objtotal, u_int objsize)
{
    struct netmap_obj_pool *p;
    int i, n;
    u_int clustsize;    /* the cluster size, multiple of page size */
    u_int clustentries; /* how many objects per entry */

#define MAX_CLUSTSIZE   (1= MAX_CLUSTSIZE) {
        /* we could do it but there is no point */
        D("unsupported allocation for %d bytes", objsize);
        return NULL;
    }

    /* 
    让obj的size取整到64字节。为啥呢? 
    因为CPU的cache line大小一般是64字节。所以object的size如果和cache line对齐,可以获得更好的性能。
    关于cache line对性能的影响,可以看一下我以前写得一篇博文《多核编程:选择合适的结构体大小,提高多核并发性能》
    */
    /* make sure objsize is a multiple of LINE_ROUND */
    i = (objsize & (LINE_ROUND - 1));
    if (i) {
        D("XXX aligning object by %d bytes", LINE_ROUND - i);
        objsize += LINE_ROUND - i;
    }
    /*
     * Compute number of objects using a brute-force approach:
     * given a max cluster size,
     * we try to fill it with objects keeping track of the
     * wasted space to the next page boundary.
     */
    /*
    这里有一个概念:cluster。
    暂时没有找到相关的文档介绍这里的cluster的概念。
    这里,我只能凭借下面的代码来说一下我的理解:
    cluster是一组内存池分配对象object的集合。为什么要有这么一个集合呢?
    众所周知,Linux的内存管理是基于页的。而object的大小或小于一个页,或大于一个页。如果基于object本身进行内存分配,会造成内存的浪费。
    所以这里引入了cluster的概念,它占用一个或多个连续页。这些页的内存大小或为object大小的整数倍,或者是浪费空间最小。
    下面的方法是一个比较激进的计算cluster的方法,它尽可能的追求上面的目标直到cluster的占用的大小超出设定的最大值——MAX_CLUSTSIZE。
    */
    for (clustentries = 0, i = 1;; i++) {
        u_int delta, used = i * objsize;
        /* 不能一味的增长cluster,最大占用空间为MAX_CLUSTSIZE */
        if (used > MAX_CLUSTSIZE)
            break;
        /* 最后页面占用的空间 */
        delta = used % PAGE_SIZE;
        if (delta == 0) { // exact solution
            clustentries = i;
            break;
        }
        /* 这次利用页面空间的效率比上次的高,所以更新当前的clustentries,即cluster的个数*/
        if (delta > ( (clustentries*objsize) % PAGE_SIZE) )
            clustentries = i;
    }
    // D("XXX --- ouch, delta %d (bad for buffers)", delta);
    /* compute clustsize and round to the next page */
    /* 得到cluster的大小,并将其与PAGE SIZE对齐 */
    clustsize = clustentries * objsize;
    i =  (clustsize & (PAGE_SIZE - 1));
    if (i)
        clustsize += PAGE_SIZE - i;
    D("objsize %d clustsize %d objects %d",
        objsize, clustsize, clustentries);

    /* 申请内存池管理结构的内存 */
    p = malloc(sizeof(struct netmap_obj_pool), M_NETMAP,
        M_WAITOK | M_ZERO);
    if (p == NULL) {
        D("Unable to create '%s' allocator", name);
        return NULL;
    }
    /*
     * Allocate and initialize the lookup table.
     *
     * The number of clusters is n = ceil(objtotal/clustentries)
     * objtotal' = n * clustentries
     */
    /* 初始化内存池管理结构 */
    strncpy(p->name, name, sizeof(p->name));
    p->clustentries = clustentries;
    p->_clustsize = clustsize;
    /* 根据要设定的内存池object的数量,来调整cluster的个数 */
    n = (objtotal + clustentries - 1) / clustentries;
    p->_numclusters = n;
    /* 这是真正的内存池中的object的数量,通常是比传入的参数objtotal要多 */
    p->objtotal = n * clustentries;
    /* 为什么0和1是reserved,暂时不明。搁置争议,留给后面解决吧。:) */
    p->objfree = p->objtotal - 2; /* obj 0 and 1 are reserved */
    p->_objsize = objsize;
    p->_memtotal = p->_numclusters * p->_clustsize;

    /* 物理地址与虚拟地址对应的查询表 */
    p->lut = malloc(sizeof(struct lut_entry) * p->objtotal,
        M_NETMAP, M_WAITOK | M_ZERO);
    if (p->lut == NULL) {
        D("Unable to create lookup table for '%s' allocator", name);
        goto clean;
    }

    /* Allocate the bitmap */
    /* 申请内存池位图,用于表示那个object被分配了 */
    n = (p->objtotal + 31) / 32;
    p->bitmap = malloc(sizeof(uint32_t) * n, M_NETMAP, M_WAITOK | M_ZERO);
    if (p->bitmap == NULL) {
        D("Unable to create bitmap (%d entries) for allocator '%s'", n,
            name);
        goto clean;
    }
    /*
     * Allocate clusters, init pointers and bitmap
     */
    for (i = 0; i objtotal;) {
        int lim = i + clustentries;
        char *clust;

        clust = contigmalloc(clustsize, M_NETMAP, M_WAITOK | M_ZERO,
            0, -1UL, PAGE_SIZE, 0);
        if (clust == NULL) {
            /*
             * If we get here, there is a severe memory shortage,
             * so halve the allocated memory to reclaim some.
             */
            D("Unable to create cluster at %d for '%s' allocator",
                i, name);
            lim = i / 2;
            for (; i >= lim; i--) {
                p->bitmap[ (i>>5) ] &=  ~( 1 lut[i].vaddr)
                    contigfree(p->lut[i].vaddr,
                        p->_clustsize, M_NETMAP);
            }
            p->objtotal = i;
            p->objfree = p->objtotal - 2;
            p->_numclusters = i / clustentries;
            p->_memtotal = p->_numclusters * p->_clustsize;
            break;
        }
        /* 初始化位图即虚拟地址和物理地址插叙表 */
        for (; i > 5;
            2. 为什么(i&31),也是这个原因;—— 这就是代码的健壮性。
            */
            p->bitmap[ (i>>5) ] |=  ( 1 lut[i].vaddr = clust;
            p->lut[i].paddr = vtophys(clust);
        }
    }

    /* 与前面一样,保留第0位和第1位。再次搁置争议。。。 */
    p->bitmap[0] = ~3; /* objs 0 and 1 is always busy */
    D("Pre-allocated %d clusters (%d/%dKB) for '%s'",
        p->_numclusters, p->_clustsize >> 10,
        p->_memtotal >> 10, name);

    return p;

clean:
    netmap_destroy_obj_allocator(p);
    return NULL;
} 

netmapnewobj_allocator的分析结束。关于netmap的内存管理,依然按照事件的主线分析,而不是集中将一部分搞定。

以后带全部看完netmap的代码后,会写一些netmap的整体性和高层面的文章,不拘泥于代码细节。这就需要先把细节看懂才行。

(未完待续。。。)

目录
相关文章
|
11月前
|
机器学习/深度学习 算法 量子技术
GQNN框架:让Python开发者轻松构建量子神经网络
为降低量子神经网络的研发门槛并提升其实用性,本文介绍一个名为GQNN(Generalized Quantum Neural Network)的Python开发框架。
290 4
GQNN框架:让Python开发者轻松构建量子神经网络
|
9月前
|
机器学习/深度学习 算法 PyTorch
【Pytorch框架搭建神经网络】基于DQN算法、优先级采样的DQN算法、DQN + 人工势场的避障控制研究(Python代码实现)
【Pytorch框架搭建神经网络】基于DQN算法、优先级采样的DQN算法、DQN + 人工势场的避障控制研究(Python代码实现)
244 1
|
9月前
|
监控 前端开发 安全
Netty 高性能网络编程框架技术详解与实践指南
本文档全面介绍 Netty 高性能网络编程框架的核心概念、架构设计和实践应用。作为 Java 领域最优秀的 NIO 框架之一,Netty 提供了异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。本文将深入探讨其 Reactor 模型、ChannelPipeline、编解码器、内存管理等核心机制,帮助开发者构建高性能的网络应用系统。
605 0
|
9月前
|
机器学习/深度学习 算法 PyTorch
【DQN实现避障控制】使用Pytorch框架搭建神经网络,基于DQN算法、优先级采样的DQN算法、DQN + 人工势场实现避障控制研究(Matlab、Python实现)
【DQN实现避障控制】使用Pytorch框架搭建神经网络,基于DQN算法、优先级采样的DQN算法、DQN + 人工势场实现避障控制研究(Matlab、Python实现)
386 0
|
SQL 监控 安全
网络安全与信息安全:漏洞、加密与安全意识
随着互联网的迅猛发展,网络安全和信息安全问题日益受到关注。本文深入探讨了网络安全漏洞、加密技术以及提高个人和组织的安全意识的重要性。通过分析常见的网络攻击手段如缓冲区溢出、SQL注入等,揭示了计算机系统中存在的缺陷及其潜在威胁。同时,详细介绍了对称加密和非对称加密算法的原理及应用场景,强调了数字签名和数字证书在验证信息完整性中的关键作用。此外,还讨论了培养良好上网习惯、定期备份数据等提升安全意识的方法,旨在帮助读者更好地理解和应对复杂的网络安全挑战。
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
479 17
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
366 10
|
存储 SQL 安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将介绍网络安全的重要性,分析常见的网络安全漏洞及其危害,探讨加密技术在保障网络安全中的作用,并强调提高安全意识的必要性。通过本文的学习,读者将了解网络安全的基本概念和应对策略,提升个人和组织的网络安全防护能力。
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的内容,并提供一些实用的代码示例。通过阅读本文,您将了解到如何保护自己的网络安全,以及如何提高自己的信息安全意识。
356 10
|
监控 安全 网络安全
网络安全与信息安全:漏洞、加密与意识的交织
在数字时代的浪潮中,网络安全与信息安全成为维护数据完整性、保密性和可用性的关键。本文深入探讨了网络安全中的漏洞概念、加密技术的应用以及提升安全意识的重要性。通过实际案例分析,揭示了网络攻击的常见模式和防御策略,强调了教育和技术并重的安全理念。旨在为读者提供一套全面的网络安全知识框架,从而在日益复杂的网络环境中保护个人和组织的资产安全。

热门文章

最新文章