零拷贝(zero-copy)基本思想是:数据报从网络设备到用户程序空间传递的过程中,减少数据拷贝次数,减少系统调用,实现CPU 的零参与,彻底消除 CPU在这方面的负载。实现零拷贝用到的最主要技术是DMA 数据传输技术和内存区域映射技术。传统的网络数据报处理,需要经过网络设备到操作系统内存空间,系统内存空间到用户应用程序空间这两次拷贝,同时还需要经历用户向系统发出的系统调用。而零拷贝技术则首先利用DMA 技术将网络数据报直接传递到系统内核预先分配的地址空间中,避免CPU 的参与;同时,将系统内核中存储数据报的内存区域映射到检测程序的应用程序空间(还有一种方式是在用户空间建立一缓存,并将其映射到内核空间),检测程序直接对这块内存进行访问,从而减少了系统内核向用户空间的内存拷贝,同时减少了系统调用的开销,实现了真正的“零拷贝”。
开发流程大致包括以下几个环节:
一、申请空间
利用__get_free_pages和SetPageReserved(virt_to_page(pdr)) 从内核申请空间
二、查看源代码,可以大致看到包处理是在函数 bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)中进行的,具体代码就不进行分析,追溯源头的话就是在bnx2_poll函数。还有一个就是分配内核空间的函数,bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)。我们需要做以下改动:
1)bnx2_alloc_rx_skb 函数中skb = __netdev_alloc_skb(bp->dev, bp->rx_buf_size, gfp);
改为 skb = getZerocpBuffer()这里的内存是第一步申请的空间
2)bnx2_rx_int中 将ring中的skb取出来之后不需要放到协议栈了,例如这样的netif_receive_skb都不需要调用了。把你自己需要考虑的一些处理加载这里,例如统计信息、以及一些控制信息等。
三、驱动程序中remap_pfn_range函数将申请的内核空间映射到用户空间。
四、用户程序中使用mmap映射将设备的内存空间映射到它的地址空间(这个已经是应用程序层次的了,不是内核层次的了,说的是怎么使用驱动了)
经过以上四个环节,数据包就能直接达到你想要的内存了。经过测试,cpu利用率几乎为0.
这一节讲的是比较大致,之后还会讲一下一些碰到的麻烦的问题。
阅读(1597) | 评论(0) | 转发(0) |