段错误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]);
}

这里的重点如下:

  1. 为了代码清晰起见,分解出像 fill_out_mbuf() 这样的函数;
  2. 根据 RTE API 合同的要求,在 rte_eth_tx_burst() 之前调用 rte_eth_tx_prepare()
  3. 使用rte_pktmbuf_alloc_bulk()提高疗效;
  4. 如果mbuf批次只发送了一部分,不要从头开始;相反,尝试发送剩余的 mbuf;
  5. 不要无限重试发送;限制重试次数。