在 tcpdump 记录中看不到 Tc qdisc 延迟

Jen*_*aKh 4 networking tcpdump tc wireshark delay

我有两个用 veth-pair 连接的 linux 容器。在一个容器的 veth 接口上,我设置了 tc qdisc netem 延迟并将流量从它发送到另一个容器。如果我使用 tcpdump/wireshark 观察双方的流量,可以看到发送方和接收方的同一数据包的时间戳不会因选定的延迟而有所不同。

我想更详细地了解在哪一点 libpcap 将时间戳放入与 tc qdisc 对应的出口流量。我在互联网上搜索了一个方案/图片,但没有找到。我发现了这个话题(wireshark packet capture point),但它建议通过再增加一个容器/接口来引入间接。在我的情况下,这不是可能的解决方案。有没有办法解决这个问题,而不是引入额外的中间接口(即不改变拓扑),而只能通过在已经给定的 veth-interface 进行记录,但以这种方式可以看到延迟?

更新:

我太快了,所以误会了。我的解决方案(与@AB 答案的第一个变体相同)和@AB 的 IFB 解决方案(我已经检查过)都不能解决我的问题。问题是a1-eth0拓扑中发送方接口的传输队列溢出:

[a1-br0 ---3Gbps---a1-eth0]---100Mbps---r1---100Mbps---r2
Run Code Online (Sandbox Code Playgroud)

我太快了,只检查了a1-eth0和路由器之间链接的延迟 10 毫秒r1。今天我试图提高延迟:100 毫秒、200 毫秒,结果(我得到的每个数据包延迟和速率图)对于上面的拓扑和正常拓扑开始不同:

[a1-eth0]---100Mbps---r1---100Mbps---r2
Run Code Online (Sandbox Code Playgroud)

所以不,当然,为了准确测试,我不能有额外的链接:Linux 网桥、这个 IFB 或任何其他第三方系统都没有引入。我测试拥塞控制方案。我想在特定的拓扑结构中做到这一点。而且我不能仅仅为了绘图而改变拓扑——我的意思是如果我的速率和延迟结果/绘图同时发生变化。

更新 2:

所以看起来已经找到了解决方案,如下所示(NFLOG 解决方案)。

更新 3:

这里描述了 NFLOG 解决方案的一些缺点(大链路层标头和具有零负载的出口 TCP 数据包的错误 TCP 校验和),并提出了一个更好的解决方案,NFQUEUE 没有任何这些问题:零长度出口数据包的 TCP 校验和错误(用 iptables 捕获)。但是,对于我的任务(拥塞控制方案的测试),NFLOG 和 NFQUEUE 都不适合。正如同一个链接所解释的那样,当从内核的 iptables 捕获数据包时,发送速率会受到限制(这就是我的理解)。因此,当您通过从接口捕获(即,定期)在发件人处记录时,您会得到 2 GB 的转储,而如果您通过从 iptables 捕获而在发送者处记录,则会得到 1 GB 的转储。大致说来。

更新 4:

最后,在我的项目中,我使用了我自己的回答中描述的 Linux 桥接解决方案。

A.B*_*A.B 5

根据Netfilter 和 General Networking原理图中的数据包流程,tcpdump在egress ( qdisc ) 之后捕获 ( AF_PACKET )。因此,您在 tcpdump 中看不到延迟是正常的:延迟在初始捕获时已经存在。

您必须提前一步捕获它,因此涉及第三个系统:

S1: system1, 在传出接口
R: 路由器上运行 tcpdump (或网桥, 在您方便时, 这不会改变), 运行 qdisc netem
S2: system2, 在传入接口上运行 tcpdump

 __________________     ________________     __________________
|                  |   |                |   |                  |
| (S1) -- tcpdump -+---+- (R) -- netem -+---+- tcpdump -- (S2) |
|__________________|   |________________|   |__________________|
Run Code Online (Sandbox Code Playgroud)

这意味着涉及3 个网络堆栈,它们是真实的、虚拟机、网络命名空间(包括ip netns、LXC 等)


或者,也可以通过使用带有镜像流量的IFB接口来欺骗和移动路由器(或网桥)上的每个特殊设置:允许通过一个技巧(专用于这种情况)插入 netem sort-of-after ingress 而不是 on出口:

 _______     ______________________________________________     _______
|       |   |                                              |   |       |         
| (S1) -+---+- tcpdump -- ifb0 -- netem -- (R) -- tcpdump -+---+- (S2) |
|_______|   |______________________________________________|   |_______|
Run Code Online (Sandbox Code Playgroud)

tc mirred联机帮助页中有一个基本的 IFB 用法示例:

使用 ifb 接口,可以通过 sfq 实例发送入口流量:

# modprobe ifb
# ip link set ifb0 up
# tc qdisc add dev ifb0 root sfq
# tc qdisc add dev eth0 handle ffff: ingress
# tc filter add dev eth0 parent ffff: u32 \
  match u32 0 0 \
  action mirred egress redirect dev ifb0
Run Code Online (Sandbox Code Playgroud)

只需在ifb0上使用netem而不是 sfq (并且在非初始网络命名空间中,ip link add name ifbX type ifb工作正常,没有 modprobe)。

这仍然需要 3 个网络堆栈才能正常工作。


使用NFLOG

从JenyaKh的建议后,事实证明这是可以捕捉到一个包tcpdump的之前出口(队列规定因而前),然后在出口处(后队列规定):使用iptables的(或nftables),以全包登录到网络链路日志基础设施和还在读他们的tcpdump,然后再次使用tcpdump的出接口上。这只需要在 S1 上进行设置(并且不再需要路由器/网桥)。

因此,对于 S1上的iptables,类似于:

iptables -A OUTPUT -o eth0 -j NFLOG --nflog-group 1
Run Code Online (Sandbox Code Playgroud)

可能应该添加特定的过滤器以匹配完成的测试,因为tcpdump过滤器仅限于 nflog 接口(wireshark 应该更好地处理它)。

如果需要答案捕获(此处在不同的组中完成,因此需要额外的tcpdump):

iptables -A INPUT -i eth0 -j NFLOG --nflog-group 2
Run Code Online (Sandbox Code Playgroud)

根据需要,也可以将它们移动到raw/OUTPUTraw/PREROUTING

使用tcpdump

# tcpdump -i nflog:1 -n -tt ...
Run Code Online (Sandbox Code Playgroud)

如果使用不同的组 (= 2) 进行输入:

# tcpdump -i nflog:2 -n -tt ...
Run Code Online (Sandbox Code Playgroud)

与此同时,像往常一样:

# tcpdump -i eth0 -n -tt ...
Run Code Online (Sandbox Code Playgroud)