1、知识百科rte_mbuf的结构与linux内核协议栈的skb_buf相似,在保存报文的内存块前后分别保留headroom和tailroom,以方便应用解封报文,headroom默认128字节,可以通过宏RTE_PKTMBUF_HEADROOM调整。返回值操作函数函数功能宏rte_pktmbuf_mtod(m, t)将指针指到数据部分的首部宏rte_pktmbuf_pkt_len(m) 获取所有mbuf的数据长度宏rte_pktmbuf_data_len(m)获取本mbuf的数据长度char *rte_get_rx_ol_flag_name char *rte_get_tx_ol_flag_name uint16_trte_mbuf_refcnt_update uint16_trte_mbuf_refcnt_read void rte_mbuf_refcnt_set void rte_mbuf_sanity_check void rte_ctrlmbuf_init intrte_is_ctrlmbuf voidrte_pktmbuf_init voidrte_pktmbuf_pool_init void rte_pktmbuf_reset struct rte_mbuf *rte_pktmbuf_alloc从rte_mempool获取一个mbufvoid rte_pktmbuf_attach void rte_pktmbuf_detach voidrte_pktmbuf_free_seg voidrte_pktmbuf_free将mbuf归还到rte_mempool中struct rte_mbuf *rte_pktmbuf_clone voidrte_pktmbuf_refcnt_update uint16_trte_pktmbuf_headroom计算出mbuf的headroom大小uint16_trte_pktmbuf_tailroom计算出mbuf的tailroom大小struct rte_mbuf *rte_pktmbuf_lastseg char *rte_pktmbuf_prepend char *rte_pktmbuf_append向mbuf追加数据,修改pkt_len和data_lenchar *rte_pktmbuf_adj向mbuf删减数据,修改pkt_len和data_lenintrte_pktmbuf_trim intrte_pktmbuf_is_contiguous voidrte_pktmbuf_dump 2、数据结构rte_vlan_macipunion rte_vlan_macip { uint32_t data; struct { uint16_t l3_len:9; //L3层首部= sizeof(struct ipv4_hdr)=20 uint16_t l2_len:7; // L3层首部= sizeof(struct ether_hdr)=14 uint16_t vlan_tci; }f;};rte_pktmbufstruct rte_pktmbuf { struct rte_mbuf *next; /**< Next segment of scattered packet. */ void*data; //mbuf数据部分的起始位置 uint16_tdata_len; //本mbuf的数据长度 uint8_t nb_segs; /**< Number of segments. */ uint8_t in_port; /**< Input port. */ uint32_tpkt_len; //所有mbuf的数据长度 union rte_vlan_macipvlan_macip; union { uint32_t rss; /**< RSS hash result if RSS enabled */ struct { uint16_t hash; uint16_t id; } fdir; /**< Filter identifier if FDIR enabled */ uint32_t sched; /**< Hierarchical scheduler */ } hash; /**< hash information */};rte_mbufstruct rte_mbuf { struct rte_mempool *pool; /**< Pool from which mbuf was allocated. */ void *buf_addr; //mbuf的起始地址 phys_addr_t buf_physaddr; /**< Physical address of segment buffer. */ uint16_tbuf_len; //mbuf的长度=mp->elt_size - sizeof(struct rte_mbuf) union { rte_atomic16_t refcnt_atomic; /**< Atomically accessed refcnt */ uint16_t refcnt; /**< Non-atomically accessed refcnt */ }; uint8_t type; /**< Type of mbuf. */ uint8_t reserved; /**< Unused field. Required for padding. */ uint16_t ol_flags; // PKT_TX_IP_CKSUM=0x1000,让网卡计算checksum union { struct rte_ctrlmbuf ctrl; struct rte_pktmbufpkt; };} __rte_cache_aligned;3、操作函数mbuf_init->rte_mempool_create函数功能:mbuf由缓冲池rte_mempool管理,rte_mempool在初始化时一次申请多个mbuf,申请的mbuf个数和长度都由用户指定,使用rte_pktmbuf_alloc申请一个mbuf。app.lcore_params[lcore].pool = rte_mempool_create( name, DEFAULT_MEMPOOL_BUFFERS, // 8192 * 32=256K个 DEFAULT_MBUF_SIZE, // (4096 + sizeof(struct rte_mbuf) + 128) DEFAULT_MEMPOOL_CACHE_SIZE,//32 sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL, 0, 0); #define RTE_PKTMBUF_HEADROOM 128备注:调用rte_mempool_create()函数创建rte_mempool的时候,指定申请多少个rte_mbuf以及每个rte_mbuf中elt_size大小,elt_size是为网卡接收的数据包预先分配的内存的大小,该内存块就是rte_mbuf->pkt.data的实际存储区域。rte_pktmbuf_alloc函数功能:从rte_mempool获取一个mbuf。static inline struct rte_mbuf *rte_pktmbuf_alloc(struct rte_mempool *mp){ struct rte_mbuf *m; if ((m = __rte_mbuf_raw_alloc(mp)) != NULL) rte_pktmbuf_reset(m); return (m);}rte_pktmbuf_free函数功能:将mbuf归还到rte_mempool中。static inline void rte_pktmbuf_free(struct rte_mbuf *m){ struct rte_mbuf *m_next; __rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 1); while (m != NULL) { m_next = m->pkt.next; rte_pktmbuf_free_seg(m); m = m_next; }}rte_pktmbuf_mtod函数功能:将指针指到数据部分的首部。#define rte_pktmbuf_mtod(m, t) ((t)((m)->pkt.data))rte_pktmbuf_pkt_len函数功能:获取所有mbuf的数据长度。#define rte_pktmbuf_pkt_len(m) ((m)->pkt.pkt_len)rte_pktmbuf_data_len函数功能:获取本mbuf的数据长度。#define rte_pktmbuf_data_len(m) ((m)->pkt.data_len)rte_pktmbuf_headroom函数功能:计算出mbuf的headroom大小。static inline uint16_t rte_pktmbuf_headroom(const struct rte_mbuf *m){ __rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 1); return (uint16_t) ((char*)m->pkt.data - (char*) m->buf_addr);}rte_pktmbuf_tailroom函数功能:计算出mbuf的tailroom大小。static inline uint16_t rte_pktmbuf_tailroom(const struct rte_mbuf *m){ __rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 1); return (uint16_t)(m->buf_len - rte_pktmbuf_headroom(m) - m->pkt.data_len);}rte_pktmbuf_append函数功能:向mbuf追加数据,修改pkt_len和data_len。static inline char *rte_pktmbuf_append(struct rte_mbuf *m, uint16_t len){ void *tail; struct rte_mbuf *m_last; __rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 1); m_last = rte_pktmbuf_lastseg(m); if (unlikely(len > rte_pktmbuf_tailroom(m_last))) return NULL; tail = (char*) m_last->pkt.data + m_last->pkt.data_len; //tail的首地址 m_last->pkt.data_len = (uint16_t)(m_last->pkt.data_len + len);//修改last mbuf的data_len m->pkt.pkt_len = (m->pkt.pkt_len + len); //修改所有mbuf的pkt_len return (char*) tail;} rte_pktmbuf_adj函数功能:向mbuf删减数据,修改pkt_len和data_len。static inline char *rte_pktmbuf_adj(struct rte_mbuf *m, uint16_t len){ __rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 1); if (unlikely(len > m->pkt.data_len)) return NULL; m->pkt.data_len= (uint16_t)(m->pkt.data_len - len); m->pkt.data= ((char*) m->pkt.data + len); m->pkt.pkt_len = (m->pkt.pkt_len - len); return (char*) m->pkt.data;}4、应用实例网卡接收包struct rte_mbuf *m = _m;uint32_tbuf_len= mp->elt_size - sizeof(struct rte_mbuf);RTE_MBUF_ASSERT(mp->elt_size >= sizeof(struct rte_mbuf));memset(m, 0, mp->elt_size); m->buf_addr= (char *)m + sizeof(struct rte_mbuf);m->buf_len= (uint16_t)buf_len;m->pkt.data= (char*) m->buf_addr + RTE_MIN(RTE_PKTMBUF_HEADROOM, m->buf_len); m->type = RTE_MBUF_PKT;….填充新数据如果需要在tailroom中加入N个字节数据,我们可以通过以下操作完成:tail = m->pkt.data + m->pkt.data_len; // tail记录tailroom首地址m->pkt.data_len += N;m->pkt.pkt_len += N;这些操作由rte_pktmbuf_append()实现,函数原型如下:char *rte_pktmbuf_append(struct rte_mbuf *m, uint16_t len)剥离数据假设m->pkt.data指向报文的二层首地址,我们可以通过以下一系列操作剥去报文的二层头部:m->pkt.data += 14;m->pkt.data_len -= 14;m->pkt.pkt_len -= 14;这些操作已经由rte_pktmbuf_adj()实现,函数原型如下:char *rte_pktmbuf_adj(struct rte_mbuf *m, uint16_t len)5、参考资料rte_mbufhttp://dpdk.org/doc/api/rte__mbuf_8h.htmlhttp://www.tuicool.com/articles/rYfqMbhttp://www.cnblogs.com/ziding/p/4214499.html dpdk-mempoolhttp://dpdk.org/doc/api/rte__mempool_8h.html