tc mirred 镜不到容器流量,因docker bridge模式下出向流量走veth+docker0网桥,未经过宿主机物理网卡qdisc;需在docker0用clsact ingress或veth主机端配置mirred,并确保目标设备up且同命名空间。

tc mirred 为什么镜不到容器里的流量
因为 tc 的 mirred 动作作用在内核 qdisc 层,而容器(尤其是 Docker 默认 bridge 模式)的网络路径里,出向流量往往绕过宿主机的物理网卡 qdisc,直接走 veth 对 + docker0 网桥转发,根本没机会被 tc 触发。
实操上得先确认流量路径:用 tcpdump -i docker0 和 tcpdump -i eth0 对比,如果只在 docker0 抓到包、eth0 没有对应出向包,说明流量压根没经过宿主机出口 qdisc —— 那在 eth0 上加 tc mirred 就是白忙。
- 优先在
docker0接口上挂tc,但注意:网桥接口默认不支持 egress qdisc,需启用echo 1 > /sys/class/net/docker0/bridge/stp或改用 clsact + ingress(更可靠) - 若必须镜像到物理网卡,可把容器改用
host网络模式,或通过veth主机端口(如vethXXXXX)绑tc,它比docker0更靠近容器出口 -
mirred的egress方向只能镜像本设备发出的包,不能镜入向;想镜双向,得分别在ingress(用 clsact)和egress各配一套
mirred action 的 target 设备必须是 up 状态且同命名空间
常见错误是镜像目标设成 lo 或一个还没 ip link set up 的 dummy 接口,结果 tc filter add ... action mirred egress redirect dev lo 看似成功,但实际无包到达 —— 内核会静默丢弃发往 down 状态设备的镜像包。
另外,容器网络常涉及 network namespace,mirred 的 dev 参数只认当前 namespace 下的设备名。比如你在宿主机想镜到容器内的 eth0,直接写 dev eth0 会失败,因为那个 eth0 不在宿主机 namespace 里。
- 用
ip link show确认目标设备状态为UP,且mtu足够(建议 ≥1500,避免分片干扰分析) - 跨 namespace 镜像要用
mirred+redirect到 veth 对的主机端,再靠 netns 路由转发,不能直写容器内设备名 - 目标设备最好专用(如
mirror0),避免复用业务接口,否则镜像流量可能触发防火墙规则或被其他工具误处理
clsact ingress 是唯一能镜入向流量的可靠方式
很多人试 tc qdisc add dev eth0 root ... 想镜入向包,失败是因为传统 qdisc 只支持 egress。真正能捕获入向原始包的,只有 clsact qdisc 的 ingress hook —— 它在进入协议栈前就截流,位置比 iptables INPUT 链还早。
但要注意:clsact 不是万能胶水,它不排队、不整形,纯做分类和动作,所以 mirred 必须搭配 clsact 使用,且只能挂 ingress 或 egress,不能混用。
- 加载方式:
tc qdisc add dev eth0 clsact,然后用tc filter add dev eth0 parent ffff: protocol ip ... action mirred egress redirect dev mirror0 -
ffff:是 ingress 的固定 handle,别写错;parent ffff:表示挂 ingress,parent :1才是 egress - ingress 镜像对性能影响比 egress 大,尤其高吞吐场景,建议加
flowid限速或只镜特定端口(如ip dport 80)
镜像流量进不了 tcpdump?检查 nf_hooks 和 offload
即使 tc mirred 配置正确,tcpdump -i mirror0 也可能收不到包,最常踩的两个坑是:网卡开启了 GRO/GSO/LRO 等卸载功能,导致镜像出来的包是“组装后”的大帧;或者包被 conntrack 提前标记为 INVALID,被 netfilter drop。
前者会让 tcpdump 解析失败(显示 malformed packet),后者则干脆没包——此时 cat /proc/net/nf_conntrack | grep INVALID 可验证。
- 关掉卸载:
ethtool -K mirror0 gro off gso off lro off,特别是gro,它是镜像流量乱码的头号元凶 - 临时绕过 conntrack:
iptables -t raw -I PREROUTING -i mirror0 -j NOTRACK,避免连接状态干扰 - 确认镜像设备没被其他 tc 规则二次处理,
tc filter show dev mirror0应为空,否则可能形成环路或丢包
复杂点在于,镜像本身不改变原路径,但一旦引入新设备和 netfilter 规则,就等于给诊断链路加了不可见跳点。越想看清流量,越要小心别让诊断工具自己成了故障源。










