mbuf : 存储器缓存

mbuf的主要用途就是保存在进程和网络接口之间相互传递的用户数据,以及源与目标地址,插口选项等等。根据在成员m_flags中填写不同标志,有4种不同的mbuf:

  1. 若m_flags为0,mbuf只包含数据。
    3.08.04.png
  2. 若m_flags为M_PKTHDR,则这是一个分组首部,描述一个分组数据的第一个mbuf。


    3.09.16.png
  3. 若m_flags为M_EXT,则这是不包含分组首部,但包含超过208字节的数据,这用到了一个叫“簇”的外部缓存。
    3.21.14.png

4 最后一类mbuf包含一个分组首部,并包含超过208字节的数据。同时设置了标志M_PKTHDR和M_EXT。


3.24.36.png

另外有几点:

  • 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链表队列。

3.36.00.png

代码介绍:

3.44.57.png

有一个全局变量为mbstat,用于mbuf的统计信息,其中所维护的各种统计,如图:
3.49.16.png

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

m_flags的独立的值:


3.55.28.png

m_devget函数

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


4.06.15.png
4.06.23.png
4.06.28.png
  • 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链表


4.41.38.png

有头尾指针的链表


4.43.18.png

使用簇的好处在于:

  • 在要求包含大量数据的时候能减少mbuf的数目。

  • 在多个mbuf间可以共享一个簇。避免了内核将数据从一个mbuf复制到另一个mbuf中。

你可能感兴趣的:(mbuf : 存储器缓存)