APP下载

EI内核中Mbuf的简化研究

2015-01-13

商丘师范学院学报 2015年9期
关键词:链表存储空间拷贝

乔 丽

(商丘师范学院 计算机与信息技术学院,河南 商丘,476000)

EI内核中Mbuf的简化研究

乔 丽

(商丘师范学院 计算机与信息技术学院,河南 商丘,476000)

嵌入式系统的网络应用需要精简的TCP/IP协议栈的支持,而在有限的存储空间中,重新设计了MBUF结构,并将其组织成链表的形式装载网络报文,采用零拷贝技术在协议栈各层间进行传递,这种简化策略可提高CPU的利用率及节约存储空间的占用,并且可移植性强,具有较高的实用价值.

嵌入式系统;缓冲区管理;TCP/IP协议栈;Mbuf结构;简化

0 引 言

随着嵌入式系统和Internet的迅速普及,嵌入式系统接入网络已经成为一种必然,若要实现嵌入式Internet接口必须在其上运行TCP/IP协议栈,由于嵌入式系统的资源有限性和其所要求的高实时性,需要对标准的TCP/IP协议栈进行优化,而在协议栈所占用的空间里,各种缓冲区占用了很大的部分,而影响网络性能的两大因素是缓冲区的数据拷贝和校验和计算[1],因此缓冲区Mbuf的管理对实现嵌入式系统低成本、小内存的接入Internet是至关重要的,Mbuf的简化应用可更好的提高CPU的利用率,减少内存空间的占用.

1 EI内核中缓冲区管理机制分析

1.1 缓冲区在TCP/IP协议栈中的作用

在TCP/IP协议栈中,缓冲区为网络数据提供载体,同时也为协议栈中的各层缓冲区提供空间[2],数据通过网卡进入嵌入式TCP/IP协议栈,在网络接口层设置有输入和输出缓冲区,数据帧存放在网络接口层缓冲区中,该缓冲区把网络帧向上传递,经IP 层、TCP/UDP层处理后,交付给Socket缓冲区;数据通过应用层接口被输出,同时Socket层也设置有输入和输出缓冲区,当应用层有数据需要输出时,将数据放入Socket 缓冲区中,数据经过逐级封装,增加各层协议的头部,最后放入接口层缓冲区.

嵌入式TCP/IP协议栈的缓冲区管理有两个任务:第一是设计最优的Mbuf结构装载网络报文,这样既能方便的被TCP/IP协议栈传递,又能更好的应用“零拷贝”技术,这样既节约了存储空间,又减轻了CPU的负荷;第二是为协议栈提供合适的缓冲区,并且能实现快速的分配和回收.嵌入式系统是一种专用的系统,具有较高的实时性、可靠性和稳定性等特点,其资源相对有限,因此,存储空间的分配必须满足其特定要求,合理的分配存储空间既能节约资源的利用,又能提高协议栈的吞吐量.在内存分配时,通用操作系统中的分配策略是不可能实现的,一般采用简单、快速的内存分配技术,而且内存分配的每次请求必须得到响应,如果分配失败,将可能带来灾难性的后果,同时内存分配要求尽可能的减少浪费,降低碎片的产生,以保证系统的稳定性;对于释放的存储空间,也应能实现及时的回收,以供再分配.

1.2 “零拷贝”技术

“零拷贝”技术[3]是指在网卡驱动程序和协议栈之间以及协议栈各层之间没有实现真正的数据拷贝,数据的传递主要是靠指针进行,这种技术即节省了存储空间的占用,又提高了系统的性能.由于网络接口层缓冲区的配置是由硬件实现的,所以硬件结构不同,数据结构的定义不同,数据的表示形式也不一样;而在协议栈内部缓冲区中,各层协议和网卡驱动程序相互独立,可以为数据定义统一的Mbuf结构;在通常的TCP/IP协议中,数据传递从网卡驱动程序到协议栈存在一次数据拷贝,协议栈中的数据仍然采用指针进行传递,这是单次拷贝技术.而本文将Mbuf的简化结构直接应用到网卡驱动程序中,在网卡驱动程序和Mbuf之间不再需要数据拷贝,各层协议间的数据利用指针进行传递,并不实现真正的数据的移动,仅需添加或去掉协议的头部,无需为每层数据分配额外的存储空间,采用“零拷贝”技术,节省了存储空间,降低了系统的开销.

2 4.4BSD Mbuf结构介绍

目前TCP/IP协议栈的缓冲区管理来源于4.4BSD-Lite[4],最普遍的解决方案是Mbuf技术,Mbuf结构中定义了很多成员,由next字段指针指向下一个Mbuf结构,Socket结构中包括两个指针,输入缓冲区指针so_rcV和输出缓冲区指针so_snd,Socket缓冲区是一个Mbuf链表,主要负责存放和传递接收到的数据,这种链表结构非常适合“零拷贝技术”的应用,当Mbuf中保存的数据在协议栈中流动时,无需复制缓冲区中的数据,只需要以参数的形式传递报文链中的指针并对链表头部做适当的处理.每一个Mbuf结构由头部和数据区组成,系统为其分配128个字节,数据区占用最多108个字节,主要存放各协议头部,Mbuf头部大约占用20个字节,主要包括链表指针、数据长度、类型、标志等控制字段.在IPV4中,一个 TCP/ UDP报文的头部最多20( IPV4头部)+40( IPV4选项)+20( TCP头部)+40( TCP选项)共120个字节[5],但是IP选项通常很少被使用,TCP选项一般不超过8个字节,所以108个字节是可以容纳TCP/IP报文头部.在不同的OS中,Mbuf簇的大小定义不同,通常为1K、2K或4K,如果报文长度超过108字节,必须将其存放在Mbuf 簇结构中.图1显示了4.4BSD发送缓冲区中的2148个字节的存放示例,链表中的第一个Mbuf结构即是一个Mbuf簇.

图1 4.4BSD Mbuf示例

在缓冲区管理中采用Mbuf结构可以方便的处理变长数据,采用链表结构可以避免数据的拷贝,数据在协议栈各层中流动时传递的是指针,更好的节约了存储空间的占用.需要注意的是,将数据存放在Mbuf中时,其协议的头部不能存放在Mbuf簇或多个Mbuf中,必须完整的保存在第一个Mbuf结构中.

3 缓冲区Mbuf的约简与实现

EI内核中的缓冲区管理优化主要分为三部分:缓冲区Mbuf数据结构的设计、Mbuf的服务例程、Mbuf的动态分配和回收.为了简化缓冲区的动态分配和回收,嵌入式缓冲区中仅使用固定长度的Mbuf,不使用Mbuf簇,这些Mbuf结构组织成链表形式,方便报文在各层协议之间进行移动,当需要增加或去除协议头时,只需对链表的头部做适当处理,协议栈各层之间传递的是数据指针,避免了数据拷贝的开销.

3.1 Mbuf数据结构的设计

Mbuf数据区的大小设计需要基于以下两点:第一,数据区不能设计的太大,如果传输的数据量较小,存储空间不能得以利用,浪费了资源;第二,数据区也不能设计的太小,否则,Mbuf的利用率(L数据区/Lmbuf)降低,宝贵的存储资源不能被充分地利用.例如Telnet协议所传输的数据通常只有几个或十几个字节,如果分配固定长度的缓冲区结构,显然降低了Mbuf的利用率.因此Mbuf结构的定义必须同时考虑大数据量和小数据量的网络传输[6].

嵌入式系统的数据链路层是以太网,其最大的数据帧是1518字节,去掉以太网帧的帧头14字节和帧尾CRC校验4字节,那么最大传输单元MTU也就1500字节.IP协议根据MTU的大小决定上层传来的数据是否进行分片,为了达到最佳传输性能,TCP数据包每次传输的最大数据字段MSS为1460字节,UDP MTU是1480字节[6].每个Mbuf结构用next链接成一个链表,数据包保存在一个Mbuf链中,payload是数据指针,指向数据的起始地址,可以是ROM或RAM的某个地址,主要决定于结构定义中的type字段,全部的协议头部被保存在第一个Mbuf结构,数据部分从第二个Mbuf开始存放.最大协议头部的大小是120字节,因此Mbuf的数据区至少应该大于120字节.报文在处理过程中需要做下一层协议报头的封装,如果再重新分配Mbuf势必影响处理性能,考虑在Mbuf中设置报文地址偏移字段,若非报文首部,offset为0;若为报文首部,offset非0,由单片机构成的嵌入式系统一般用于专用的通信,报文处理较为简单,所以按照MAC+IP(IPV4)长度34字节,offset设定为64,通过定义宏在预编译阶段确定.整个Mbuf长度定义为512字节,数据区长度为496字节,len字段表示当前pbuf中的有效数据长度,tot_len表示当前pbuf和其后所有pbuf的有效数据的长度,pbuf链中第一个pbuf的tot_len字段表示整个数据包的长度,而最后一个pbuf的tot_len字段必和len字段相等.

# define MLEN 496

Struct mbuf{

Struct mbuf*next;

Struct mbuf*payload;

U_intl6 tot_len;

U_intl6 type;

U_intl6 len;

#define M_DATA 1

#define M_FREE 0 }

type字段取值不同,其Mbuf状态不同,当type取0时表示该块处于空闲状态;取1时表示该Mbuf处于忙的状态,所保存的报文可能停留在缓冲区也可能在协议栈中传递.

3.2 Mbuf链的实现例程

申请Mbuf结构时,协议栈在内存中分配相应的空间,其中包括头部和缓冲区,通过函数mem_malloc进行内存分配,P为函数返回的指向Mbuf的指针.

P=(struct mbuf*)mem_malloc(size of_struct_mbuf+length+offset);

分配成功以后,Mbuf头和数据区在一片连续的存储空间里,playload指向offset之后的一段区域,这段被隔开的offset区域主要存放TCP报头和IP报头.

在传输层的协议中,都需要进行CRC校验,利用函数cksum可实现Mbuf链中的报文校验和的计算.其中p是指向Mbuf链的指针,len是数据区的长度.

intl6 cksum(struct mbuf*p,intl6 len);

当指向Mbuf链的指针P为空时,需要调用函数prepend_mbuf来创建一个Mbuf链表,该链表能容纳len个字节,同时Mbuf块中留有offset字段,在传输层添加TCP/UDP协议头部,在IP层添加IP头部.

当需要向Mbuf链表中添加块时,应调用函数append_mbuf,参数m、n分别为Mbuf链的不同块.

struct mbuf*append_mbuf(struct buf*m,struct mbuf*n,int16 len);

当需要将数据输入到Socket输入或输出缓冲区时,应调用函数prepend_mbuf.

struct mbuf*prepend_mbuf(struct mbuf*p,intl6 len);

当需要将数据从Socket缓冲区中删除掉或者要删除数据尾部的多余部分时,需调用函数adj_mbuf,其中参数len可取正数或负数两种情况,len为正数时,表示删除指针P所指块的头部len个字节,len为负数时,表示删除P所指块的尾部len个字节.

struct mbuf*adj_mbuf(struct mbuf*p,int16 len);

很多情况下,数据需要从链表的一个块的缓冲区拷贝到另一个块中,或者从网络接口层的缓冲区拷贝到Mbuf链表中,需要调用函数mbufcopy实现,然后数据再从Mbuf链交给协议栈传递.

struct mbuf*mbufcopy(struct mbuf*p,const u_int8*buf,int16 len,int16 offset);

协议栈在传送数据时,需要将数据从Socket缓冲区复制到Mbuf链表中,当数据在协议栈中流动时,网络接口层需要查找其MAC地址,这时,ARP会把Mbuf链表拷贝到ARP的未决队列,直到查找到MAC地址后,将数据封装发送.

struct mbuf*copy_mbuf(struct mbuf*src,u_int32 offset,u_int32 len);

3.3 Mbuf的分配和回收

在Mbuf的简化管理中,定义了固定长度Mbuf结构,申请32个Mbuf构成了Mbuf缓冲池.

#define MBUFNUM 32

static struct mbuf pool[MBUFNUM];

当协议栈申请分配一个Mbuf时,就调用:p = memp_malloc(MEMP_PBUF_POOL);

内存池分配函数memp_malloc可实现系统在极短的时间内分配所申请的大小,调用该函数进行扫描内存池,当某个Mbuf空闲时,其状态应为M_FREE,分配成功以后,将其type字段改为M_DATA,系统可分配多个固定大小的Mbuf块,并将其链接成一个Mbuf链表,以满足用户的分配请求.如果池中Mbuf耗尽,函数的返回值为NULL并标注错误号.

void memp_free(struct mbuf*p);

数据传输完成以后,Mbuf链表需要被释放,其空间将被回收,该过程需要调用函数memp_free来实现,用队列的方式管理这个Mbuf池的数据结构:Queue head→Mbuf0→Mbufl→...→Mbuf31←Queue Tail.申请Mbuf时,从队头删除一个Mbuf,其过程为:Queue head→Mbufl→...→Mbuf3 l←Queue Tail;释放Mbuf时,将其插入到队尾中,回收到Mbuf池:Queue head→Mbufl→...→Mbuf31→Mbuf0←Queue Tail.以下情况需要释放Mbuf链:数据从Socket缓冲区中被取走时,该缓冲区将被释放;TCP连接关闭时,Socket缓冲区也要被释放;当TCP收到ACK时,表示数据发送成功,Socket输出缓冲区的数据不用再保存,可以立即释放;当输入的报文发现有错误时,需要释放缓冲区,舍弃该报文;当输出的报文交由下层协议发送后,也需要立即释放报文.网卡在发送数据时,网卡上的缓冲区通过DMA同网络接口层缓冲区交互.为了防止数据被覆盖,一般要求协议栈尽快将输入缓冲区上的数据拷贝到安全的地方[7].但是对于一些短小的报文,处理速度很快,缓冲区实现的是零拷贝,这些报文直接在网络接口层缓冲区中被处理.例如ARP报文;而对于非IP报文,协议栈直接检查网络接口层缓冲区中的帧类型[8],如果不是IP报文,就马上舍弃.

4 性能测试分析

测试方法:嵌入式系统目标机将10个100MB的数据发送给实验机PC,实验机再将数据发送回来,目标机的TCP/IP协议栈是基于简化的Mbuf缓冲区管理策略进行实现.对比实验:在缓冲区不做简化管理的情况下,目标机同样将10个100MB的数据发送给实验机,实验机再将数据发送回来.

测试分析:实验结果如表1所示:

通过实际的运行.证明基于Mbuf的简化策略设计的嵌入式TCP/IP协议栈是有效和正确的,实现中数据区占30 K,TCP/IP协议栈只占16 K,剩下的14 K被网络接口层缓冲区占用,因此,节约了很多存储空间,减少了CPU的占用率.

表1 缓冲区测试结果

5 结束语

本文设计了Mbuf结构的简化策略,并在网卡驱动程序中直接引入简化的Mbuf结构,实现了数据的零拷贝,减少了CPU的占用率.因为所简化的Mbuf结构独立于平台,没有操作系统的支持,基于裸机实现,所以可移植性很强.可以很容易的把简化的Mbuf及在该环境下的协议栈移植到不同平台上,具有很大的实用价值.

[1] 王力生,梅岩,曹南洋.轻量级嵌入式TCP/IP协议栈的设计[J].计算机工程,2007,33(2):246-247.

[2] 黄志强,等.嵌入式家庭远程监控系统设计[J].微计算机信息,2005,3(3):91-92.

[3] 王佰玲,方滨兴,云晓春.零拷贝报文捕获平台的研究与实现[J].计算机学报,2005,28(1):46-53.

[4] Jun-ichiro itojun Hagino.Mbuf issues in 4[M].4BSD IPv6/IPsecsupport,USENIX Annual Technical Conference,2000.

[5] Andrew S.Tanenbaum著.潘爱民,译.计算机网络[M].北京:清华大学出版社,2004.78-80.

[6] Gary R,Wright W.Richard Stevens TCP/IP详解卷2:实现[M].北京:机械工业出版社,2000.213.

[7] 乔丽.一种嵌入式轻便TCP/IP协议栈的设计与实现[J].西南民族大学学报,2010,36(3):487-490.

[8] Sridhar T著.彭甫阳,王怀彬,王安生,译.嵌入式通信软件设计[M].北京:北京航空航天大学出版社,2004.125.

[责任编辑:王军]

The study of MBUF simplified in EI kernel

QIAO Li

(College of Computer and Information Technology, Shangqiu Normal University, Shangqiu 476000,China)

The network application of the embedded system need the support of the TCP/IP protocol stack.And in the limited storage space, MBUF structure was redesigned.and they was organized into the form of list to load network packet.The zero copy technology is adopted to transmit data among the protocol stack.the simplified strategy can improve the utilization of CPU and save the occupancy of storage space.And the way has portability and high value.

embedded System; buffer Management;TCP/IP protocol stack; Mbuf structure;simplification

2015-06-09;

2015-06-16

河南省科技厅基础与前沿技术研究计划项目(No.14230410186)

乔丽(1980-),女,河南商丘市人,商丘师范学院讲师,硕士,主要从事嵌入式系统、智能信息处理的研究.

TP393.11

A

1672-3600(2015)09-0072-05

猜你喜欢

链表存储空间拷贝
基于多种群协同进化算法的数据并行聚类算法
苹果订阅捆绑服务Apple One正式上线
用好Windows 10保留的存储空间
基于二进制链表的粗糙集属性约简
跟麦咭学编程
唐氏综合征是因为“拷贝”走样了
基于链表多分支路径树的云存储数据完整性验证机制
文化拷贝应该如何“拷”
链表方式集中器抄表的设计
基于硬盘还原卡的数据传送技术在高校网络机房中的应用