【转载】DPDK编程开发(5)—mbuf

时间:2022-09-29 22:31:05

原文

1、知识百科

rte_mbuf的结构与linux内核协议栈的skb_buf相似,在保存报文的内存块前后分别保留headroomtailroom,以方便应用解封报文,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_t

rte_mbuf_refcnt_update

 

uint16_t

rte_mbuf_refcnt_read 

 

void 

rte_mbuf_refcnt_set 

 

void 

rte_mbuf_sanity_check

 

void 

rte_ctrlmbuf_init

 

int

rte_is_ctrlmbuf

 

void

rte_pktmbuf_init

 

void

rte_pktmbuf_pool_init

 

void 

rte_pktmbuf_reset

 

struct rte_mbuf *

rte_pktmbuf_alloc

rte_mempool获取一个mbuf

void 

rte_pktmbuf_attach

 

void 

rte_pktmbuf_detach

 

void

rte_pktmbuf_free_seg

 

void

rte_pktmbuf_free

mbuf归还到rte_mempool

struct rte_mbuf *

rte_pktmbuf_clone

 

void

rte_pktmbuf_refcnt_update

 

uint16_t

rte_pktmbuf_headroom

计算出mbufheadroom大小

uint16_t

rte_pktmbuf_tailroom

计算出mbuftailroom大小

struct rte_mbuf *

rte_pktmbuf_lastseg

 

char *

rte_pktmbuf_prepend

 

char *

rte_pktmbuf_append

mbuf追加数据,修改pkt_lendata_len

char *

rte_pktmbuf_adj

mbuf删减数据,修改pkt_lendata_len

int

rte_pktmbuf_trim

 

int

rte_pktmbuf_is_contiguous

 

void

rte_pktmbuf_dump

 

2、数据结构

【转载】DPDK编程开发(5)—mbuf

rte_vlan_macip

union 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_pktmbuf

struct rte_pktmbuf {

                  struct rte_mbuf *next;  /**< Next segment of scattered packet. */

                  void* data;            //mbuf数据部分的起始位置

                  uint16_t data_len;      //mbuf的数据长度

 

                  uint8_t nb_segs;        /**< Number of segments. */

                  uint8_t in_port;        /**< Input port. */

                  uint32_t pkt_len;       //所有mbuf的数据长度

 

                  union rte_vlan_macip vlan_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_mbuf

struct 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_t buf_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_pktmbuf pkt;

                  };

} __rte_cache_aligned;

3、操作函数

【转载】DPDK编程开发(5)—mbuf

mbuf_init->rte_mempool_create

函数功能:mbuf由缓冲池rte_mempool管理,rte_mempool在初始化时一次申请多个mbuf,申请的mbuf个数和长度都由用户指定,使用rte_pktmbuf_alloc申请一个mbuf

【转载】DPDK编程开发(5)—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_mbufelt_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

函数功能:计算出mbufheadroom大小。

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

函数功能:计算出mbuftailroom大小。

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_lendata_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 mbufdata_len

                  m->pkt.pkt_len  = (m->pkt.pkt_len + len);                //修改所有mbufpkt_len

                  return (char*) tail;

}

 

rte_pktmbuf_adj

函数功能:mbuf删减数据,修改pkt_lendata_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_mbuf

http://dpdk.org/doc/api/rte__mbuf_8h.html

http://www.tuicool.com/articles/rYfqMb

http://www.cnblogs.com/ziding/p/4214499.html

 

dpdk-mempool

http://dpdk.org/doc/api/rte__mempool_8h.html