mbuf全称即memory buffer,即存储器缓存,在内核中属于全局支持的范畴。从网络协议的角度来说,mbuf的主要用处是保存在进程和网络接口间相互传递的用户数据。当然,在实际使用中,mbuf除了保存用户数据以外,还需要保存其他各类数据,比如比较常见的网络报文头部的源地址与目的地址以及端口信息乃至Socket选项等。
在软件系统的设计中,存储器缓存的概念其实应该并不陌生,它在设计理念上有点像对应到硬件中各种Cache的概念,比如CPU与内存之间有Cache,近阶段比较流行的SSD硬盘一般也配备Cache,无非是对高性能的要求做的一种层次性的设计。使用内存缓冲区,可以减少进程之间的相互等待时间,降低内存分配的额外负担。
比如STL的空间配置器的设计上,SGI设计了双层级配置器,如果需要配置的空间“过小”(小于128bytes)时,直接采用memory pool的管理方式,维护一个小内存的list,专门负责配置和回收。
回到mbuf,从mbuf所承担的工作来看,mbuf必须像链表一样,在存储用户数据的时候作出一些空间上“浪费”的牺牲。单个mbuf的总长是128个字节,里面有20个字节是mbuf的首部,包含了这个mbuf个体的一些信息。其中包括:
- m_next 指向mbuf链中的下一个mbuf的指针,m_next把多个mbuf连在一起,形成一条mbuf链表。
- m_nextpkt 指向下一个mbuf链的指针,m_nextpkt把多个多个mbuf链表连在一起,形成一个mbuf链表的队列。
- m_len 此mbuf中数据部分的大小
- m_data 指向此mbuf中数据
- m_type 此mbuf中数据的类型,可以为MT_DATA或MT_HEADER(比如存储的是TCP报文段分组的首部)
- m_flags M_PKTHDR表示这个mbuf是此mubf链表中的第一个,即链表的头,0表示此mbuf只包含数据,M_EXT表示此mbuf用到了外部的簇来存储较大的数据。
mbuf头部的代码如下:
1 /* header at beginning of each mbuf: */ 2 struct m_hdr { 3 struct mbuf *mh_next; /* next buffer in chain */ 4 struct mbuf *mh_nextpkt; /* next chain in queue/record */ 5 int32_t mh_len; /* amount of data in this mbuf */ 6 caddr_t mh_data; /* location of data */ 7 short mh_type; /* type of data in this mbuf */ 8 short mh_flags; /* flags; see below */ 9 };
而mbuf结构的代码如下:
1 struct mbuf { 2 struct m_hdr m_hdr; 3 union { 4 struct { 5 struct pkthdr MH_pkthdr; /* M_PKTHDR set */ 6 union { 7 struct m_ext MH_ext; /* M_EXT set */ 8 char MH_databuf[_MHLEN]; 9 } MH_dat; 10 } MH; 11 char M_databuf[_MLEN]; /* !M_PKTHDR, !M_EXT */ 12 } M_dat; 13 };
从mbuf的结构代码中可以看出,在数据部分使用了union,包括了可选的mbuf分组首部,由m_flags来控制不同类型的mbuf,也分别具有额外的pkthdr首部或者m_ext首部。
参考资料: