Intele1000零拷贝的方法

文档序号:6562131阅读:309来源:国知局
专利名称:Intel e1000零拷贝的方法
技术领域
本发明涉及一种计算机内部数据通讯的传输方法,是一种通过用户应用程序和网卡硬件驱动 程序直接数据通讯的方法。
背景技术
在实际应用中,网络管理程序常常需要接收网卡的原始报文进行分析。然而,传统的报 文捕获机制往往无法保证大流量的网络流的要求,从而成为系统处理的瓶颈。在Linux系统 上,报文从网卡到应用层经过了多次数据拷贝,并且涉及到内核态和用户态的切换,降低了 应用程序捕获报文的能力。虽然内核采用了 NAPI、 MMAP等机制大幅度提高了网卡到内核的接 收性能,但是仍然无法满足千M网络的报文特别是小报文的处理要求。

发明内容
本发明的目的在于克服论述中网络数据从网卡接收到传输给应用程序过程中需要经过多 次拷贝而提供一种计算机内部数据通讯和数据传输的方法。
本发明的目的是通过如下措施来达到
内核和应用层程序共享一块环形内存缓冲区,内存缓冲区划分为N个slot (也可以看作 可以缓存N个报文的数组),每个缓存一个报文。网卡驱动采用DMA方式向缓冲区写入报文; 应用层空间从缓冲区读出数据。缓冲区有当前可以读出和写入的slot下标索引,并且每个 slot有标志位,表示该slot是否为空。每个slot有一些额外的信息,例如报文长度、时间 戳等;
注册一种新的socket族(PF—RING socket),实现零拷贝行为的控制,包括环形缓冲区 的内存映射、接口绑定、ioctl等。新注册的socket族和el000驱动属于同一个模块。当使 用socket接口控制接口使用零拷贝机制的时候,elOOO接收报文驱动就开始向环形缓冲区写 入数据,而不是原始的skb机制。这时候,内核(协议族)就无法接收到网卡的报文了;
上层应用通过socket机制绑定接口、得到映射的内存后,就可以直接访问环形缓冲区数 据。如果环形缓冲区没有数据,应用调用poll->PF—RING ring_p0ll等待报文接收。当有新 的报文到来的时候,驱动程序唤醒进程继续处理报文。
系统框架结构如附图1
环形缓冲区就是用于实现数据零拷贝的内存区域。 环形缓冲区被三个部分使用-
1) libpcap库接口或应用程序
2) PF—RING socket
3) elOOO报文驱动
通过充分的共享环形缓冲区,达到零拷贝的目的。 环形缓冲区的设计
环形缓冲区存在读出和写入的操作,缓冲区的每个节点(下面简称slot)存储一个报文。
为了读出和写入,需要相关的索引记录当前可以读出和写入的位置。同时为了判断当前索引 位置是否真的可以读出和写入,需要相关的状态标志判断当前节点是否可以读出或写入。实
际上,网卡驱动是首先申请内存进行DMA映射,当网卡接收到报文后,报文内容已经DMA直 接映射到了内存了,同时网卡上报中断。网卡在中断回调中,修改内存的状态标记,表示这 块内存已经写入了数据。
为了简化环形缓冲区的实现以及内存映射使用,我们使用数组方式实现环形缓冲区根据 最大报文长度和缓冲区节点数目,在内核中申请一大块内存(最多2M)。这一大块内存就可 以看成一个可以存放N个报文的环形缓冲区。
缓冲区的示意图如附图2 缓冲区头flowSlotInfo
记录缓冲区的统计信息,包括内存大小、数组大小、报文总数、可以读出的首位置、可以 申请首位置等信息。
typedef struct flowSlotlnfo
u—int32—t tot—slots, slot—len, tot—mem, bucketSpace;
u—int32—t tot__pkts, tot—lost;
u—int32一t tot—insert, tot—read;
u—intl6—t insert—idx:
u—intl6—t remove—idx;
FlowSlotlnfo;
(1) tot—slots
数组slot个数,由num—slots全局变量和申请内存页面大小决定。
(2) slot—len
slot的长度,包括flowSlot头和报文长度。slotjen留下的报文缓冲区应该能够缓 冲一个完整的报文,例如大于1514。
(3) tot—mem
环形缓冲区占用的内存量
(4) bucketSpace
报文缓冲区的实际长度
(5) tot_pkts
收到报文总和
(6) tot—lost
丢失报文综合
(7) tot—insert
插入到缓冲区的报文总的个数
(8) tot一read
从缓冲区读出的报文总的个数。(tot—insert-tot—read)是可以读出报文的个数。
(9) insert—idx
可以申请的缓冲区的slot索引。如果slot的slot—state为空,表示该slot可以申请; 否则表示缓沖区满,没有空闲的空间存储报文
(10〉 remove一idx
可以读出的slot索引。如果slot的slot—state为可读,表示该slot可读;否则表示缓 冲区为空,没有存储任何报文。
缓冲区节点flowSlot typedef struct flowSlot
u_intl6_t idx;
u—char slot—state; /* 0=empty, l=full */
int dataoff;/ point to the data position水/
u一char bucket; bucket[bucketlen], include pcap一pkthdr */,
FlowSlot;
(1) idx '
slot索引下标,类似数组下标。仅仅是为了便于调试才加上的。
(2) slot—state
slot状态标记。为l表示已经写入数据,O表示该节点为空。
(3) data—off
数据存储的地址和bucket的偏移量。注意数据存储的地址应该4直接对齐。
(4) bucket
存储数据的首地址,包括pcap』kthdr。
函数实现
缓冲区初始化packet—ring—bind
缓冲区是在绑定接口的时候进行初始化的。其基本原理就是根据预定义的slot个数和slot 长度,从内存中申请一块连续的物理页面,并设置页面为非交换模式。
slot申请ring—dev—alloc
驱动调用ring—dev—alloc申请环形缓冲区存放报文。流程就是检査insert_idx处的slot 状态,如果可以申请返回slot地址,并且增加insert—idx;否则返回空。
slot释放
在某些情况下可能需要释放slot空间,例如elOOO清除接收缓冲区的时候。就是把 insert—idx减1。
状态设置ring一dev一put
设置slot的报文长度、时间戳、状态位,标记slot已经写入数据,同时增加tot—insert 计数。
PF一RING socket
注册一种新的sock类型(称为PF—RING socket),共享机制的实现采用socket隱邓,绑 定接口 (Intel网卡)的动作采用socket bind,无报文时的等待机制采用socket poll,接 口设置采用socket ioctl。 PF—RING socket族的注册成为e1000驱动的一部分,不再做单独 的模块,避免模块间的依赖。环形缓冲区、绑定接口等信息属于sock私有信息。
sock私有数据
linux内核中,结构socket和sock是一一对应的关系。PF—RING模块一般用到的是sock 结构,每个sock结构对应着一个环形缓冲区。为了不修改内S, PF_RING必须维护sock和 缓冲区数据相关的对应关系。这里我们采用全局链表维护上述关系,链表节点的定义为
struct ring—list
struct sock伞sk;
struct ring—opt氺theRing;
struct ring—list *next:
其中,ring一opt是环形缓冲区私有数据, struct ring—opt
struct net—device氺ring—netdev;/氺绑定的接CI氺/
/ Packet buffers / unsigned long order:
/ Ring Slots / unsigned long ring—memory;
FlowSlotlnfo *slots_info: /* Basically it points to ring—memory /
char *ring—slots; /* Basically it points to ring—metnory+sizeof (FlowSlotlnfo) */ —
wait』ueiie一head一t ring—slots—waitqueue: 等待队歹!j
其中,slots—info是环形缓冲区,ringjietdev是绑定的接口, ring—slots_waitqueue实 现等待机制。
因此,可以按照下面的流程査找环形缓沖区
socket-〉sock-〉査找ring—list链表,得到theRing-> slots—info。
函数ring—insert、 ring—remove实现链表的插入、删除动作。注意,使用了读写锁 ring—rogmt」oc保护链表访问的原子性。sk—get—ringopt查找链表得到sock的私有数据信息。
销毁sock的动作稍微复杂一些,包括
(1) 清除elOOO的接收缓冲区
因为elOOO从缓沖区申请了数据并进行了 DMA映射,因此我们调用 elOOO—sync—ring~〉el000_clean—all—rx~rings取消e1000对环形缓冲区的访问。
(2) 取消net—device和环形缓冲区的绑定关系
(3) 释放环形缓冲区
(4) 从全局链表中删除对应节点 接口绑定ring—bind
一般而言,PF—RING socket绑定一个e1000网卡,不允许多个PF_RING socket绑定到相 同的e1000网卡。同时,由于PF—RING socket改变了 e1000驱动接收报文的属性,必须down/up 一下接口以便网卡复位。
net—device引用计数
绑定e1000网卡需要记住e1000网卡对应的net—device指针(ring—opt->ring—netdev)。 使用dev—getj)y—name函数从网卡名字得到net—device指针,这个^数增加了 net—device 的引用计lS[; i close socket的时候需要调用dev—put递减net—device的引用计数。
e1000网卡测试
函数elOOO—test_devbind测试net—device是否是e1000网卡,实际上就是判断 (netdev 〉open el000一open )是否为真。
sock create- ring—create ring—create的主要工作包括
(1) 分配并初始化sock接口
(2) 调用ring一insert把sock插入到全局链表中
从net—device得到ring—opt
e1000驱动见到的是net—device,而不是socket,因此需要维护net—device和环形缓冲 区ring_opt的对应关系。f以通过査找前面的ring—list找到匹配关系,但是效率有点儿低, 每个报文都需要査找。因此我们把ring—opt存在net—device的私有数据中,在e1000中就 是struct el000—adapter,添力口 theRing成员记录ring一opt。
(1) de乙setJheRing是绑定接口的时候设置theRing成员
(2) dev—get—theRing是从net—device得至!jtheRing成员
(3) ring—dev—sync取消PF—RING和接口的绑定关系
内存映射r i ng—ramap
映射环形缓冲区到应用空间,2.4使用的是remap—page_range函数,2.6使用的是 remap—pf n一range 。
等待/唤醒机制
ring_opt中的ring一slots—vmitqueue实现等待/唤醒机制。当环形缓冲区没有数据可读的 时候,应用程序调用poll-〉ringjo11-〉polljvait阻塞在等待队列上;当网卡收到报文后, 调用ring一dev—rx唤醒等待的进程。
ring—ioctl
对接口行为的控制,直接调用dev—ioctl返回, 一般也就是设置接口混杂模式。


图1是系统框架结构 图2是缓冲区的示意图
具体实施例方式
图1是本发明的系统框架结构的一个具体实施。该技术与现有技术相比,其最突出的区 别特征在于使用了共享的环形缓冲区,使得上层的用户应用程序不用通过系统内核等途径, 直接从驱动程序的数据缓冲区读取数据,不需要通过多次的数据拷贝。
图2是共享的数据缓冲区示意图。在缓冲区内部,每个节点存储一个报文。为了读出和 写入,需要相关的索引记录当前可以读出和写入的位置。同时为了判断当前索引位置是否真 的可以读出和写入,需要相关的状态标志判断当前节点是否可以读出或写入。实际上,网卡 驱动是首先申请内存进行DMA映射,当网卡接收到报文后,报文内容已经DMA直接映射到了 内存了,同时网卡上报中断。网卡在中断回调中,修改内存的状态标记,表示这块内存已经 写入了数据。
权利要求
一种计算机内部数据通讯的传输方法,是一种通过用户应用程序和网卡硬件驱动程序直接数据通讯的方法,它的特征是采用了一个共享的数据存储区域,实现用户应用程序和网卡驱动报文之间的数据交互,具体的实现方式如下1.内核和应用层程序共郭一块环形内存缓冲区,内存缓冲区划分为N个slot(也可以看作可以缓存N个报文的数组),每人缓存一个报文。
1. 内核和应用层程序共享一块环形内存缓冲区,内存缓冲区划分为N个slot (也可 以看作可以缓存N个报文的数组),每个缓存一个报文。
2. 网卡驱动采用DMA方式向缓冲区写入报文;应用层空间从缓冲区读出数据。缓冲 区有当前可以读出和写入的slot下标索引,并且每个slot有标志位,表示该slot 是否为空。每个siot有一些额外的信息,例如报文长度、时间戳等。
3. 注册一种新的socket族(PF一RING socket),实现零拷贝行为的控制,包括环形 缓冲区的内存映射、接口绑定、ioctl等。新注册的socket族和el000驱动属于 同一个模块。当使用socket接口控制接口使用零拷贝机制的时候,el000接收报 文驱动就开始向环形缓冲区写入数据,而不是原始的skb机制。这时候,内核(协 议族〉就无法接收到网卡的报文了。
4. 上层应用通过socket机制绑定接口、得到映射的内存后,就可以直接访问环形缓 冲区数据。如果环形缓冲区没有数据,应用调用poll-〉PF—RING ringj)oll等待 报文接收。当有新的报文到来的时候,驱动程序唤醒进程继续处理报文。
全文摘要
本发明涉及一种计算机内部数据通讯的传输方法,是一种通过用户应用程序和网卡硬件驱动程序直接数据通讯的方法。内核和应用层程序共享一块环形内存缓冲区,内存缓冲区划分为N个slot(也可以看作可以缓存N个报文的数组),每个缓存一个报文。网卡驱动采用DMA方式向缓冲区写入报文;应用层空间从缓冲区读出数据。当使用socket接口控制接口使用零拷贝机制的时候,e1000接收报文驱动就开始向环形缓冲区写入数据,上层应用通过socket机制绑定接口、得到映射的内存后,就可以直接访问环形缓冲区数据。
文档编号G06F13/12GK101178694SQ20061013785
公开日2008年5月14日 申请日期2006年11月7日 优先权日2006年11月7日
发明者尹志超 申请人:莱克斯信息技术(北京)有限公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1