段错误DPDK
Segmentation fault DPDK
我使用 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
根据提供的源代码和调试打印输出,每次 rte_eth_tx_burst()
发送整批 256 mbuf 失败时,您的程序都会泄漏未发送的数据包。循环重复从而覆盖 mbufs
。泄漏随后增长,内存池用完可用对象。在某个时候 rte_pktmbuf_alloc()
returns NULL
。您的程序不检查 return 值,因此对 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 库编写了一个发件人应用程序。
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根据提供的源代码和调试打印输出,每次 rte_eth_tx_burst()
发送整批 256 mbuf 失败时,您的程序都会泄漏未发送的数据包。循环重复从而覆盖 mbufs
。泄漏随后增长,内存池用完可用对象。在某个时候 rte_pktmbuf_alloc()
returns NULL
。您的程序不检查 return 值,因此对 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;
- 不要无限重试发送;限制重试次数。