Networking 使用DPDK将数据包数据写入文件会导致丢包(即使在通信速度低于200 Mbps的情况下)。瓶颈是什么?

Networking 使用DPDK将数据包数据写入文件会导致丢包(即使在通信速度低于200 Mbps的情况下)。瓶颈是什么?,networking,pcap,dpdk,Networking,Pcap,Dpdk,我想用DPDK以大于10 Gbps的线路速率以PCAP格式捕获并存储来自1个单端口的100%流量,并将其延长一段时间。我使用的NIC是Mellanox Connectx-5,系统运行的是Centos 7.4。存储文件系统是XFS。我有超过100个内核要利用,并且在硬件Raid 0配置中有非常大的存储容量。我已经使用多个进程(1-10)测试了该存储,这些进程可以以1GB/s-~8GB/s的综合速率对其进行写入。我尝试了几个测试来实现线速率数据包存储,但在流量速度从150 Mbps到4000 Mbp

我想用DPDK以大于10 Gbps的线路速率以PCAP格式捕获并存储来自1个单端口的100%流量,并将其延长一段时间。我使用的NIC是Mellanox Connectx-5,系统运行的是Centos 7.4。存储文件系统是XFS。我有超过100个内核要利用,并且在硬件Raid 0配置中有非常大的存储容量。我已经使用多个进程(1-10)测试了该存储,这些进程可以以1GB/s-~8GB/s的综合速率对其进行写入。我尝试了几个测试来实现线速率数据包存储,但在流量速度从150 Mbps到4000 Mbps的情况下,似乎总是至少有0.2%-20%的数据包丢失

我做的第一个测试是使用DPDK的testpmd和pdump。这不是一个好的解决方案,因为在硬件接口上丢弃的数据包占很大比例

然后,我尝试了一个修改过的基本转发应用程序,它不是转发数据包,而是使用标准PCAP头和fwrite写入单个数据包。当达到阈值(100万个数据包)时,pcap文件将增加。通过这些测试,我能够捕获并存储0%滴落的最佳吞吐量为100 Mbps,这对于我的需求来说是难以置信的慢

然后,我尝试了之前相同的测试,但使用了一个mmap'd文件和rte_memcpy,以及一个单独的线程,该线程将使用生产者/消费者逻辑准备好许多mmap'd文件。对于高吞吐速度下的短突发,这似乎效果很好,但随着时间的推移,性能会下降,并且并不比简单地使用fwrite好多少

然后,我尝试了DPDK的环形库将数据包分发给多个线程,每个线程将使用fwrite为自己的文件处理写操作。我能够以0%的速率捕获和存储流量的最佳速率是1000 Mbps左右,10个内核接收和写入不同的文件。超过10个内核,性能似乎会下降,并且下降会增加。我还发现,通过这种设置,我能够捕获所有的数据包,但是丢弃的数据包只是被转移,而不是在接口处,而是在数据包排队/退队等待写入的环处。下面是执行写入操作的代码段

static inline int
write_pkt(struct rte_mbuf *mbuf, FILE* out_file)
{
  uint8_t *pkt;
  uint32_t pkt_len = mbuf->pkt_len;
  struct pkt_header *pcap_hdr = (struct pkt_header *)
            rte_pktmbuf_prepend(mbuf,
                (uint16_t)sizeof(struct pkt_header));
  pcap_hdr->pkt_length = pkt_len;
  pcap_hdr->pkt_length_wire = pcap_hdr->pkt_length;
  pkt = rte_pktmbuf_mtod(mbuf, uint8_t *);
  fwrite(pkt, 1, pkt_len+pcap_header_size, out_file);
  return 0;
}

static int
do_packet_write(uint8_t in_client, FILE* outFile){
    int i;
    struct client   *cl_in = &clients[in_client];

    struct rte_mbuf *pkts_burst[PACKET_READ_SIZE];
    const uint16_t nb_rx = rte_ring_dequeue_burst(cl_in->rx_q, \
                                                        (void **)pkts_burst, PACKET_READ_SIZE, NULL);
    if (nb_rx == 0){
        return 0;
    }
    captured[in_client] += nb_rx;

    for (i = 0; i < nb_rx; i++){
        write_pkt(pkts_burst[i], outFile);
        rte_pktmbuf_free(pkts_burst[i]);
    }
    return (int)nb_rx;
}
静态内联int
write_pkt(结构rte_mbuf*mbuf,文件*out_文件)
{
uint8_t*pkt;
uint32_t pkt_len=mbuf->pkt_len;
结构pkt_头*pcap_hdr=(结构pkt_头*)
rte_pktmbuf_预装(mbuf,
(uint16_t)sizeof(struct pkt_header));
pcap_hdr->pkt_长度=pkt_长度;
pcap\U hdr->pkt\U长度\U线=pcap\U hdr->pkt\U长度;
pkt=rte_pktmbuf_mtod(mbuf,uint8_t*);
fwrite(pkt,1,pkt_len+pcap_头大小,out_文件);
返回0;
}
静态整数
数据包写入(uint8输入客户端,文件*输出文件){
int i;
结构客户端*cl_-in=&clients[in_-client];
结构rte_mbuf*pkts_突发[数据包读取大小];
const uint16\u t nb\u rx=rte\u ring\u dequeue\u burst(cl\u in->rx\u q\
(void**)pkts_突发,数据包_读取_大小,NULL);
如果(nb_rx==0){
返回0;
}
捕获的[in_client]+=nb_rx;
对于(i=0;i
我的目标是以50000 Mbps的速率达到0%的数据包丢失率,而我离这还很远。处理写操作的瓶颈是什么?我怎样才能把它修好,这样就不会滴水了


我还尝试了其他一些改进来提高性能,比如使用数据包读取大小(8-64),增加1GB的hugepages数,将数据包复制到大缓冲区,然后写入缓冲区,所有这些似乎都没有帮助。使用SETVBUF增加vbuf大小。在接口RX内核和写入内核之间添加一层工作线程,以预先发送PCAP头。我真的非常想更深入地理解这个问题

我没有使用过
DPDK
,但我必须使用write vs mmap和
PF_packet
来制作一款生产级的商业产品,它与您尝试的产品非常相似[尽管数据速率较低,但我必须进行大量测量以验证没有数据包丢失]。我(最终)会尝试发布一个带有一些建议的答案,但首先了解更多的事情会有所帮助。
数据包读取大小的值是多少?
getsockopt(fd、SOL\u SOCKET、SO\u RCVBUF)的值是多少?当您使用
mmap
进行写入时,是否使用了
madvise
?如果您对输入进行了虚拟加载(例如,伪造
rte_ring_dequeue_burst
以立即提供数据),可能会限制到最大预期输入速率,持续写入速率是多少?我有一个称为
clock\u gettime(clock\u MONOTONIC,…)
的时间戳/基准例程,并对我的代码进行检测,以便它为对您有意义的任何“事件”(例如EVT\u PKT\u到达、EVT\u PKT\u排队等待写入、EVT\u PKT\u在写入线程中退出队列)保留内存中的环形队列。如果我的代码检测到异常,它将强制转储事件[或从ctrl-c]。感谢您的回复和建议。为了回答您的问题,数据包读取大小目前为32。我实际上不使用getsockopt来接收数据包,DPDK提供了这些接口特定的驱动程序来直接从硬件队列接收数据包并绕过内核。我不熟悉madvise,但它看起来是一个在我的情况下使用的好工具。我不确定虚拟加载的持续写入速率,我将尝试下一步。Dpdk-pdump已增强,可以使用19.08及更高版本的多线程。因此,基于带有默认4RX线程的测试pdump用例,您至少重定向4个pcap文件。但是任何使用fwrite的系统调用都会导致开销。您是否可以对多个pdump线程而不是所有rx队列的单个线程尝试相同的测试。您还可以增强dpdk pdump以仅捕获头并尝试使用mmap WRITE