问题现象

  • 服务器(Ubuntu,网卡 ens2f0)配置 netplan 静态 IP 后,无法 ping 通网关 192.168.1.1
  • 路由表正常:default via 192.168.1.1 dev ens2f0 proto static
  • 同网段、同交换机的其他设备可以正常 ping 通网关

初始 netplan 配置:

network:
  version: 2
  ethernets:
    ens2f0:
      addresses:
        - 192.168.1.77/24
      nameservers:
        addresses:
          - 211.136.192.6
          - 120.196.165.24
      routes:
        - to: default
          via: 192.168.1.1

排查过程

第一阶段:排除基础链路问题

ip link show ens2f0        # 网卡 UP,链路正常
ip neigh show dev ens2f0   # 网关 ARP 为 REACHABLE

结论:二层正常,网关在线,ARP 解析正常。

第二阶段:用 tcpdump 定位"包到哪了"

tcpdump -ni ens2f0 icmp

关键现象:echo request 正常发出,网关的 echo reply已经到达网卡,但 ping 仍显示 100% 丢包。

知识点:tcpdump 抓取发生在内核 netfilter 之前,能看到包不代表包能交给应用。说明回包在"到达网卡"和"交给 ping 进程"之间被丢弃。

第三阶段:逐项排除内核丢包嫌疑

检查项命令结果
防火墙iptables -L INPUT -n -v策略 ACCEPT,无规则
nftablesnft list ruleset空
反向路径校验sysctl net.ipv4.conf.*.rp_filter宽松模式(2),排除
XDP/eBPFbpftool net list无挂载程序
tc 过滤器tc filter show dev ens2f0 ingress/egress无
驱动丢包ip -s link / ethtool -Sdropped 只涨 1,可忽略

结论:防火墙、协议栈、驱动全部干净。

第四阶段:锁定真凶——MAC 地址分析

tcpdump -eni ens2f0 icmp    # -e 显示 MAC 地址

抓包结果:

e8:61:1f:21:3c:c2 > 00:10:18:5d:b6:f8 ... 192.168.1.77 > 192.168.1.1: echo request
00:10:18:5d:b6:f8 > 00:26:b9:50:1a:81 ... 192.168.1.1 > 192.168.1.77: echo reply
                    ^^^^^^^^^^^^^^^^^^

回包的目的 MAC 是 00:26:b9:50:1a:81,而本机 MAC 是 e8:61:1f:21:3c:c2——回包发给了别人。

根因 #1:IP 地址冲突 网络中另有一台设备(MAC 00:26:b9:50:1a:81)也配置了 192.168.1.77,网关 ARP 表记住了它的 MAC。tcpdump 因混杂模式能看到这些包,正常模式下网卡按目的 MAC 过滤,ping 永远收不到。此前 ARP 时好时坏、现象瞬态,正是两个 MAC 在网关 ARP 表中互相顶替的表现。


经验总结

核心排查套路

"ping 不通但 tcpdump 能看到回包" → 直接 tcpdump -eni <网卡> icmp,看回包目的 MAC 是谁。

此类问题常见原因只有三种:

  1. IP 冲突 —— 回包发给了另一台同名设备(本案)
  2. ARP 绑定错误 —— 静态条目写错 MAC(本案第二坑)
  3. VLAN/策略路由 —— 回包从别的路径走

可跳过的弯路

防火墙、rp_filter、XDP、驱动丢包这些都可以先放一放——先用 -e 看 MAC,一分钟定位方向。

其他建议

  • 做 ARP/MAC 绑定时,直接从 ip link show 复制,避免手敲;优先考虑 DHCP 静态租约
  • 在网关/DHCP 上对关键设备做 IP-MAC 绑定 + DHCP Snooping,防止 IP 冲突复发

时间线回顾

步骤动作结论
1查链路/ARP二层正常
2tcpdump 抓包回包到达网卡但 ping 收不到
3查防火墙/rp_filter/XDP/驱动全部排除
4tcpdump -e看 MAC发现回包发给别的 MAC → IP 冲突
5修正绑定✅ 恢复

icmp数据包为什么mac地址不对,主机还能收到,并且被tcpdump抓到?

这个问题的答案就是整个案件的"最后一块拼图"——因为 tcpdump 工作时网卡处于混杂模式(Promiscuous Mode),此时网卡不再按目的 MAC 过滤,所有帧照单全收。但这并不等于主机"收到了"这个包——要分两层来看:

1. 正常模式 vs 混杂模式

正常模式下,网卡硬件会做目的 MAC 过滤,只有三类帧会被接收:

  • 目的 MAC = 自己网卡 MAC
  • 广播帧(ff:ff:ff:ff:ff:ff)
  • 自己订阅的组播帧

目的 MAC 是别人的帧在网卡硬件层就被丢掉,根本进不了系统,也不会出现在任何统计里。

混杂模式下(tcpdump 默认会开启,你的 dmesg 里就有证据):

igb 0000:0a:00.0 ens2f0: entered promiscuous mode

网卡关闭 MAC 过滤,线上经过的帧全部收进来。这是 tcpdump 能"看到"那个错误 MAC 回包的唯一原因。可以用 ip link show ens2f0 看到 PROMISC 标志,或加 -p 参数让 tcpdump 不开混杂模式对比验证。

2. "tcpdump 抓到" ≠ "主机收到"

帧进入内核后有两条路径:

网卡 → 驱动 → ┬─→ AF_PACKET 套接字(tcpdump)      ← 混杂模式下什么帧都给
              └─→ 协议栈(IP → ICMP → ping)        ← 还要再过 MAC 检查这一关

tcpdump 挂在 AF_PACKET 上,位置在协议栈之前,所以协议栈收不到的包它照样能抓。

而错误的回包(目的 MAC 08:61:1f:...)在协议栈入口还要再做一次目的 MAC 校验——不匹配,直接丢弃,永远到不了 ICMP 层。这就完美解释了本案的核心矛盾:

tcpdump 看得见回包,ping 却 100% 丢包 —— 包只到了 tcpdump 这一层,没到 ping 那一层。

3. 顺带解释:包为什么会流到这台服务器的端口上

这是交换式网络,交换机应该只把帧转发到目的 MAC 对应的端口。回包目的 MAC 08:61:1f:21:3c:c2 是绑错的人造地址,交换机 MAC 表里学不到这个地址,于是触发"未知单播洪泛"(Unknown Unicast Flooding)——从除入端口外的所有端口发一份。你的服务器端口正好收到一份,混杂模式下的 tcpdump 就抓到了。

如果那个假 MAC 恰好被交换机学到了(比如某台机器随机生成过),你连 tcpdump 都看不到回包,排查会更迷惑。

一句话总结

正常模式混杂模式(tcpdump)
别人的 MAC 帧网卡硬件直接丢收进来给 tcpdump 看,但协议栈照样丢

所以 tcpdump 抓到的包是"旁观者视角",不代表主机真正接收了它——本案正是利用这一点,用 tcpdump -e 对比"回包目的 MAC"和"本网卡 MAC",一分钟定位了 IP 冲突和绑定错误。