【转载】高性能网络I/O框架-netmap源码分析(6)

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

作者:gfree.wind@gmail.com
原文地址:<http://blog.chinaunix.net/uid-23629988-id-3803045.html>

因为最近比较忙,很久没有更新博客了,但是netmap源码分析还没有写完,今天继续分析。这里就显示出了写博客的好处。如果不是写博客,可能自己私下看代码,看了一半,就半途而废了。而写了博客,每次打开自己的主页,看到还未完成的系列,就会坚持把这件事情做完。

唠了一点闲话,也是鼓励大家多写文章,给ChinaUnix贡献一些文字吧。

上次已经把netmap_ioctl分析完了,根据netmap的示例,下面该分析netmap的mmap的实现了。

定位netmap的mmap

前文提到过netmap会创建一个设备

static struct miscdevice netmap_cdevsw = {  /* same name as FreeBSD */  
    MISC_DYNAMIC_MINOR,  
    "netmap",  
    &netmap_fops,  
}; 

netmap_fops定义了netmap设备支持的操作

static struct file_operations netmap_fops = {
    .mmap = linux_netmap_mmap,
    LIN_IOCTL_NAME = linux_netmap_ioctl,
    .poll = linux_netmap_poll,
    .release = netmap_release,
}; 

OK,现在我们找到了mmap的入口,linuxnetmapmmap。

linux_netmap_mmap分析

现在直接进入linux_netmap_mmap的代码

static int
linux_netmap_mmap(struct file *f, struct vm_area_struct *vma)
{
    int lut_skip, i, j;
    int user_skip = 0;
    struct lut_entry *l_entry;
    const struct netmap_obj_pool *p[] = {
        nm_mem->nm_if_pool,
        nm_mem->nm_ring_pool,
        nm_mem->nm_buf_pool };
    /*
    * vma->vm_start: start of mapping user address space
    * vma->vm_end: end of the mapping user address space
    */

    /* 
    这里又是一个编程技巧,使用(void)f既不会产生任何真正的代码,又可以消除变量f没有使用的warning。
    为什么f不使用,还会出现在参数列表中呢?没办法啊,只是Linux框架决定的。linux_netmap_mmap只是一个注册回调,自然要遵从linux的框架了。
    */
    (void)f;    /* UNUSED */
    // XXX security checks

    for (i = 0; i < 3; i++) {  /* loop through obj_pools */
        /*
         * In each pool memory is allocated in clusters
         * of size _clustsize , each containing clustentries
         * entries. For each object k we already store the
         * vtophys malling in lut[k] so we use that, scanning
         * the lut[] array in steps of clustentries,
         * and we map each cluster (not individual pages,
         * it would be overkill).
         */
        /* 
        上面的注释说的很明白。
        每个pool里的object都是由_clustsize组成的,每一个都包含clustertries个基础内存块。 一个pool公有_numclusters个基础内存块。
        所以,在进行内存映射的时候,user_skip表示已经映射的内存大小,vma->start+user_skip也就是当前未映射内存的起始地址,lut_skip表示当前待映射的物理内存池的块索引
        */
        for (lut_skip = 0, j = 0; j < p[i]->_numclusters; j++) {
            l_entry = &p[i]->lut[lut_skip];
            if (remap_pfn_range(vma, vma->vm_start + user_skip,
                    l_entry->paddr >> PAGE_SHIFT, p[i]->_clustsize,
                    vma->vm_page_prot))
                return -EAGAIN; // XXX check return value
            lut_skip += p[i]->clustentries;
            user_skip += p[i]->_clustsize;
        }
    }

    /* 
    循环执行完毕后,netmap在内核中的3个对象池已经完全映射到用户空间
    真正执行映射的函数是remap_pfn_range,这是内核函数,用于将内核空间映射到用户空间
    这个函数超出了本文的主题范围了,我们只需要知道它是做什么的就行了。 
    */

    return 0;
} 

用户态得到对应网卡的netmap结构

在将netmap内核态的内存映射到用户空间以后,netmap的示例通过offset来得到对应网卡的netmap结构。

fd = open("/dev/netmap", 0);
strcpy(req.nr_name, "ix0"); // register the interface
ioctl(fd, NIOCREG, &req); // offset of the structure
mem = mmap(NULL, req.nr_memsize, PROT_READ|PROT_WRITE, 0, fd, 0);
nifp = NETMAP_IF(mem, req.nr_offset); 

在此例中,使用ioctl,得到req.nroffset是ix0网卡的netmap结构的偏移——准确的说是netmap管理网卡结构内存池的偏移。mmap后,mem是netmap内存的映射,而网卡结构内存是内存中的第一项,那么mem同样可以视为netmap管理网卡结构的内存池的起始地址。因此,利用前面的req.nroffset,就得到了ix0的netmap结构,即struct netmap_if。

走读netmap的示例中工作代码

按照netmap示例,马上就要进入netmap真正工作的代码了。

for (;;) {  
    struct pollfd x[1];
    /*
    根据netmap的代码,NETMAP_RXRING的定义如下
    #define NETMAP_RXRING(nifp, index)          \
        ((struct netmap_ring *)((char *)(nifp) +    \
        (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] ) )
    得到该网卡的接收ring buffer。

    吐个槽,为什么英文接收Receive要缩写为RX呢。。。我在别的地方也见过。
    */
    struct netmap_ring *ring = NETMAP_RX_RING(nifp, 0);
    x[0].fd = fd;
    x[0].events = POLLIN;
    /* 超时1秒等接收事件发生 */
    poll(x, 1, 1000);
    /* 收到ring->avail个包 */
    for ( ; ring->avail > 0 ; ring->avail--) {
        /* 得到当前包索引 */
        i = ring->cur;
        /* 得到对应的数据包 */
        buf = NETMAP_BUF(ring, i);
        /* 用户态处理该数据包 */
        use_data(buf, ring->slot[i].len);
        /* 移到下一个待处理数据包 */
        ring->cur = NETMAP_NEXT(ring, i);
    }
} 

(netmap源码分析,未完待续。。。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值