我有一个奇怪的掉落问题,要理解我的问题,最好的方法是看一下这个简单的代码段:

while( 1 )
{
    if( config->running == false ) {
        break;
    }
    num_of_pkt = rte_eth_rx_burst( config->port_id,
                                   config->queue_idx,
                                   buffers,
                                   MAX_BURST_DEQ_SIZE);
    if( unlikely( num_of_pkt == MAX_BURST_DEQ_SIZE ) ) {
        rx_ring_full = true; //probably not the best name
    }

    if( likely( num_of_pkt > 0 ) )
    {
        pk_captured += num_of_pkt;

        num_of_enq_pkt = rte_ring_sp_enqueue_bulk(config->incoming_pkts_ring,
                                               (void*)buffers,
                                               num_of_pkt,
                                               &rx_ring_free_space);
        //if num_of_enq_pkt == 0 free the mbufs..
     }
}

此循环正在从设备中检索数据包,并将其推入队列以供另一个lcore进一步处理。

当我用Mellanox卡运行测试时,以2.5M p / s发送20M(20878300)数据包时,循环似乎丢失了一些数据包,而pk_captured始终类似于19M或类似数据。

rx_ring_full永远不会为真,这意味着num_of_pkt总是
现在,如果从该片段中删除了rte_ring_sp_enqueue_bulk调用(并确保释放所有的mbuf),则pk_captured始终等于我发送至NIC的数据包数量。

因此,似乎(但我无法解决这个想法)rte_ring_sp_enqueue_bulk有点太慢,并且在一次调用rte_eth_rx_burst与另一次调用之间,由于NIC上的满环而导致丢包,但是,为什么num_of_pkt(来自rte_eth_rx_burst)总是小于好像总是有足够的空间容纳MAX_BURST_DEQ_SIZE(小得多)?

请注意,MAX_BURST_DEQ_SIZE为512。

编辑1:

也许这些信息可能会有所帮助:丢弃似乎也可以通过rte_eth_stats_get看到,或更准确地说,没有丢弃被报告(忽略且错误数为0),但是ipackets的值等于我的计数器pk_captured(丢失的数据包刚刚消失了吗? ?)

编辑2:

根据ethtools,rx_crc_errors_phy为零,并且所有数据包都在PHY级别接收(rx_packets_phy用正确数量的已传输数据包更新)。

来自rte_eth_stats的rx_nombuf的值似乎包含废纸((这是来自我们测试应用程序的打印内容):

OUT(4):端口1统计信息:ipkt:19439285,opkt:0,ierr:0,oerr:0,imiss:0,rxnobuf:2061021195718

对于2000万个数据包的传输,您可以看到rxnobuf是垃圾,或者它具有我不理解的含义。日志由以下人员生成:
  log("Port %"PRIu8" stats: ipkt:%"PRIu64",opkt:%"PRIu64",ierr:%"PRIu64",oerr:%"PRIu64",imiss:%"PRIu64", rxnobuf:%"PRIu64,
        config->port_id,
        stats.ipackets, stats.opackets,
        stats.ierrors, stats.oerrors,
        stats.imissed, stats.rx_nombuf);

统计信息来自rte_eth_stats_get。

数据包不是即时生成的,而是从现有的PCAP重放的。

编辑3

在回答了Adriy的问题(​​谢谢!)之后,我包括了Mellanox卡的xstats输出,同时使用较小的数据包集再现了相同的问题,我可以看到rx_mbuf_allocation_errors得到了更新,但似乎包含垃圾:
OUT(4): rx_good_packets = 8094164
OUT(4): tx_good_packets = 0
OUT(4): rx_good_bytes = 4211543077
OUT(4): tx_good_bytes = 0
OUT(4): rx_missed_errors = 0
OUT(4): rx_errors = 0
OUT(4): tx_errors = 0
OUT(4): rx_mbuf_allocation_errors = 146536495542

这些计数器似乎也很有趣:
OUT(4): tx_errors_phy = 0
OUT(4): rx_out_of_buffer = 257156
OUT(4): tx_packets_phy = 9373
OUT(4): rx_packets_phy = 8351320

其中rx_packets_phy是我一直发送的确切数据包数量,然后将rx_out_of_buffer与rx_good_packets求和就得出了确切的数量。因此,似乎mbuf耗尽了,一些数据包被丢弃了。

我对原始代码进行了调整,现在使用link从RX环上复制了mbuf,它们立即释放了内存,另一个lcore对该副本进行了进一步的处理。但这并不能解决问题,事实证明,要解决该问题,我必须禁用数据包处理并释放数据包副本(在另一个lcore上),这没有任何意义。

好吧,将做更多的调查,但是至少rx_mbuf_allocation_errors似乎需要在这里修复。

最佳答案

我猜想,调试rx_nombuf计数器是一种方法。它可能看起来像是垃圾,但是实际上,此计数器不反映丢弃的数据包的数量(像ierrorsimissed一样),而是反映失败的RX尝试次数。

这是MLX5 PMD的片段:

uint16_t
mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
{
    [...]
    while (pkts_n) {
        [...]
        rep = rte_mbuf_raw_alloc(rxq->mp);
        if (unlikely(rep == NULL)) {
            ++rxq->stats.rx_nombuf;
            if (!pkt) {
                /*
                 * no buffers before we even started,
                 * bail out silently.
                 */
                break;

因此,该问题的可能情况如下:
  • RX队列中有一个数据包。
  • 相应的内存池中没有缓冲区。
  • 应用程序轮询新数据包,即循环调用:num_of_pkt = rte_eth_rx_burst(...)
  • 每次我们调用rte_eth_rx_burst()时,rx_nombuf计数器都会增加。

  • 也请看看rte_eth_xstats_get()。对于MLX5 PMD,有一个硬件rx_out_of_buffer计数器,它可以证实这一理论。

    关于network-programming - 即使rte_eth_rx_burst没有返回完整的突发,丢弃的数据包,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49474567/

    10-14 15:03
    查看更多