使用 DPDK 测量往返时间

Posted

技术标签:

【中文标题】使用 DPDK 测量往返时间【英文标题】:Measuring Round Trip Time using DPDK 【发布时间】:2021-06-01 07:13:14 【问题描述】:

我的系统是 CentOS 8,内核为:4.18.0-240.22.1.el8_3.x86_64,我使用的是 DPDK 20.11.1。内核:

我想以优化的方式计算往返时间,以便从机器 A 发送到机器 B 的数据包从机器 B 环回到 A 并测量时间。完成此操作后,机器 B 正在运行 DPDK 转发应用程序(如 testpmd 或 l2fwd/l3fwd)。

一种方法是使用 DPDK pktgen 应用程序 (https://pktgen-dpdk.readthedocs.io/en/latest/),但我找不到以这种方式计算往返时间的方法。虽然 ping 是另一种方式,但是当机器 B 从机器 A 接收到 ping 数据包时,它必须处理数据包然后响应机器 A,这会增加一些周期(这在我的情况下是不希望的)。

接受计算此时间的建议和方法。此外,比较基于 DPDK 的应用程序与非 DPDK 设置的 RTT(往返时间)的基准也会提供更好的比较。

编辑:有一种方法可以在 DPDK pktgen 中启用延迟。任何人都可以分享一些有关如何计算此延迟及其含义的信息(我在文档中找不到有关页面延迟的可靠信息。

【问题讨论】:

pktgen repo manager 已在 github 上回复了有关查询:github.com/pktgen/Pktgen-DPDK/issues/73 @AmmerUsman,我强烈建议您编辑您的问题以反映how to measure round trip time taken, rather than TX-RX latency from DUT? 的真实意图,这是因为您指的是DPDK latency stats/metric,但这是用于测量最小/最大/平均延迟之间的rx-tx 在同一个 DUT 上。 但正如 Keith 在 github 问题上所提到的,延迟统计显示的结果也可以称为往返时间。除非数据包被连接的设备环回,否则延迟统计信息也不会出现。 @AmmerUsman DPDK 延迟库是代表 TX-callback 和 RX-callback 之间差异的统计数据,不适用于您描述的用例。根据基思的解释指出Packet send out by traffic generator should sent timestamp on payload, receiver ap should forward to same port. then receiver app can measure difference between received timestamp and timestamp embedded in apcket.。为此,您需要将其发送回与您的设置图不匹配的同一端口。 您是否使用 1 个端口更改了设置?如果是,请更新github.com/pktgen/Pktgen-DPDK/issues/73 和这张票。因为它令人困惑 【参考方案1】:

这实际上取决于您要衡量的往返行程类型。考虑以下时间戳

  -> t1  -> send() -> NIC_A -> t2  --link--> t3  -> NIC_B -> recv() -> t4
host_A                                                              host_B
  <- t1' <- recv() <- NIC_A <- t2' <--link-- t3' <- NIC_B <- send() <- t4' 

你想测量t1' - t1吗?然后只需编写一个小型 DPDK 程序,在主机 A 上每次发送/接收函数调用之前/之后存储 TSC 值。(在主机 b 上运行转发应用程序。)另请参阅 rte_rdtsc_precise()rte_get_tsc_hz()将 TSC 增量转换为纳秒。

对于非 DPDK 程序,您可以通过 other means 读出 TSC 值/频率。根据您的分辨率需求,您也可以只调用 clock_gettime(CLOCK_REALTIME),其开销约为 18 ns。

这适用于通过rte_eth_tx_burst() 进行的单数据包传输和单数据包接收 - 这对于您的目标应用程序来说不一定是现实的。对于较大的突发,您必须在第一次传输之前和最后一次传输之后使用获取时间戳,然后计算平均增量。


时间戳t2, t3, t2', t3' 是由(更严重的)网卡提供的硬件传输/接收时间戳。

如果您想计算往返 t2' - t2,那么您首先需要调整 NIC 的时钟(例如使用 phc2ys),启用时间戳并获取这些时间戳。但是,AFAICS dpdk 通常不支持获取 TX 时间戳。

因此,当使用 SFP 收发器时,另一种方法是在 NIC_A 的 RX/TX 端安装无源 optical TAPs,并将监控端口连接到支持接收硬件时间戳的数据包捕获 NIC。通过这样的设置,计算t2' - t2 往返只需编写一个脚本,该脚本从您的 pcap 读取匹配数据包的时间戳并计算它们之间的增量。

【讨论】:

【参考方案2】:

通过接口发送和接收数据包延迟的理想方法是在机器 A NIC 端口上设置外部 Loopback 设备。这将确保发送的数据包在没有任何处理的情况下被接收回同一个 NIC。

下一个最佳选择是启用Internal Loopback,这将确保所需的数据包转换为 PCIe 有效负载和 DMA 到硬件数据包缓冲区。基于 PCIe 配置,数据包缓冲区将与 RX 描述符共享,从而导致发送数据包的 RX。但是对于这个需要一个网卡

    支持内部环回 并且可以抑制 Loopback 错误处理程序。

另一种方法是使用PCIe port to port cross connect。在 DPDK 中,我们可以为 core-A 上的 port-1 运行 RX_BURST,为 core-B 上的 port-2 运行 RX_BURST。这将确保几乎准确的往返时间。

注意:较新的硬件支持doorbell 机制,因此在 TX 和 RX 上,我们可以启用硬件向驱动程序/PMD 发送回调,然后可用于获取硬件辅助的 PTP 时间戳以实现纳秒级精度。

但在我的建议中使用外部(机器-B)是不可取的,因为

    根据传输介质的质量,延迟会有所不同 如果机器 B 必须配置为理想设置(几乎为 0 延迟) 即使物理配置相同,机器 A 和机器 B 也需要维护并在相同的热设置下运行,以实现正确的时钟。 Machine-A 和 Machine-B 都必须使用相同的 PTP grand master 来同步时钟。 如果使用 DPDK,请修改 PMD 或使用rte_eth_tx_buffer_flush 确保将数据包发送到 NIC

通过这些更改,可以创建一个虚拟 UDP 数据包,其中

前 8 个字节应携带来自机器 A (T1) 的 tx_burst 之前的实际 TX 时间。 第二个 8 字节由机器 B 在通过 rx_burst (2) 实际接收到 SW 中的数据包时添加。 第三个 8 字节由 Machine-B 在 tx_burst 完成 (T3) 时添加。 当通过 rx-burst (T4) 实际接收到数据包时,在 Machine-A 中找到第四个 8 字节

使用这些Round trip Time = (T4 - T1) - (T3 - T2),其中 T4 和 T1 给出来自机器 A 和 T3 的接收和传输时间,而 T2 给出处理开销。

注意:根据处理器和代,无变体 TSC 可用。这将确保刻度 rte_get_tsc_cycles 不会因频率和功率状态而变化。

[Edit-1] 如 cmets 所述

    @AmmerUsman,我强烈建议编辑您的问题以反映如何测量往返时间的真实意图,而不是 DUT 的 TX-RX 延迟?这是因为您指的是 DPDK 延迟统计/指标,但用于测量同一 DUT 上 Rx-Tx 之间的最小/最大/平均延迟。 DPDK 中的@AmmerUsman 延迟库是代表 TX-callback 和 RX-callback 之间差异的统计数据,不适用于您所描述的用例。根据 Keith 的解释,流量生成器发出的数据包应在有效负载上发送时间戳,接收应用程序应转发到同一端口。然后接收方应用程序可以测量接收到的时间戳和嵌入在数据包中的时间戳之间的差异。为此,您需要将其发送回与您的设置图不匹配的同一端口

【讨论】:

我会添加建议的更改。再次感谢您。

以上是关于使用 DPDK 测量往返时间的主要内容,如果未能解决你的问题,请参考以下文章

UWB芯片DW3000之双边双向测距法

使用UDP和TCP测量网络延迟

TCP/IP传输层协议实现 - TCP的超时与重传(lwip)

安装和使用Smokeping

如何使用 C 对 TCP 和 UDP 进行基准测试?

TCP中RTT的测量和RTO的计算