原文
1、知識百科
rte_mbuf的結構與linux內核協議棧的skb_buf相似,在保存報文的內存塊前後分別保留headroom和tailroom,以方便應用解封報文,headroom默認128字節,可以通過宏RTE_PKTMBUF_HEADROOM調整。
返回值 |
操作函數 |
函數功能 |
宏 |
rte_pktmbuf_mtod(m, t) |
將指針指到數據部分的首部 |
宏 |
獲取所有mbuf的數據長度 |
|
宏 |
獲取本mbuf的數據長度 |
|
char * |
|
|
char * |
|
|
uint16_t |
|
|
uint16_t |
|
|
void |
|
|
void |
|
|
void |
|
|
int |
|
|
void |
|
|
void |
|
|
void |
|
|
struct rte_mbuf * |
從rte_mempool獲取一個mbuf |
|
void |
|
|
void |
|
|
void |
|
|
void |
將mbuf歸還到rte_mempool中 |
|
struct rte_mbuf * |
|
|
void |
|
|
uint16_t |
計算出mbuf的headroom大小 |
|
uint16_t |
計算出mbuf的tailroom大小 |
|
struct rte_mbuf * |
|
|
char * |
|
|
char * |
向mbuf追加數據,修改pkt_len和data_len |
|
char * |
向mbuf刪減數據,修改pkt_len和data_len |
|
int |
rte_pktmbuf_trim |
|
int |
rte_pktmbuf_is_contiguous |
|
void |
rte_pktmbuf_dump |
|
2、數據結構
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、操作函數
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_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