由于网络协议栈是分层的,因此对数据缓冲区提出了以下要求:

  • 能够方便地在头部和尾部添加数据。(下层封装上层数据)

  • 能够方便地从缓存中移出数据。(数据传递给上层时需要移除头部)

  • 尽量减少拷贝。

BSD 给出的答案是 mbuf(memory buffer)。

mbuf 种类

mbuf 的定义如下:

sys/mbuf.h
struct m_hdr {
    struct mbuf *mh_next;
    struct mbuf *mh_nextpkt;
    caddr_t mh_data;
    int mh_len;
    short mh_type; (1)
    short mh_flags; (2)
};

struct mbuf { (3)
    struct m_hdr m_hdr;
    union {
    } M_dat;
};

#define m_flags m_hdr.mh_flags
  1. mbuf 中储存的数据类型:

    类型说明

    MT_FREE

    should be on free list

    MT_DATA

    dynamic (data) allocation

    MT_HEADER

    packet header

    MT_SOCKET

    socket structure

    MT_PCB

    protocol control block

    MT_RTABLE

    routing tables

    MT_HTABLE

    IMP host tables

    MT_ATABLE

    address resolution tables

    MT_SONAME

    socket name

    MT_SOOPTS

    socket options

    MT_FTABLE

    fragment reassembly header

    MT_RIGHTS

    access rights

    MT_IFADDR

    interface address

    MT_CONTROL

    extra-data protocol message

    MT_OOBDATA

    expedited data

  2. mbuf 的类型

  3. mbuf 的大小为 128B。

根据 m_flags 的值,mbuf 一共分为四种类型:

m_flags作用

0

mbuf 只包含数据

struct mbuf {
    struct m_hdr m_hdr; // 20B
    union {
        char M_databuf[MLEN]; (1)
    } M_dat;
};
#define m_dat M_dat.M_databuf (2)
  1. MLEN 为 108。这种类型的 mbuf 能够储存 108 字节的用户数据。

  2. 用于简化 taggled union 字段的访问。

M_PKTHDR

分组首部

struct mbuf {
    struct m_hdr m_hdr;
    union {
        struct {
            struct pkthdr MH_pkthdr; // 8B
            union {
                char MH_databuf[MHLEN]; (1)
            } MH_dat;
        } MH;
    } M_dat;
};

#define m_pktdat M_dat.MH.MH_dat.MH_databuf
  1. MHLEN 为 100。mbuf 能够储存 100 字节的用户数据。

M_EXT

数据簇

struct m_ext {
    caddr_t ext_buf;
    void (*ext_free)();
    u_int ext_size;
};

struct mbuf {
    struct m_hdr m_hdr;
    union {
        struct {
            struct pkthdr MH_pkthdr; // 8B
            union {
                struct m_ext MH_ext; (1)
            } MH_dat;
        } MH;
    } M_dat;
};
  1. 2048B 的外部数据缓存。

M_PKTHDR | M_EXT

包含了分组首部的数据簇

mbuf 的基本结构

mbuf 本是是一个单向链表。其结构为:

Diagram

mbuf 的分配和释放

mbuf 的分配和释放函数如下:

函数作用
void MGET(struct mbuf **m, int how, int type); (1)

分配一个 mbuf。

void MFREE(struct mbuf *m, struct mbuf *n);

释放 mbuf

  1. 由于 MGET 实际上是一个宏,所以第一个参数类型实际上为 mbuf *m

需要注意的时,这两个函数实际上都是宏,但是被改写成了函数形式。MGET 的准确定义为:

#define MGET(m, how, type)                                       \
    {                                                            \
        MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
        if (m) {                                                 \
            (m)->m_type = (type);                                \
            MBUFLOCK(mbstat.m_mtypes[type]++;)                   \
            (m)->m_next = (struct mbuf *)NULL;                   \
            (m)->m_nextpkt = (struct mbuf *)NULL;                \
            (m)->m_data = (m)->m_dat;                            \
            (m)->m_flags = 0;                                    \
        } else                                                   \
            (m) = m_retry((how), (type));                        \
    }
Last moify: 2022-12-04 15:11:33
Build time:2025-07-18 09:41:42
Powered By asphinx