分段错误 DPDK
Posted
技术标签:
【中文标题】分段错误 DPDK【英文标题】:Segmentation fault DPDK 【发布时间】:2021-08-16 18:59:52 【问题描述】:我使用 dpdk 库编写了一个发送方应用程序。
struct my_message
struct rte_ether_hdr eth_hdr; // the ethernet header
char payload[10];
;
*/ Sender Application */
void my_send(struct rte_mempool *mbuf_pool, uint16_t port, uint64_t max_packets)
int retval;
struct rte_mbuf *bufs[BURST_SIZE];
struct rte_ether_addr src_mac_addr;
retval = rte_eth_macaddr_get(0, &src_mac_addr); // gets MAC address of Port 0
struct rte_ether_addr dst_mac_addr = 0xaa,0xbb,0xcc,0xdd,0xee,0xff;
struct my_message *my_pkt;
int j=0;
uint16_t sent_packets = BURST_SIZE; //BURST_SIZE is 256
do
for(int i = 0; i < sent_packets; i ++)
bufs[i] = rte_pktmbuf_alloc(mbuf_pool); //allocates a new mbuff from mempool
my_pkt = rte_pktmbuf_mtod(bufs[i], struct my_message*); //points (pointer is casted to struct my_message*) to start of data in mbuf
*my_pkt->payload = 'Hello2021';
int pkt_size = sizeof(struct my_message);
bufs[i]->pkt_len = bufs[i]->data_len = pkt_size;
rte_ether_addr_copy(&src_mac_addr, &my_pkt->eth_hdr.s_addr);
rte_ether_addr_copy(&dst_mac_addr, &my_pkt->eth_hdr.d_addr);
my_pkt->eth_hdr.ether_type = htons(PTP_PROTOCOL);
const uint16_t sent_packets = rte_eth_tx_burst(port, 0, bufs, BURST_SIZE);
printf("Number of packets tx %" PRIu16 "\n", sent_packets);
j = j + sent_packets;
while(j < max_packets);
/* Free any unsent packets. */
if (unlikely(sent_packets < BURST_SIZE))
uint16_t buf;
for (buf = sent_packets; buf < BURST_SIZE; buf++)
rte_pktmbuf_free(bufs[buf]);
我把这个函数称为
int main(int argc, char *argv[])
--
EAL initialization and port initialization
--
struct rte_mempool *mbuf_pool;
my_send(mbuf_pool, 0, 3000000);
该程序编译没有错误,但是,在运行该程序时,我遇到了分段错误。以下是输出:
我运行了 gdb,但无法从 gdb 输出进行调试
并收到以下消息
线程 1“app_tx_v2”收到信号 SIGSEGV,分段错误。 my_send()中的0x0000555555555567
【问题讨论】:
请提供minimal reproducible example 并将图片替换为文本输出。来自How do I ask a good question?:“请勿发布代码、数据、错误消息等的图片。 - 将文本复制或输入到问题中” @stackinside,感谢您的提示。rte_pktmbuf_alloc()
返回一个 NULL 指针确实是对的。下一步是了解为什么会发生这种情况。以及如何避免这种情况。
【参考方案1】:
根据提供的源代码和调试打印输出,每次rte_eth_tx_burst()
发送整批 256 mbuf 失败时,您的程序都会泄漏未发送的数据包。循环重复从而覆盖mbufs
。泄漏随后增加,并且内存池用完了可用对象。在某些时候rte_pktmbuf_alloc()
返回NULL
。您的程序不检查返回值,因此后续访问 mbuf 数据会导致观察到的分段错误。
至于调试信息,我相信您已经知道需要在 gcc
调用上指定 -g
参数才能拥有它。另外,请务必指定-Wall
键。
至于程序本身,它很难阅读,因此它隐藏了上述 mbuf 泄漏。考虑通过以下方式重新实现它:
static void
fill_out_mbuf(struct rte_mbuf *m)
/* Get mtod */
/* Set the data / packet size */
/* Fill out the header and payload */
/* ... */
static uint16_t
send_mbufs(uint16_t port,
struct rte_mbuf **mbufs,
uint16_t nb)
uint16_t ret;
ret = rte_eth_tx_prepare(port, 0, mbufs, nb);
if (ret == 0)
return 0;
return rte_eth_tx_burst(port, 0, mbufs, ret);
#define NB_RETRIES_MAX (1000)
static void
my_send(struct rte_mempool *mbuf_pool,
uint16_t port,
uint64_t max_packets)
struct rte_mbuf *mbufs[BURST_SIZE];
unsigned int nb_retries;
uint16_t nb_mbufs;
uint16_t nb_done;
uint16_t i;
if (max_packets == 0)
return;
do
memset(mbufs, 0, sizeof(mbufs));
nb_mbufs = RTE_MIN(max_packets, RTE_DIM(mbufs));
nb_retries = 0;
nb_done = 0;
if (rte_pktmbuf_alloc_bulk(mbuf_pool, mbufs, nb_mbufs) != 0)
break;
for (i = 0; i < nb_mbufs; ++i)
fill_out_mbuf(mbufs[i]);
do
nb_done += send_mbufs(port, mbufs + nb_done, nb_mbufs - nb_done);
++nb_retries;
while (nb_done < nb_mbufs && nb_retries < NB_RETRIES_MAX);
max_packets -= nb_done;
while (max_packets > 0 && nb_retries < NB_RETRIES_MAX);
for (i = nb_done; i < nb_mbufs; ++i)
rte_pktmbuf_free(mbufs[i]);
这里的重点如下:
-
为了代码清晰起见,将
fill_out_mbuf()
等函数分解出来;
根据 RTE API 合同的要求,在 rte_eth_tx_burst()
之前调用 rte_eth_tx_prepare()
;
使用rte_pktmbuf_alloc_bulk()
提高疗效;
如果 mbuf 批处理只发送了部分,不要从头开始;而是尝试发送剩余的 mbuf;
不要无限重试发送;限制重试次数。
【讨论】:
以上是关于分段错误 DPDK的主要内容,如果未能解决你的问题,请参考以下文章
为啥这段代码在 leetcode 运行良好,但在 geeksforgeeks 出现分段错误?