linux DPDK rte_mbuf数据包未正确释放

dzjeubhm  于 2023-04-05  发布在  Linux
关注(0)|答案(1)|浏览(450)

靶区;DR

我使用DPDK以高吞吐量接收UDP数据包。当我尝试释放rte_mbufs时(UDP数据包)在一个没有运行在DPDK lcore上的线程上使用rte_pktmbuf_free_bulk(),实际上没有释放rte_mbuf,这导致无法接收超过4096个数据包。我是否需要将所有逻辑移动到运行在lcore上的线程上,还是我还能做些什么来让这一切继续下去

DPDK设置注意事项

我是DPDK的新手,继承了代码的初始化部分,这部分代码太长了,无法在这里包含。我不确定关于配置的哪些具体细节可能是重要的或相关的,但如果有人对DPDK设置有具体问题,我很乐意补充这篇文章。然而,我已经包含了主要的RX循环代码及其描述,如下。

代码说明:

  • 主RX循环包含在一个名为_receive_packets()的方法中,该方法只能使用rte_eal_remote_launch()调用,这就是为什么参数是用空指针传递的。
  • thread_arg是我定义的一个结构体,用于在使用rte_eal_remote_launch()调用此函数时传递所需的所有参数。
  • 由于一些可能与这个问题无关的原因,_receive_packets()必须是一个静态类方法,这就是为什么你会看到奇怪的input_arg->ds_instance表示法。
  • input_arg->ds_instance->m_active在应用程序关闭时变为false。
  • BURST_SIZE是512
  • IO_Job是一个结构体,我使用它来将数据包发送到另一个(非lcore)线程,并使用rte_ring进行处理和流式传输到文件。使作业出队的代码在数据包上调用rte_eal_remote_launch()并删除在_receive_packets()中创建的任何对象,因此看起来可能存在内存泄漏,但实际上并没有。
  • input_arg->ds_instance->enqueue_io_job()是一个helper函数,它简单地将一个作业排队到上面提到的rte_ring

密码

void Data_Streamer::_receive_packets(void* arg) 
{
    thread_arg* input_arg = (thread_arg*) arg;

    uint16_t port_id = input_arg->port_id;
    uint16_t queue_id = input_arg->queue_id;
    long long bytes_recorded = 0;

    
    while (input_arg->ds_instance->m_active)
    {
        // If BURST_SIZE packets not ready, then do nothing this cycle
        if (rte_eth_rx_queue_count(port_id, queue_id) < BURST_SIZE) continue;
        
        // Once data is available, get packets as burst
        rte_mbuf** packets = new rte_mbuf*[BURST_SIZE];
        const uint16_t got_num_packets = rte_eth_rx_burst(port_id, queue_id, packets, BURST_SIZE);

        // Package packets into job and enqueue the job
        if (got_num_packets)
        {
            IO_Job* job = new IO_Job;
            job->byte_offset = bytes_recorded;
            job->packets = packets;
            job->num_packets = got_num_packets;

            input_arg->ds_instance->enqueue_io_job(job);
        }
    }
}

故障排除注意事项

  • 当我修改代码,使rte_pktmbuf_free_bulk()在作业入队后立即从_receive_packets()调用时,数据包将按预期释放,但是,这会创建一个争用条件,其中数据包中的数据可能会在非lcore线程上处理之前被新的数据包数据覆盖。
  • 我尝试进一步修改代码,以便将数据包缓存在_receive_packets()中,直到在非lcore线程上运行的进程发送一个通知,表明它已使用数据。在这种情况下,行为与在非lcore线程中释放数据包时的行为类似-数据包不被释放。(就好像只查看非lcore线程中的数据会阻止它被正确释放一样,即使从lcore线程中释放也是如此。
  • 如果我重复上面的尝试,但是使用rte_pktmbuf_mtod()提取我实际想要读取的缓冲区的地址,这样我就不会向非lcore线程发送指向packets对象的指针,它仍然没有正确地释放rte_mbuf
hi3rlvi2

hi3rlvi21#

解决方案是在DPDK lcore线程上执行所有使用mbuf的代码。没有必要在所有使用rte_pktmbuf_free()的线程上释放数据包,正如我之前在评论中建议的那样。如果所有线程都在DPDK lcore上运行,那么只需要对rte_pktmbuf_free()进行一次调用。
我以为我可以在没有运行在DPDK lcore上的线程中从mbufs中阅读数据,但显然,如果读取是在运行在DPDK lcore上的线程上执行的,即使读取操作也是线程安全的。

相关问题