DPDK 中 mbuf 的结构

1. 单段 mbuf 的结构示意

An mbuf with One Segment:

image-20250510142226654

整个 mbuf 可分为两块:rte_mbuf 结构体和数据缓冲区(注意数据缓冲区(图中mbuf struct后面全部)和实际发送的数据包区域(图中红色部分)的区别)

  • mbuf struct rte_mbuf结构体,存放数据包的元信息
  • priv_data 私有数据区域,在mbuf struct后面,一般为 0,图中未展示.
  • headroom 数据缓冲区开头预留的一段空间(默认为RTE_PKTMBUF_HEADROOM = 128个字节)
  • rte_pktmbuf_datalen(m) 实际的数据包长度,即mbuf->data_len。单段 mbuf 的情况, pktlen等于datalen
  • tailroom 数据缓冲区剩余还未使用的空间

默认大小:

#define RTE_PKTMBUF_HEADROOM 128
#define    RTE_MBUF_DEFAULT_DATAROOM   2048
#define    RTE_MBUF_DEFAULT_BUF_SIZE   \
    (RTE_MBUF_DEFAULT_DATAROOM + RTE_PKTMBUF_HEADROOM)

2. rte_mbuf结构体中的部分成员变量含义

struct rte_mbuf {
    void *buf_addr;           /** mbuf 缓冲区的虚拟地址 */
    rte_iova_t buf_iova __rte_aligned(sizeof(rte_iova_t)); /** mbuf 缓冲区的物理地址 */
    uint16_t data_off;  /** 缓冲区内实际数据的偏移量,即headromm的长度 */
    uint16_t nb_segs; /** 段数量,只有第一段 mbuf 的 nb_segs 有效 */
    uint32_t pkt_len;         /** 整个数据包的数据字节数 */
    uint16_t data_len;        /** 当前 mbuf 的段内实际存储的数据字节数 */
    uint16_t buf_len;         /** 当前 mbuf 所分配的缓冲区总大小(包括 headroom + data + tailroom)*/
    struct rte_mempool *pool; /** 当前 mbuf 是由哪个mempool分配的 */
    struct rte_mbuf *next;    /** 当前 mbuf 的下一个段 */
    uint16_t priv_size;       /** 当前 mbuf 附带的私有数据区大小,介于 rte_mbuf struct 和 buffer(或者说 headroom)之间*/
}

mbuf->buf_addr 是整个缓冲区的起始地址

mbuf->data_offheadroom的长度

实际用户发送的数据包起始地址是(uint8-t *)mbuf->buf_addr + mbuf->data_off

也可以使用函数 rte_pktmbuf_mtod(mbuf, uint8_t *)来获取,等价于(uint8-t *)mbuf->buf_addr + mbuf->data_off

注意:

  1. rte_mbuf结构体并不包含实际数据,只是描述和指向数据,所有数据实际存在mbuf->buf_addr指向的 buffer 中;
  2. 为了性能,mbuf 在分配和释放时最好避免跨 NUMA 节点。

3. 向 mbuf 中写入数据的方法

✅推荐方法

void *data_ptr = rte_pktmbuf_append(mbuf, data_len);
memcpy(data_ptr, your_data, data_len);

❌不推荐方法

char *pkt_data = rte_pktmbuf_mtod(mbuf, char *);
memcpy(pkt_data, my_data, data_len);
// 必须自己更新长度字段
mbuf->data_len = data_len;
mbuf->pkt_len  = data_len;

使用该方式,可能会忘记更新data_lenpkt_len,导致异常。

4. headroom作用

主要用于协议栈预留空间,比如添加额外的协议头。

默认情况下,网卡实际发送的数据范围是起始地址为(uint8-t *)mbuf->buf_addr + mbuf->data_off,长度为mbuf->data_len的部分。

如果添加了额外的协议头,并希望被网卡发送出去,则需要:

  1. 把协议头写入headroom区域
  2. 调整mbuf->data_off,增加mbuf->datambuf->pkt_len的值,确保新加的数据在发送范围之内

✅推荐方法

// 在 mbuf 前部预留 20 字节空间
void *hdr = rte_pktmbuf_prepend(mbuf, 20); // 最好判断一下 hdr 是否为空
// 将 header 内容写入新预留空间
memcpy(hdr, my_header_data, 20);

❌不推荐方法

// 向前移动 data_off
mbuf->data_off -= 20;

// 把你的 header 数据写入 headroom 中对应位置
memcpy((char *)mbuf->buf_addr + mbuf->data_off, my_header, 20);

// 更新长度
mbuf->data_len += 20;
mbuf->pkt_len += 20;

【参考】

  1. DPDK官方Programmer’s Guide
  2. DPDK官方API解释rte_pktmbuf_pool_create
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇