mbuf : 存储器缓存
mbuf的主要用途就是保存在进程和网络接口之间相互传递的用户数据,以及源与目标地址,插口选项等等。根据在成员m_flags中填写不同标志,有4种不同的mbuf:
-
若m_flags为0,mbuf只包含数据。
3.08.04.png
-
若m_flags为M_PKTHDR,则这是一个分组首部,描述一个分组数据的第一个mbuf。
3.09.16.png
-
若m_flags为M_EXT,则这是不包含分组首部,但包含超过208字节的数据,这用到了一个叫“簇”的外部缓存。
3.21.14.png
4 最后一类mbuf包含一个分组首部,并包含超过208字节的数据。同时设置了标志M_PKTHDR和M_EXT。

另外有几点:
-
mbuf结构的大小为128字节,之后两个mbuf结构中有m_ext,其m_ext的空间是88字节。
-
因为有些协议(如UDP)允许零长记录,那就就可以有m_len=0的数据缓存。
-
mbuf成员中的m_data指向的是相应缓存的开始。
-
带有簇的mbuf总是包含缓存的起始地址m_ext.ext_buf和它的大小m_ext.ext_size
-
指针m_next把mbuf链接在一起,把一个分组形成一条mbuf链表。
-
指针m_nextpkt把多个分组链接成一个mbuf链表队列。

代码介绍:


可通过netstat -m检测。(内核在一个全局变量中保持对某些统计信息的跟踪,当内核在运行时,一个进程对这些信息进行检查)
m_flags的独立的值:

m_devget函数
当接收到一个以太网帧时,设备驱动程序调用m_devget来创建一个mbuf链表,并把所接收到的帧复制到这个链表中。根据所接收到的帧的长度不同,导致以下4种不同的mbuf链表。



-
mtod返回一个指回mbuf数据的指针,并把指针声名为指定类型。
-
dtom取得一个存放在一个mbuf中任意位置的数据的指针,并返回这个mbuf结构本身的一个指针。(如果m_data指向一个簇时不能使用宏dtom,因为没有从簇指回mbuf的指针)
m_pullup函数
m_pullup函数有两个目的:
- 当一个协议发现第一个mbuf的数据量m_len小于协议首部的最小长度(IP 20,UDP 8,TCP 20),m_pullup基于假定协议首部的剩余部分存在链表中的下一个mbuf,然后m——pullup重新安排mbuf链表,使得前N字节的数据被连续放在链表的第一个mbuf中。(N<=MHLEN:100)m_pullup有两个原因会失败:(1)如果它需要其他mbuf并且调用MGET失败,(2)如果整个mbuf链表中的数据总数少于要求的字节数
- m_pullup涉及到IP和TCP的重组。IP分片算法把各分片都存在一个双向链表中,并且用IP首部中的源和目标IP地址来存放向前与向后的链表指针。但若IP首部在一个簇中,链表指针也就在一个簇中,当遍历链表时,指向IP首部的指针不能转换成指向mbuf的指针。所以当接收到一个分片时,若分片在一个簇中,IP分片例程总是调用m_pullup。重组TCP报文段使用的是不同的技术而不是m_pullup,是因为m_pullup数据复制开销较大。
只有头指针的mbuf链表

有头尾指针的链表

使用簇的好处在于:
-
在要求包含大量数据的时候能减少mbuf的数目。
-
在多个mbuf间可以共享一个簇。避免了内核将数据从一个mbuf复制到另一个mbuf中。