当前位置: 首页 > news >正文

mbuf(存储器缓存)详解【转】

版权声明:本文为转载文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/yexiangCSDN/article/details/88355509

作者:HarkerYX

一、mbuf 介绍

在BSD TCP/IP协议栈代码设计中的一个基本概念就是存储器缓存,称作一个mbuf全称为"memory buffer",用于存储各种信息。mbuf的主要用途是保存在进程和网络接口间互相传递的用户数据。但mbuf也用于保存其他各种数据:源与目标地址、插口选项等等。mbuf相当于Linux内核中的skb。

mbuf的相关定义在文件/4.4BSD-Lite/usr/src/sys/sys/Mbuf.h

二、mbuf 结构体

/*每个mbuf的大小*/
#define    MSIZE        128    
/*一个mbuf簇(外部缓存)的大小*/
#define    MCLBYTES    2048
/*128-20=108,正常mbuf中的最大数据量*/
#define    MLEN        (MSIZE - sizeof(struct m_hdr))    /* normal data len */  
/*108-8=100,带分组首部的mbuf的最大数据量*/
#define    MHLEN        (MLEN - sizeof(struct pkthdr))    /* data len w/pkthdr */
/*208,存储到簇中的最小数据量*/
#define    MINCLSIZE    (MHLEN + MLEN)/* mbuf的头部信息 */
这个结构用来描述mbuf跟具体的内容无关
struct m_hdr {struct  mbuf *mh_next;        /* 指向链中下一个mbuf的指针 */struct  mbuf *mh_nextpkt;     /* 指向下一个链的指针 */int     mh_len;               /* mbuf中数据的长度(不包括头部) */char    *mh_data;             /* 指向数据区的指针 */short   mh_type;              /* mbuf的数据类型,如MT_DATA*/short   mh_flags;             /* mbuf标识,具体定义见下 */
};/ *记录/包头在链的第一个mbuf中; M_PKTHDR设置有效* /
struct pkthdr {int      len;                 /* 整个mbuf链表包含数据的总长度,在链表的第一个mbuf中维护一个带有总长度的分组首部的原因是,当需要总长度时可以避免查看所有mbuf中的mh_len来求和*/struct   ifnet *rcvif;        /* 指向接收分组的接收接口结构的指针*/
};/ *描述外部存储映射到mbuf,M_EXT设置有效* /
struct m_ext {caddr_t    ext_buf;        /* 缓冲区的开始 */void    (*ext_free)();        /* free routine if not the usual */u_int    ext_size;        /* 缓冲区大小,对于ext_free */
};这个就是mbuf的描述,设计的比较巧妙
struct mbuf {struct       m_hdr m_hdr;union {struct {struct       pkthdr MH_pkthdr;    /* M_PKTHDR set */union {struct     m_ext MH_ext;   /* M_EXT set */char       MH_databuf[MHLEN];} MH_dat;} MH;char       M_databuf[MLEN];              /* !M_PKTHDR, !M_EXT */} M_dat;
};// 为了便于访问,这里定义了很多宏
#define    m_next        m_hdr.mh_next
#define    m_len        m_hdr.mh_len
#define    m_data        m_hdr.mh_data
#define    m_type        m_hdr.mh_type
#define    m_flags        m_hdr.mh_flags
#define    m_nextpkt    m_hdr.mh_nextpkt
#define    m_act        m_nextpkt
#define    m_pkthdr    M_dat.MH.MH_pkthdr
#define    m_ext        M_dat.MH.MH_dat.MH_ext
#define    m_pktdat    M_dat.MH.MH_dat.MH_databuf
#define    m_dat        M_dat.M_databuf

mbuf的总长为128个字节,前20个字节是首部struct m_hdr),mbuf可以用成员mh_next和mh_nextpkt链接起来。(m_next指向链中下一个mbuf,而m_nextpkt指向下一个链)

 

三、mbuf 四种类型

可以看到mbuf大体由两部分组成,m_hdr和M_dat。

M_dat是个联合体,使用其中哪个成员是由m_hdr.mh_flags来决定的。

1.如果mh_flags里没有M_EXT与M_PKTHDR,则此mbuf完全是用来存放数据的。总共可以存放MLEN(108)字节的数据

2.如果mh_flags里有M_EXT则此mbuf使用外部簇(外部存储空间(cluster))来存放数据

3.如果mh_flags里有M_PKTHDR,则此mbuf是一个记录的起始mbuf(某个packet的一串mbuf中的第一个),由于MH_pkthdr占用了部分空间,总共只能存放MHLEN(100)字节的数据;

4.如果mh_flags里既有M_PKTHDR又有M_EXT(注意: 一个mbuf可以同时设置上述两个标志)则此mbuf是起始mbuf,但是使用外部簇来存放数据。

/* mbuf mh_flags*/#define       M_EXT        0x0001    /* 一个mbuf的大小是128字节,是一个相对比较小的缓存。如果数据比较多,就需要多个mbuf连起来或者用一个叫簇的东西来存储数据。M_EXT就是这个标志 */#define       M_PKTHDR     0x0002    /* 表明分组的第一个mbuf,在数据区中有pkthdr */
#define       M_EOR        0x0004    /* 表明记录的尾部,TCP是一个字节流,不设置这个标志 */

 

m_hdr.mh_type 介绍

/* mbuf types */
#define    MT_FREE        0    /* should be on free list */
#define    MT_DATA        1    /* dynamic (data) allocation */ 数据就是这个类型
#define    MT_HEADER    2    /* packet header */
#define    MT_SOCKET    3    /* socket structure */
#define    MT_PCB        4    /* protocol control block */
#define    MT_RTABLE    5    /* routing tables */
#define    MT_HTABLE    6    /* IMP host tables */
#define    MT_ATABLE    7    /* address resolution tables */
#define    MT_SONAME    8    /* socket name */
#define    MT_SOOPTS    10    /* socket options */
#define    MT_FTABLE    11    /* fragment reassembly header */
#define    MT_RIGHTS    12    /* access rights */
#define    MT_IFADDR    13    /* interface address */
#define MT_CONTROL    14    /* extra-data protocol message */
#define MT_OOBDATA    15    /* expedited data  */

 

当mh_flags设置为M_PKTHDR时,一般与下面的类型进行或操作 如 mh_flags |= M_MCAST

/* mbuf pkthdr flags, also in m_flags */#define M_BCAST 0x0100 /* send/received as link-level broadcast */#define M_MCAST 0x0200 /* send/received as link-level multicast *//* flags copied when copying m_pkthdr */
这个具体干嘛用的不懂。。。
#define    M_COPYFLAGS    (M_PKTHDR|M_EOR|M_BCAST|M_MCAST)

判断类型

(m_flags & M_PKTHDR) == 1

(m_flags & M_EXT) == 1

mbuf大小固定的理由:

1. 可以最大限度地避免内存碎片的产生

2. 可在不重新分配和拷贝的前提下完成协议对数据区的操作。

3. 如果mbuf不是固定长度,dtom()函数的开销将会非常大。

4. mbuf中的pakcet头中的tags用于携带一些关于packet的但又不能放在packet内部的信息。

 

四、mbuf 四种类型(图示)

把图中分为四个部分:从左到右依次叫 图-1,图-2,图-3,图-4

1.  m_flags的值为0图-1 表示此mbuf只包含数据。在mbuf中有108字节的数据空间(m_dat数组,详情见mbuf结构定义),指针m_data指向这108字节缓存中的某个位置。图中m_data指向缓存数据的起始位置,但它可以指向缓存中的任意位置。m_len指示了从m_data开始的数据字节数。

2.  m_flags的值为M_PKTHDR图-2 M_PKTHDR表示此mbuf是一个分组首部,而且是一个分组数据的第一个mbuf。数据仍然保存在这个mbuf中,但是由于分组首部占用8个字节,所以只有100字节的数据可以存储在这个mbuf中(m_pktdat数组,详情见mbuf结构定义)。

m_pkthdr.len的值是这个分组的mbuf链中所有数据的总长度即所有通过m_next指针链接的mbuf的m_len值的和。输出分组的m_pkthdr.rcvif为空,但是对于输入分组,m_pkthdr.rcvif是一个指向接收接口的ifnet结构的指针。

3.  m_flags的值为M_EXT图-3 这种mbuf没有分组首部(没有设置M_PKTHDR),但是包含超过208字节的数据(MINCLSIZE),此时用到一个叫“簇”的外部缓存(设置M_EXT)。此mbuf中仍然为分组首部分配了空间,但是没用图-3 中用阴影表示出来。

一般来说,我们希望这种类型的mbuf的m_len的值最小为209,即至少存储的数据大小为209字节(而不应该是图-3 中的208,图中有误)。208字节数据可以存放到两个mbuf中,第一个存放100字节,第二个存放108字节。

4. m_flags的值为M_PKTHDR|M_EXT图-4 此类mbuf包含一个分组首部,并且数据超过208字节。

关于mbuf的几点说明:

1. mbuf结构的大小总是128字节。这意味着图-3、图-4两个mbuf在结构m_ext后面的未用空间为88字节(128-20-8-12)。

2. 既然有些协议(例如UDP)允许零长记录,当然就可以有m_len为0的缓存。

3. 在每个mbuf中的成员m_data指向相应缓存数据的开始(mbuf本身或者一个簇)。这个指针能指向相应缓存的任意位置,不一定是开始。

4. 带有簇的mbuf总是包含缓存的起始地址(m_ext.ext_buf)以及缓存大小(m_ext.ext_size)。注意m_data和m_ext.ext_buf的不同含义,m_data是指向缓存数据的起始地址,m_ext.ext_buf是指向缓存(簇)的起始地址,只有当m_data也只指向缓存(簇)的第一个字节时,两者的值是一样的。

5. 指针m_next是把多个mbuf链接在一起,把一个分组形成一条mbuf链表。指针m_nextpkt把多个分组链接成一个mbuf队列。在队列中的每个分组可以是一个单独的mbuf,也可以是一个mbuf链表。每个分组的第一个mbuf包含一个分组首部。如果分组是一个mbuf链表,只有第一个mbuf的m_nextpktp被使用,其它mbuf的m_nextpkt为空指针。

上图是包含两个分组的mbuf队列,第一个分组UDP数据报已经放到接口输出队列中(14字节的以太网商务部已经添加到链表中第一个mbuf的IP首部前面);第二个分组TCP报文段(1460字节数据)也被添加到队列中,TCP数据包含在一个簇中,并且第一个mbuf中包含了以太网、IP与TCP首部,在这个簇中可以看到指向簇中缓存数据的指针m_data并没有指向簇的起始位置(注意理解)。

上图所示的是m_flags的五个独立的值。M_EXT和M_PKTHDR前文已经介绍过,如果数据流有记录边界,那么对于记录尾的mbuf其m_flags应该设置M_EOR,TCP从来不需要设置,因为它提供的是无记录边界的字节流服务。OSI和XNS运输层要使用到这个标志。M_BCAST和M_MCAST主要用于链接层广播或者多播数据的接收和发送。

m_type指示存储在mbuf中的数据类型。mbuf除了可以存放要发送或者接收的用户数据,还可以存储各种不同类型的数据结构,具体如上图所示。


http://www.taodudu.cc/news/show-5435439.html

相关文章:

  • 代码随想录-算法训练营day31【贪心算法01:理论基础、分发饼干、摆动序列、最大子序和】
  • Linux 案例命令使用操作总结
  • 2024年钉钉群直播回放怎么保存
  • Oracle ORA-28547:connection to server failed,probable Oracle Net admin error
  • weditor安装的时候产生的问题
  • Zoho CRM企业成长的智能引擎,智能化销售自动化
  • TCP IP详解卷2之mbuf宏与函数
  • Unix/Linux编程:四种mbuf
  • 2022CTF培训(十三)虚拟化QEMU架构分析QEMU CVE示例分析
  • C++ Primer Plus(第6版) 第3章编程练习
  • 【python-docx 07】使用word样式
  • python读取docx文件,就是如此简单
  • Caused by: java.lang.ClassNotFoundException: freemarker.template.Configuration
  • A component required a bean of type ‘XXX‘ that could not be found 解决办法
  • spring aop 自定义注解配合swagger注解保存操作日志到mysql数据库含(源码)
  • 小而美 | Mac上鲜为人知,但极大提升效率的小工具
  • 防火墙体系结构的组合形式
  • E - B-莲子的机械动力学
  • 需要克服的缺点
  • 高版本springboot整合swagger
  • PHP. 03 .ajax传输XML、 ajax传输json、封装
  • ajax请求php返回xml数据格式,ajax传输的数据格式(XML,json)怎么获取解析
  • JavaScript基础之Ajax总结大全
  • Ajax入门和发送http请求
  • 04-Ajax传输json和XML
  • python网络爬虫——爬虫第三方库的使用(二)
  • ajax使用频率,11-Ajax详解
  • 使用Ajax发送http请求(getpost请求)
  • 人加智能FPGA应用实践-AI快速进化
  • Mac显示证书不受信任或者无效的解决办法
  • Mac | 解决证书不受信任问题
  • Java 解析CA证书 对数据进行签名和验签
  • ca证书 csr_什么是csr证书
  • 招行网银证书不见了
  • 网银的业务学习之道:数字证书的基础知识
  • 网上银行安全证书工作原理