L3层Netfilter钩子中看不到VLAN标签的问题排查方法咨询
排查Linux网络栈入站skb->vlan_tci被修改的方案
运行时动态排查方法
- 用kprobe/ebpf定位字段修改点:可以用bpftrace快速捕获对
skb->vlan_tci的修改操作,以下命令会在__vlan_hwaccel_clear_tag(内核中负责清空vlan_tci的通用函数)被调用时打印完整内核调用栈:
如果命中直接就能看到是哪个函数发起的清空操作。如果没有命中,可以直接针对vlan_tci在skb结构体中的偏移设置写断点,逐步缩小修改发生的范围。bpftrace -e 'kprobe:__vlan_hwaccel_clear_tag { print(kstack); }' - 按执行顺序遍历已注册的处理钩子:rx_handler执行时机早于所有三层协议处理和Netfilter钩子,你可以先读取
/proc/net/ptype查看当前系统注册的所有三层协议处理函数,再通过lsmod排查加载的网络相关内核模块,重点排查优先级介于rx_handler和你注册的Netfilter钩子之间的处理逻辑。 - 开启内核网络tracepoint分段验证:可以用内核自带的
netif_receive_skb、ip_rcv等tracepoint逐段打印skb的vlan_tci值,也可以在你dump vlan_tci的两个点位之间加多个dump点,确认修改发生的具体区间。 - 排查vlan硬件卸载配置:执行
ethtool -k 你的网卡名查看vlan-offload相关配置是否开启,部分网卡驱动会在硬件层面处理vlan标签,和内核处理逻辑耦合时也可能出现vlan_tci被意外清空的问题。
源码路径排查方法
- 先理清入站skb的标准执行路径:rx_handler在
__netif_receive_skb_core函数中执行,后续处理流程依次为:rx_handler返回 -> 遍历ptype_base中注册的三层协议处理函数 -> 匹配到对应协议后进入协议层接收函数 -> 执行Netfilter对应协议的PREROUTING钩子。你遇到的vlan_tci修改一定发生在rx_handler和你注册的Netfilter钩子之间的这段流程。 - 优先排查常见的vlan_tci修改逻辑:最常见的触发场景为8021q模块的标准处理:如果你的系统创建了对应vlan id的子接口,8021q模块注册的ETH_P_8021Q协议处理函数会先于IP层处理执行,该函数会提取
skb->vlan_tci中的信息匹配对应VLAN子接口,之后清空skb->vlan_tci再把报文转到VLAN子接口的接收流程,此时后续Netfilter钩子拿到的vlan_tci就是0,这属于内核的正常处理逻辑。除此之外桥接模块的vlan过滤功能、第三方网络内核模块的自定义处理也会修改该字段。 - 全量搜索内核源码中修改vlan_tci的位置:在内核源码根目录执行以下命令筛选所有修改vlan_tci的逻辑,再结合你的内核版本对应代码流程逐一排查:
grep -rn "vlan_tci\|__vlan_hwaccel_clear_tag\|skb_vlan_tag_set" net/
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

