零拷贝技术交流文档
本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。
E-mail: wwwlkk@126.com
来源: ;aid=6&un=wwwlkk#7
零拷贝技术交流文档
目录:
(一)linux中的分页机制 ..................................................................................................................... 1
(二)实现零拷贝的两个理论
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
....................................................................................................... 2
(三)为防火墙定制的零拷贝技术方案 ............................................................................................... 3
(四)参考文献 ...................................................................................................................................... 5
前言:零拷贝技术是比较实用的技术,但是网络上很少有人介绍这种技术的实现原理,本文的目的就是详细的讲解零拷贝的实现原理,但是不讨论技术细节,因为技术细节不好表述,而且不同的需求或者不同的程序员,都会选择不同技术来实现,但是最终的实现原理是不变的。 (一)linux中的分页机制
CPU要访问某块物理内存,必须要获得内存的物理地址,CPU集成有寻址硬件,会根据机器语言指令中提供的地址,执行地址转换,获得的物理地址。
CPU有两种转换模式:1.实模式 2.保护模式。实模式下的物理地址=线性地址,保护模式下的物理地址=线性地址通过分页机制转化为物理地址。
启动保护模式:把CPU控制寄存器CR0中的最高位置1。
CPU保护模式寻址方式:
图1 分页机制寻址
说明:CR3控制寄存器的值是物理地址。由于寻找的是页框的物理地址,页框的物理地址是4096的整数倍,所以CR3,页目录和页表中存储的物理地址后12位都为0。也就是这12位的空
技术交流文档:零拷贝技术 责任编辑: 林可可 wwwlkk@126.com 1 /6
间不存储物理地址信息,而是用于存储访问控制信息(可读/可写/CPU特权级别),或者对应的页是否存在等信息。
其中访问控制信息(可读/可写/CPU特权级别)可以特别利用:例如:如果某个页框的范围控制标记是只读的,那么进程如果对这个页框进行写操作,就会产生段错误。
注意:从2.6.11版本开始,采用了四级分页模型,但基本原理是一样的。
每个进程的CR3的值是不同,进程切换时保存或者恢复CR3的值。只要设置了CR3的值CPU将自动进行寻址。
要将某个物理页加入进程的地址空间,要做的事情就是将物理页的物理地址填写进程页目录表内的表项和页表内的表项。
如果将内核使用到的物理页加入进程的地址空间,这样进程就可以零拷贝的读取内核数据。
在32位的linux系统中,内核的线性空间是1G。
进程的线性空间是4G,其中3G是进程独有的,1G是内核线性空间,是内核和整个系统的所有进程共享的。
虽然每个进程的页表中都包含了内核的页表,但是进程却不能直接使用内核页表,原因有2点:
1) 内核页表的CPU的访问级别是内核级,进程如果处于用户级别时访问内
核页表会出现段错误。
2) 使用gcc链接应用程序时,无法和内核链接,这样导致了应用程序也无法
直接使用内核数据和函数。
(二)实现零拷贝的两个理论方案
方案一. 使某个进程的状态总是处于内核态。
正常进行系统调用时,首先将CPU变为内核级,系统调用返回时又变为用户级。可以将用户代码和数据段的DPL改为0,这样进程就总是处于内核级。这个技术在论文《IPv6下基于病毒过滤防火墙的设计与实现》有提到,但是这种方案的用户空间可以随意修改内核的数据,系统会很不稳定。
技术交流文档:零拷贝技术 责任编辑: 林可可 wwwlkk@126.com 2 /6
实现原理:CPU的cs寄存器有2位的字段,用于指明CPU的当前特权级(CPL),值为0表示内核级,3表示用户级。当把__KERNEL_CS宏产生的值装进CS寄存器,CPU就是内核级,当把__USER_CS宏产生的值装进CS寄存器,CPU就是用户级,具体做法就是修改__USER_CS宏产生的值使CPU变为0。
方案二. 将skb指向的数据的物理地址,映射到进程的用户空间。
现在普遍使用的零拷贝技术是方案二,开源社区有3个零拷贝实现模块: 1)ntzc
2)PF_RING
3)PACKET_MMAP
其中ntzc是真正意义上的零拷贝,PACKET_MMAP还带有一次的数据拷贝,PF_RING还没分析过,初步判断和PACKET_MMAP差不多,也应该带有一次数据拷贝。
(三)为防火墙定制的零拷贝技术方案
上面就是零拷贝的技术原理,也已经有了3个零拷贝的实现模块,但是这3个模块都不是为防火墙定制的,都有各自的局限性:
1) ntzc并不经过
协议
离婚协议模板下载合伙人协议 下载渠道分销协议免费下载敬业协议下载授课协议下载
栈,而是由驱动层到应用层,再到驱动层。
2) PACKET_MMAP还有一次的数据拷贝(PF_RING应该也类似)。
所以,有必要为防火墙定制一个零拷贝模块,具备以下功能:
1) 不会降低防火墙原来的处理性能。
2) 和防火墙可以并发的处理数据。
下面给出关键的技术点:
技术点1:物理内存映射
如图2所示:左边是系统的物理内存,以及内核是如何划分物理内存的;右边是某个进程的线性地址空间,进程在用户态可使用的线性空间大小是3G。
假设,物理内存是512M,那么进程初始化时分配512M连续的线性空间用于映射物理内存(通过/dev/mem可以做到),假定这块线性空间的起始地址是start,某块内存的物理地址是0x1234,在进程内使用*(start+0x1234)就可以访问到这块内存。
补充1:有可能实际的物理内存很大,比如2G,4G,一个进程的线性空间不够映射,那么可以使用多个进程来映射。
补充2:图1中的高速缓存是用于设备的高速缓存。
技术交流文档:零拷贝技术 责任编辑: 林可可 wwwlkk@126.com 3 /6
图2 物理内存映射
技术点2:skb对象和skb->data指向的内存块是连续的物理内存
通过分析slab的代码,可以看到skb对象和skb->data指向的内存块是使用get_free_page分配的,也就是说每个对象是连续的物理内存,那么只要知道对象的物理地址和大小就可以访问到整个对象。
补充1:通过vmalloc分配的物理内存的线性地址空间是连续的,但是物理内存可能不是连续的,所以为什么vmalloc分配的内存空间会比较大,就是因为它不受连续物理空间的限制。
使用以上2个技术点可以实现的功能:
1. 有2个环A,B,内核释放skb时,将不会马上释放,而是把,skb和skb->data的线性地址和物理地址写入环A。
2. 进程从环中获得skb->data的物理地址,通过技术点1访问数据包的内容,并打印出ip层的内容,最后将skb的线性地址写入环B。
3. 内核访问环B,释放里面的skb。
技术点3:可以通过netfilter挂钩机制,获取skb以及skb->data的物理地址。 技术点4:灵活使用skb的引用计数
skb有一个引用计数,如果引用技术减为0时,内核才会真正的释放skb,那么如果某个skb
技术交流文档:零拷贝技术 责任编辑: 林可可 wwwlkk@126.com 4 /6
进入零拷贝环,此时需要增加skb的引用计数,这样内核和应用进程就都可以安全的使用skb。 技术点5:只读访问内核代码区
由于内核的数据是关键数据,是不允许进程随意修改,那么进程映射物理内存时使用只读映射,这样就保证了内核数据的安全性。
技术点6:进程间零拷贝传递数据
一个进程如果使用完数据后,可以将这个数据的物理地址传递给下一个进程,这样下一个进程就零拷贝的获得了数据。
以上给出了零拷贝的技术原理(希望已经讲清楚了),而没有涉及具体的技术细节,主要是因为linux提供了很多实现技术,最终还是要根据具体的需求然后结合程序员的偏好使用具体的技术。
(四)参考文献
参考文档:
1.《PACKET_MMAP实现分析》
2.《netlink实现分析》
3.《skb释放和分配流程分析》
4.《IPC共享内存和文件映射编程及实现原理》
参考书籍:
1(《Linux内核分析及编程》倪继利 (作者)
2(《LINUX设备驱动程序(第3版) 》 科波特 (作者), 魏永明 (译者)
3.《深入理解linux内核第三版中文版》译者: 陈莉君
4.《Linux中TCP/IP协议实现及嵌入式应用》 著译者:张曦煌
参考源代码:
1. linux-2.6.35源码
技术交流文档:零拷贝技术 责任编辑: 林可可 wwwlkk@126.com 5 /6
2. ntzc源码
技术交流文档:零拷贝技术 责任编辑: 林可可 wwwlkk@126.com 6 /6