【轉載】DPDK編程開發(5)—mbuf

原文

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、數據結構

clip_image002[8]

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、操作函數

clip_image002[6]

mbuf_init->rte_mempool_create

函數功能:mbuf由緩衝池rte_mempool管理,rte_mempool在初始化時一次申請多個mbuf,申請的mbuf個數和長度都由用戶指定,使用rte_pktmbuf_alloc申請一個mbuf

image

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_t buf_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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章