高性能网络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的整体性和高层面的文章,不拘泥于代码细节。这就需要先把细节看懂才行。

(未完待续。。。)

目录
相关文章
|
7天前
|
存储 SQL 安全
网络安全与信息安全:守护数字世界的坚盾在这个高度数字化的时代,网络安全和信息安全已经成为个人、企业乃至国家安全的重要组成部分。本文将深入探讨网络安全漏洞、加密技术以及安全意识的重要性,旨在为读者提供一个全面的网络安全知识框架。
随着互联网技术的飞速发展,网络安全问题日益凸显。从个人信息泄露到企业数据被盗,再到国家安全受到威胁,网络安全事件层出不穷。本文将从网络安全漏洞的定义与分类入手,探讨常见的网络攻击手段;随后深入解析加密技术的原理及其在保护信息安全中的作用;最后强调提升公众与企业的安全意识的重要性,并提出具体的建议。通过综合运用这些知识点,我们可以更好地构建起一道道坚固的防线,守护我们的数字世界。
|
10天前
|
编解码 分布式计算 网络协议
Netty高性能网络框架(一)
Netty高性能网络框架(一)
完成切换网络+修改网络连接图标提示的代码框架
完成切换网络+修改网络连接图标提示的代码框架
|
2月前
|
测试技术 数据库
探索JSF单元测试秘籍!如何让您的应用更稳固、更高效?揭秘成功背后的测试之道!
【8月更文挑战第31天】在 JavaServer Faces(JSF)应用开发中,确保代码质量和可维护性至关重要。本文详细介绍了如何通过单元测试实现这一目标。首先,阐述了单元测试的重要性及其对应用稳定性的影响;其次,提出了提高 JSF 应用可测试性的设计建议,如避免直接访问外部资源和使用依赖注入;最后,通过一个具体的 `UserBean` 示例,展示了如何利用 JUnit 和 Mockito 框架编写有效的单元测试。通过这些方法,不仅能够确保代码质量,还能提高开发效率和降低维护成本。
43 0
|
4天前
|
存储 安全 网络安全
云计算与网络安全:技术融合下的信息安全新挑战
【9月更文挑战第29天】在数字化浪潮的推动下,云计算服务如雨后春笋般涌现,为各行各业提供了前所未有的便利和效率。然而,随着数据和服务的云端化,网络安全问题也日益凸显,成为制约云计算发展的关键因素之一。本文将从技术角度出发,探讨云计算环境下网络安全的重要性,分析云服务中存在的安全风险,并提出相应的防护措施。我们将通过实际案例,揭示如何在享受云计算带来的便捷的同时,确保数据的安全性和完整性。
|
4天前
|
SQL 安全 算法
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
【9月更文挑战第29天】随着互联网的普及,网络安全问题日益严重。本文将介绍网络安全漏洞、加密技术以及安全意识等方面的内容,帮助读者了解网络安全的重要性,提高自身的网络安全意识。
|
4天前
|
存储 SQL 安全
网络安全与信息安全:构建安全防线的关键策略
本文深入探讨了网络安全与信息安全领域的核心要素,包括网络安全漏洞、加密技术以及安全意识的重要性。通过对这些关键领域的分析,旨在为读者提供一套综合性的防护策略,帮助企业和个人在日益复杂的网络环境中保障数据安全。
16 4
|
1天前
|
安全 网络协议 网络安全
网络安全与信息安全:漏洞、加密与意识的三重奏
【9月更文挑战第32天】在数字世界的交响乐中,网络安全是那不可或缺的乐章。本文将带您深入探索网络安全的三大主题:网络漏洞的识别与防范、加密技术的奥秘以及安全意识的重要性。通过深入浅出的方式,我们将一起揭开这些概念的神秘面纱,并学习如何在实际生活中应用它们来保护自己的数字足迹。让我们开始这场既刺激又富有教育意义的旅程,提升个人和组织的网络安全防御能力。
|
3天前
|
SQL 安全 程序员
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
【9月更文挑战第30天】在数字化时代,网络安全和信息安全已成为全球关注的焦点。本文将探讨网络安全漏洞、加密技术以及提升安全意识的重要性。我们将通过代码示例,深入理解网络安全的基础知识,包括常见的网络攻击手段、防御策略和加密技术的实际应用。同时,我们还将讨论如何提高个人和企业的安全意识,以应对日益复杂的网络安全威胁。
|
2天前
|
SQL 安全 算法
数字时代的守护者:网络安全与信息安全的现代策略
【9月更文挑战第31天】在数字化时代,网络安全与信息安全成为保护个人隐私和企业资产的关键。本文将深入探讨网络安全漏洞的成因、加密技术的应用以及提升安全意识的重要性,旨在为读者提供防范网络威胁的策略和知识分享。
17 7
下一篇
无影云桌面