第2章 mbuf:存储器缓存

所属:TCP/IP详解 卷2:实现 来源:TCP/IP详解 卷2:实现

本章描述mbuf(memory buffer)的结构和操作,mbuf是内核中用于存储网络数据的基本单元。


2.1 引言

什么是mbuf

mbuf(memory buffer):

  • 内核中用于存储网络数据的结构
  • 内存缓冲区
  • 灵活的内存管理
  • 可以链接成链表
  • 避免大量数据拷贝

mbuf是网络数据的基本存储单元。


为什么需要mbuf

mbuf的作用:

  1. 存储网络数据

    • 存储接收和发送的数据
    • 存储协议首部
  2. 灵活管理

    • 可以动态分配和释放
    • 可以链接起来
    • 支持各种长度的数据
  3. 提高效率

    • 避免数据拷贝
    • 直接操作指针
    • 高效的首部添加和移除

mbuf设计的目标是高效和灵活。


2.2 mbuf的结构

mbuf结构定义

mbuf的结构:

struct mbuf {
    struct  mbuf *m_next;       /* 下一个mbuf */
    u_char  *m_data;            /* 数据起始位置 */
    u_int   m_len;              /* 数据长度 */
    u_char  m_type;             /* 类型 */
    u_char  m_flags;            /* 标志 */
    /* ... 其他字段 ... */
    
    union {
        struct {
            u_char  *m_pktdat;  /* 分组数据 */
        } M_dat;
        struct {
            struct mbuf *m_fre; /* 空闲链表 */
        } M_fre;
        /* ... 其他联合体 ... */
    } M_dat;
};

字段说明

字段说明
m_next指向下一个mbuf,链表结构
m_data指向当前数据的起始位置
m_len当前mbuf中数据的长度
m_typembuf的类型
m_flags标志位

m_next把多个mbuf链接成链表。


mbuf的类型

常见的mbuf类型:

类型说明
MT_FREE空闲
MT_DATA数据
MT_HEADER协议首部
MT_SOCKET套接字
MT_PCB协议控制块
MT_RTABLE选路表
…其他类型

不同类型用于不同的用途。


mbuf的标志

常见的mbuf标志:

标志说明
M_PKTHDR分组首部
M_EOR记录结束
M_BCAST广播发送
M_MCAST多播发送
M_EXT外部存储

标志描述mbuf的属性。


2.3 mbuf的链表结构

三种链表结构

mbuf有三种链表结构:

  1. 简单链表(m_next)

    • 单链表
    • 一个接一个
    • 存储连续的数据
  2. 分组链表(m_nextpkt)

    • 整个分组的链表
    • 每个分组是一个mbuf链
    • 用于队列
  3. mbuf队列(ifqueue)

    • 接口的发送/接收队列
    • 多个分组排队

mbuf可以组成各种链表结构。


分组的结构

一个IP分组的mbuf结构:

mbuf 1          mbuf 2          mbuf 3
+--------+      +--------+      +--------+
| m_next |----->| m_next |----->| m_next |-----> NULL
+--------+      +--------+      +--------+
| m_data |      | m_data |      | m_data |
+--------+      +--------+      +--------+
| m_len  |      | m_len  |      | m_len  |
+--------+      +--------+      +--------+
|  IP首部  |      | TCP首部 |      |  数据   |
|        |      |        |      |        |
+--------+      +--------+      +--------+

一个分组可以由多个mbuf组成。


2.4 mbuf的操作

分配和释放

分配mbuf:

  • m_get:分配一个mbuf
  • m_gethdr:分配一个带分组首部的mbuf
  • m_clget:分配外部存储

释放mbuf:

  • m_free:释放一个mbuf
  • m_freem:释放整个mbuf链

分配和释放是基本操作。


数据操作

常用的数据操作:

函数功能
m_copy复制mbuf链
m_pullup把数据拉到前面,确保连续
m_prepend在前面添加数据
m_adj调整指针,跳过数据
m_cat连接两个mbuf链
m_dup复制整个分组

各种操作方便数据处理。


m_pullup

m_pullup的作用:

  • 确保前N字节是连续的
  • 方便访问协议首部
  • 如果不连续,就重新排列

为什么需要:

  • 协议首部通常在最前面
  • 需要连续访问
  • mbuf可能不连续

m_pullup确保首部连续。


m_prepend

m_prepend的作用:

  • 在数据前面添加空间
  • 用于添加协议首部
  • 发送时每层都要加首部

例子:

  • TCP发送时,IP层要加IP首部
  • 调用m_prepend预留空间
  • 然后写入IP首部

m_prepend在前面添加空间。


m_adj

m_adj的作用:

  • 调整m_data和m_len
  • 跳过前面的数据
  • 用于移除首部

例子:

  • IP接收时,处理完IP首部
  • 调用m_adj跳过IP首部
  • 然后交给TCP

m_adj调整指针,不拷贝数据。


2.5 外部存储

什么是外部存储

外部存储(external storage):

  • mbuf本身很小,只有128字节左右
  • 大数据用外部存储
  • mbuf指向外部的大缓冲区
  • M_EXT标志表示有外部存储

大数据用外部存储,小数据用mbuf本身。


为什么需要外部存储

好处:

  • 支持大数据
  • 减少mbuf的数量
  • 提高效率
  • 减少链表长度

代价:

  • 管理更复杂
  • 需要引用计数
  • 分配释放开销大

大小数据用不同的方式。


2.6 mbuf的统计和监控

统计信息

mbuf的统计:

  • 总数
  • 空闲数
  • 各种类型的数量
  • 等待数
  • 失败数

可以监控mbuf的使用情况。


调优

mbuf的调优:

  • 调整mbuf的数量
  • 调整外部存储的大小
  • 根据负载调整
  • 避免mbuf不足

合理配置mbuf可以提高性能。


2.7 小结

mbuf概述

  1. 什么是mbuf

    • 内存缓冲区
    • 存储网络数据
    • 内核网络的基本单元
  2. 为什么需要

    • 灵活管理
    • 避免拷贝
    • 高效处理

mbuf结构

  1. 结构定义

    • m_next:下一个
    • m_data:数据指针
    • m_len:数据长度
    • m_type:类型
    • m_flags:标志
  2. 类型和标志

    • 各种类型
    • 各种标志

链表结构

  1. 简单链表

    • m_next链接
    • 存储数据
  2. 分组链表

    • 整个分组的链
    • 用于队列
  3. 队列

    • 多个分组排队
    • 接口队列

mbuf操作

  1. 分配释放

    • m_get / m_free
    • m_gethdr / m_freem
  2. 数据操作

    • m_copy:复制
    • m_pullup:拉平
    • m_prepend:前面加
    • m_adj:调整
    • m_cat:连接
    • m_dup:复制分组

外部存储

  1. 什么是外部存储

    • 大数据用
    • mbuf指向外部
    • M_EXT标志
  2. 优缺点

    • 优点:支持大数据,减少mbuf
    • 缺点:管理复杂

关键概念

  1. mbuf

    • 网络数据的基本存储单元
    • 灵活高效
  2. 链表结构

    • 多个mbuf链接
    • 支持任意长度
  3. 操作函数

    • 各种操作函数
    • 方便数据处理
  4. 外部存储

    • 大数据用
    • 提高效率

mbuf存储器缓存