第二章 mbuf(存储器缓存)

来源:互联网 发布:c语言中文网vip资料1t 编辑:程序博客网 时间:2024/05/22 15:44

一:mbuf的主要用途

mbuf的主要用途是保存在进程和网络接口间互相传递的用户数据。但 m b u f也用于保存其他各种数据:源与目标地址、插口选项等等。

二:四种不同类型的mbuf

四种不同类型的 m b u f,它们依据在成员m _ f l a g s中填写的不同标志M _ P K T H D R和M _ E X T而不同。

1) 如果m _ f l a g s等于0,m b u f只包含数据。

2) 第二类m b u f的m _ f l a g s值是M _ P K T H D R,它指示这是一个分组首部,描述一个分组数据的第一个m b u f。数据仍然保存在这个 m b u f中,但是由于分组首部占用了 8字节,只有1 0 0字节的数据可存储在这个m b u f中。

3) 下一种m b u f不包含分组首部(没有设置K _ P K T H D R),但包含超过2 0 8字节的数据,这时用到一个叫“簇”的外部缓存 (设置M _ E X T)。在此m b u f中仍然为分组首部结构分配了空间,但没有用—在图2 - 1中,我们用阴影显示出来。

4) 最后一类 m b u f包含一个分组首部,并包含超过 2 0 8字节的数据。同时设置了标志M _ P K T H D R和M _ E X T。


mbuf各个成员含义如下(结合图2-1与2-2来看)

m_next:因为mbuf的大小为128个字节当发送的数据超过128个字节后,将数据缓存中的数据复制多个m b u f中。这种安排叫做m b u f链表。在每个m b u f中的成员m _ n e x t把链表中所有的m b u f都链接在一起。指针m _ n e x t把m b u f链接在一起,把一个分组(记录)形成一条m b u f链表

m_nextpkt:指针m _ n e x t p k t把多个分组(记录)链接成一个m b u f链表队列。在队列中的每个分组可以是一个单独的m b u f,也可以是一个m b u f链表。每个分组的第一个 m b u f包含一个分组首部。如果多个m b u f定义一个分组,只有第一个m b u f的成员m _ n e x t p k t被使用—链表中其他m b u f的成员m _ n e x t p k t全是空指针。

m_len:当前mbuf的长度。

m_data:指向m b u f中的数据。

m_type:包含在m b u f中数据的类型。


m_flags:填写m_flags不同的标志,设置不同类型的mbuf。


m_pkthdr.len:只用在链表的第一个 m b u f中。它包含了整个m b u f链表的总长度

m_pkthdr.rcvif:只用在链表的第一个 m b u f中。它包含了一个指向接收分组的接收接口结构的指针。

m_ext.ext_buf:带有簇的m b u f总是包含缓存的起始地址(m _ e x t . e x t _ b u f)

m_ext.ext_free:

m_ext.ext_size:带有簇的m b u f总是包含缓存的大小(m _ e x t . e x t _ s i z e)。注:是簇的大小,不是簇中数据的大小

注:指针 m _ n e x t把m b u f链接成一个m b u f链表,而指针m _ n e x t p k t把m b u f链表链接成一个m b u f队列。

注:在第一个m b u f中,U D P与T C P协议首部位置的不同是由于 U D P调用M _ P R E P E N D而T C P调用M G E T H D R造成的。

三:mbuf的定义

处理m b u f时,会反复遇到几个常量。(如下图)


由于m b u f有一个固定长度( 1 2 8字节),因此对于m b u f的使用有一个限制—包含的数据不能超过1 0 8字节。

mbuf不是一个链表结构,它是一个128字节的结构体。所有类型的mbuf都有以下6个字段,即mbuf的头部,共20字节:

m_next:本分组的下一个mbuf块的地址,4字节 m_nextpkt:下一个分组的首部的地址,4字节

m_len:本mbuf中有效数据的长度(不包括头部),4字节

m_data:本mbuf块有效数据的起始地址,4字节

m_type:本mbuf的数据类型,2字节

m_flags:区分mbuf块,2字节

四:M G E T宏与 m _ r e t r y函数

(1)调用M G E T来分配存储s e n d t o系统调用的目标地址(若内核的存储器分配调用成功则产生mbuf 如图1-6)。


(2)当调用调用M G E T若内核的存储器分配调用失败则调用m _ r e t r y函数。我们在m_retry函数中调用了m _ r e c l a i m后有可能有机会得到更多的存储器,因此再次调用宏M G E T,试图获得m b u f。

五: m _ d e v g e t和m _ p u l l u p函数

m _ d e v g e t函数:

当接收到一个以太网帧时,设备驱动程序调用函数 m _ d e v g e t来创建一个m b u f链表,并把设备中的帧复制到这个链表中。根据所接收的帧的长度 (不包括以太网首部),可能导致4种不同的m b u f链表。见P2  图2-15)

1)0≤数据长度≤84

2)85≤数据长度≤100

3)101≤数据长度≤207(当数据在1 0 1 ~ 2 0 7字节之间时,要求有两个m b u f。)

4)208≤数据长度≤2048(数据超过或等于 208  字节(M I N C L B Y T E S),要用一个或多个簇。)

注:m _ l e n的实际最小值是2 8:2 0字节的I P首部,8字节的U D P首部和一个0长度的U D P数据报。

m _ p u l l u p函数:

我们已经讨论了关于使用m _ p u l l u p的三种情况:
1)大多数设备驱动程序不把一个I P数据报的第一部分分割到几个m b u f中。假设协议首部都紧挨着存放,则在每个协议 ( I P、I C M P、I G M P、U D P和T C P )中调用m _ p u l l u p的可能性很小。如果调用m _ p u l l u p,通常是因为I P数据报太小,并且m _ p u l l u p返回一个差错,这时数据报被丢弃,并且差错计数器加 1。
2)对于每个接收到的I P分片,当I P数据报被存放在一个簇中时,m _ p u l l u p被调用。这意味着,几乎对于每个接收的分片都要调用m _ p u l l u p,因为大多数分片的长度大于208 字节。
3) 只要T C P报文段不被 I P分片,接收一个 T C P报文段,不论是否失序,都不需调用m _ p u l l u p。这是避免I P对T C P分片的一个原因。

六:m t o d和d t o m宏

m t o d(“m b u f到数据”)返回一个指向m b u f数据的指针,并把指针声名为指定类型。

宏d t o m (“数据到m b u f”)取得一个存放在一个m b u f中任意位置的数据的指针,并返回这个m b u f结构本身的一个指针。

原创粉丝点击