root@openwrt:~# ip -s -s -4 neigh show dev lan
10.64.42.121 lladdr b8:20:00:00:00:00 used 6387/6341/6313 probes 1 STALE
10.64.42.157 lladdr b8:20:00:00:00:00 used 24/813/19 probes 1 STALE
10.64.42.12 used 29066/30229/29063 probes 6 FAILED
10.64.42.1 lladdr e8:00:00:00:00:00 ref 1 used 10/5/5 probes 1 REACHABLE
root@openwrt:~# cat /proc/sys/net/ipv4/neigh/default/gc_interval
30
root@openwrt:~# cat /proc/sys/net/ipv4/neigh/default/gc_stale_time
60
root@openwrt:~# cat /proc/sys/net/ipv4/neigh/lan/gc_stale_time
60
局域网 (b8:20:00:00:00:00) 中的一台主机的 IP 地址为 10.64.42.121。此 IP 现在无效,该主机的 IP 现在为 10.64.42.157(新的 DHCP 租约)。
我尝试弄清楚旧的 arp 缓存条目何时会将状态更改为 FAILED(只要没有人尝试联系 IP)。
上次确认该条目的时间是 6341 秒前(1 小时 45 分钟前)。这超过了 60 秒。为什么该条目仍处于 STALE 状态,什么时候会变为 FAILED 状态(或被删除)(如果没有人尝试使用该条目)?
答案1
gc_stale_time
是调整以从 ARP 表中驱逐 STALE 条目的正确参数。但还有更多:
ARP 垃圾收集定期运行neigh_periodic_work
功能。可以通过 /proc/sys 变量调整间隔gc_interval
。
然后它会检查至少gc_thresh1
ARP 表中的条目如果表太小而无法在内存方面看到任何实际好处,这将避免消耗额外的 CPU 周期。
就你的情况而言,我怀疑gc_thresh1
这是你需要调整的变量。降低它会迫使 GC 更频繁地运行。不过,这可能会对性能产生负面影响,具体取决于运行间隔。
注意:gc_thresh3
是一个硬阈值。表将永远不会保存超过此值的条目。请小心调整。
答案2
Linux 内核中的邻居缓存并不是那么简单。
邻居缓存条目实际上完全从缓存中消失与仅被标记为陈旧/无效之间存在细微差别。在两者之间的某个时刻基本可达时间/2 和 3*基本可达时间/2,条目仍将保留在缓存中,但将被标记为 STALE 状态。您应该能够使用“ip -s neighbour show”查看该状态。
当处于 STALE 状态(如上所示)时,如果我 ping 10.64.42.121,它将立即将数据包发送到 b8:20:00:00:00:00。大约一秒钟后,它通常会发送一个 ARP 请求,询问谁拥有 10.64.42.121,以便将其缓存更新回 REACHABLE 状态。但是,更令人困惑的是,内核有时会根据来自更高级别协议的积极反馈更改超时值。这意味着,如果我 ping 10.64.42.121 并且它回复,那么内核可能不会发送 ARP 请求,因为它认为 pong 意味着它的 ARP 缓存条目有效。如果条目处于 STALE 状态,它还将通过碰巧看到的未经请求的 ARP 回复进行更新。
现在,对于大多数情况,您只需要担心条目处于 STALE 状态。为什么需要将条目从缓存中完全删除?内核付出了很多努力,只通过更改缓存条目的状态而不是实际将它们从缓存中删除和添加到缓存中来避免内存混乱。
如果你真的坚持认为它不仅会被标记为 STALE,而且会从邻居缓存使用的哈希表中删除,那么你必须注意几件事。首先,如果该条目尚未使用并且已经过时gc_stale_time秒,则应该有资格被删除。如果gc_stale_time并将该条目标记为可以删除,它将在垃圾收集器运行时被删除(通常在垃圾收集间隔秒)。
现在的问题是如果邻居条目正在被引用,则不会被删除。你最有可能遇到的问题就是IPv4 路由表有很多复杂的垃圾收集东西,但需要注意的重要一点是,路由缓存的垃圾收集器每 5 分钟只会使条目过期一次(/proc/sys/net/ipv4/route/gc_timeout很多内核上可能需要 30 秒的时间。这意味着邻居条目必须被标记为过期(可能为 30 秒,具体取决于基本可达时间),那么需要等待 5 分钟,路由缓存才会停止引用该条目(如果你幸运的话),然后是以下几种组合:gc_stale_time和垃圾收集间隔在实际清理之前会经过(所以,总的来说,大约需要 5-10 分钟)。
总结:你可以尝试减少/proc/sys/net/ipv4/route/gc_timeout缩短到较短的值,但变量很多,很难全部控制。我们付出了很多努力,通过不过早删除缓存中的条目(而是将它们标记为 STALE 甚至 FAILED)来使系统运行良好。
答案3
Kernel.org 的文档指出
route/max_size - INTEGER
Maximum number of routes allowed in the kernel. Increase
this when using large numbers of interfaces and/or routes.
From linux kernel 3.6 onwards, this is deprecated for ipv4
as route cache is no longer used.
/proc/sys/net/ipv4/route/gc_timeout
与邻居表的含义完全不同,并且路由缓存不再用于 ip4。如果你执行 a,sysctl net.ipv4.route.gc_thresh
你可能会看到它被设置为-1
答案4
在函数中neigh_periodic_work
有如下代码:
if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
goto out;
out:
/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
* ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
* BASE_REACHABLE_TIME.
*/
schedule_delayed_work(&tbl->gc_work,
NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
write_unlock_bh(&tbl->lock);
如果邻居数小于 gc_thresh1,则退出,gc 的任务被延迟,因此它无法删除 STALE 和 FAILED 邻居表,您可以修改的值/proc/sys/net/ipv4/neigh/default/gc_thresh1
,内核默认为 1283.10.0-327.36.3