一次veth丢包排查
date
slug
tags
summary
type
status
记一次有趣的排查bug日记:
问题
事情的起因是在进行网络实验时发现出现丢包的情况,实验的设置如下下图所示:
由一个Emulator负责接收veth包并转发到对应的veth(通过AF_XDP)。在进行iperf测试时,发现跑几秒钟网络带宽就变为0。之后两个节点就相互ping不通了。
排查
通过ifconfif观察到,在问题后,通过veth1向veth0投送包时总是被drop掉。
首先,我通过tcpdump,nettrace,xdp ebpf对veth0的包接收行为进行了观察,但都无法捕获到丢包的现象。怀疑可能在发送阶段包就丢了,因此为了能够观察veth的发送行为,复制了一份veth的代码,重新编译了一个“uveth”模块,如此便可以愉快地在veth的源码中打log。
构建内核模块的流程很丝滑,网上找了一份Makefile模版,把veth复制一下,改个设备名就可以直接编译了。
启动完uveth后有一个问题:如何创建相应的设备?
一般创建veth的方式是通过ip link创建,其内部使用了netlink与内核的进行通信创建。
为了避免手写netlink通信,看了下iproute的代码,发现只需要通过hack一下名称的方式就可以复用veth的所有创建逻辑。
之后就可以愉快地使用
ip link add .. type uveth ..
创建相应设备了。有了日志之后发现网络包果然是在veth发送包(veth0→veth1)时丢掉的,原因是在__dev_forward_skb中
is_skb_forwardable
判断失败,通过将skb的长度打印出来后,发现是长度超过了mtu。由于网络包是直接转自来自veth的网络包,所以理论上网络包不应该超过veth设置的mtu,所以我怀疑问题来自于emulator中某个环节对网络包的内容进行了污染。
通过在emulator每次发送之前打印网络包的长度,我发现传送数据长度都是符合要求的。那么错误的原因可能出现在其他地方,我观察到af_xdp发送包的元数据
FrameDesc
中有描述包大小的字段,通过比较该长度和实际的数据长度,果然这个字段会出现与实际数据不一致,超过mtu的情况。最终,我发现是因为
FrameDesc
在重新被分配时没有进行初始化,导致其长度可能是上一次的长度,因此再次使用FrameDesc
会使得长度会变成上一次的两倍,超过实际的数据长度。Loading...