"arp incomplete"问题排查
异常问题
在局域网中
网关 30.17.44.254
host A: 30.17.44.236/24
host B: 30.17.44.12/24
有时候,突然会发生 A 不能访问 B(无法ping或者ssh到B),但是,此时在B主机上,ping外部网络都是正常的(通过网关)。而A访问外部网络也正常。
由于A和B是同一个网段的两个主机,所以就推测到问题和ARP有关
排查
当异常发生时,在B主机上检查:
[root@devstack ~]# arp -an
? (30.17.44.254) at 58:69:6c:31:de:16 [ether] on wlp3s0
? (172.17.0.2) at 02:42:ac:11:00:02 [ether] on docker0
? (172.17.0.5) at 02:42:ac:11:00:05 [ether] on docker0
? (30.17.44.236) at <incomplete> [ether] on wlp3s0
? (172.17.0.6) at 02:42:ac:11:00:06 [ether] on docker0
? (172.17.0.9) at <incomplete> on docker0
? (172.17.0.8) at 02:42:ac:11:00:08 [ether] on docker0
? (192.168.122.11) at 52:54:00:82:87:0e [ether] on virbr0可见B主机上无法找到A主机30.17.44.236的ARP地址。
在RedHat的知识库有一篇"arp" or "ip neigh" showing hardware MAC address as INCOMPLETE提到了解决
推测是内核存在问题或者是某个内核设置存在问题,导致ARP表被刷新过期。具体原因我还需要再探索。
可以使用
ip neighbour显示MAC地址
[root@devstack ~]# ip neigh
30.17.44.254 dev wlp3s0 lladdr 58:69:6c:31:de:16 STALE
172.17.0.2 dev docker0 lladdr 02:42:ac:11:00:02 STALE
172.17.0.5 dev docker0 lladdr 02:42:ac:11:00:05 REACHABLE
30.17.44.236 dev wlp3s0 lladdr b8:e8:56:33:e4:8a REACHABLE
172.17.0.6 dev docker0 lladdr 02:42:ac:11:00:06 STALE
172.17.0.9 dev docker0 INCOMPLETE
172.17.0.8 dev docker0 lladdr 02:42:ac:11:00:08 STALE
192.168.122.11 dev virbr0 lladdr 52:54:00:82:87:0e STALESTALE 表示不新鲜的,即可能会过期(如果长时间没有数据通讯到30.17.44.254则这个ARP缓存会过期)。如何转换这个ARP状态呢?我们尝试ping 30.17.44.254,完成一个短暂的ping验证网络联通正常后,再次检查arp -an可以看到:
[root@devstack ~]# ip neigh
30.17.44.254 dev wlp3s0 lladdr 58:69:6c:31:de:16 DELAY
...可以看到这条ARP记录被延迟失效,而且,再次使用ip neighbour检查,可以看到这个目标地址ARP转变成了REACHABLE
[root@devstack ~]# ip neigh
30.17.44.254 dev wlp3s0 lladdr 58:69:6c:31:de:16 REACHABLE和ARP相关的内核参数cg_XXXX
cg_XXXX详细请参考Configuring ARP age timeout和2.1. Address Resolution Protocol (ARP)
ARP性能调整的参数位于 /proc/sys/net/ipv4/neigh/default 目录下,有:
gc_interval- 默认值30,表示30秒进行一次gcgc_stale_time- 默认值60。注意:路由缓存的垃圾回收时间就是这个值的5倍gc_thresh1gc_thresh2gc_thresh3
以上内核参数值尚未仔细研究,待查证
在neighbor缓存对象失效或只是被标记为stale/invalid是有细微区别的。介于base_reachable_time/2和3*base_reachable_time/2之间,则对象还会在缓存中,但是会被标记为STALE状态。可以通过ip -s neighbor show进行检查:
$ ip -s neighbor list
192.168.42.1 dev eth0 lladdr 00:25:90:7d:7e:cd ref 2 used 184/184/139 probes 4 STALE
192.168.10.2 dev eth0 lladdr 00:1c:23:cf:0b:6a ref 3 used 33/28/0 probes 1 REACHABLE
192.168.10.1 dev eth0 lladdr 00:17:c5:d8:90:a4 ref 219 used 275/4/121 probes 1 REACHABLE当出于STALE状态,如果ping这个地址,就会正确发送给00:25:90:7d:7e:cd数据包。一秒钟或者稍后,就通常会发送一个ARP请求"who has 192.168.42.1"以便能够更新它的缓存回到REACHABLE状态。但是,有时候内核会基于更高层协议反馈修改timeout值。这意味着,如果ping 192.168.42.1并且它答复,则内核可能并不会发送ARP请求因为它假定这个pong已经表明了ARP缓存值是正确的。如果这个对象是STALE状态,它也会被已经查看到的主动ARP相应更新。
临时的解决方法
强制刷新网络接口arp
参考Clear the arp cache on linux, really使用如下命令强制刷新arp
ip link set arp off dev wlp3s0
ip link set arp on dev wlp3s0重启网络接口
根据故障排查经验,通过简单的重启网络接口可以强制刷新arp
ifdown wlp3s0
ifup wlp3s0之后通常可以正常通讯。
设置静态ARP解析解决
临时解决的方法可以参考Linux下Mac地址绑定防范arp病毒攻击,编辑/etc/ethers添加
30.17.44.236 b8:e8:56:33:e4:8a然后执行arp -f命令刷新,再次使用arp -an就可以看到
? (30.17.44.236) at b8:e8:56:33:e4:8a [ether] on wlp3s0如果将ARP映射配置存放到其他文件,例如/etc/ip-mac,则通过-f参数指定读取文件,即执行arp -f /etc/ip-mac,也能实现相同效果。
如果不使用-f参数读取配置文件,也可以使用-s参数直接指定设置:
arp -s 30.17.44.236 b8:e8:56:33:e4:8a参考
Guide to IP Layer Network Administration with Linux - 所有有关ARP协议原理和排查案例请参考该手册的2.1. Address Resolution Protocol (ARP),非常详细的一份网络协议指南
Last updated
Was this helpful?