分段错误 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 出现分段错误?

python跟踪分段错误

带有 std::promise 的 C++11 分段错误

C++:当我添加看似无关的代码行时,分段错误消失了

为啥调用 glCreateShader 时这个 OpenGL 着色器分段错误?

什么是分段错误?