Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I've written a sender application using dpdk libraries.
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
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]);
I call this function as
int main(int argc, char *argv[])
EAL initialization and port initialization
struct rte_mempool *mbuf_pool;
my_send(mbuf_pool, 0, 3000000);
The program compiles with no errors, however, upon running this program, I'm getting a segmentation fault. Following is the output:
I ran gdb but couldn't debug from the gdb output
and got the following message
Thread 1 "app_tx_v2" received signal SIGSEGV, Segmentation fault.
0x0000555555555567 in my_send ()
–
–
As per the provided source code and debug printouts, every time rte_eth_tx_burst()
fails to send the whole batch of 256 mbufs, your program leaks unsent packets. The loop reiterates thus overwriting mbufs
. The leak subsequently grows, and the mempool runs out of available objects. At some point rte_pktmbuf_alloc()
returns NULL
. Your program does not check the return value and thus the subsequent access to the mbuf data causes the observed segmentation fault.
As for debug information, I trust you already know that one needs to specify -g
argument on gcc
invocation in order to have it. Also, please make sure to specify -Wall
key.
As for the program itself, it's hard to read and thus it hides the said mbuf leak. Consider re-implementing it the following way:
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;
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]);
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]);
The key points here are as follows:
Factor out functions like fill_out_mbuf()
for the sake of code clarity;
Invoke rte_eth_tx_prepare()
before rte_eth_tx_burst()
as required by the RTE API contract;
Use rte_pktmbuf_alloc_bulk()
for improved efficacy;
If the mbuf batch has been sent only partially, don't start from scratch; instead, attempt to send remaining mbufs;
Do not retry sending infinitely; limit the number of retries.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.