ARP缓存报“No buffer space available”并非单纯缓存满,而是当前邻居表总数≥gc_thresh3且垃圾回收不及,尤其NUD_INCOMPLETE条目堆积导致GC低效;需同步调大gc_thresh1/2/3并验证生效。

Linux内核的ARP缓存限制能改,但不能只调一个参数就完事——gc_thresh1、gc_thresh2、gc_thresh3必须严格满足递增关系,否则内核会静默忽略修改或触发异常回收行为。
为什么改了gc_thresh3还是报SIOCSARP: No buffer space available
这个错误不是缓存“满了”才出现,而是当新条目尝试插入时,当前邻居表总数已 ≥ gc_thresh3,且垃圾回收器(GC)来不及清理。关键点在于:
-
gc_thresh1是GC启动下限(默认128),低于它GC根本不动; -
gc_thresh2是软上限(默认512),超了允许撑5秒; -
gc_thresh3是硬上限(默认1024),一超立刻强制GC,但若此时大量条目处于NUD_INCOMPLETE(如arping未响应)状态,GC效率极低,新条目仍被拒。
常见于Mininet仿真、Kubernetes节点密集通信、大规模容器网络等场景。临时解决办法是同步调高三者,例如:
sudo sysctl -w net.ipv4.neigh.default.gc_thresh1=1024 sudo sysctl -w net.ipv4.neigh.default.gc_thresh2=4096 sudo sysctl -w net.ipv4.neigh.default.gc_thresh3=8192
注意:IPv6需单独设net.ipv6.neigh.default.gc_thresh*,不共用同一组值。
永久生效时/etc/sysctl.conf写错位置会失效
很多用户把参数写成net.ipv4.neigh.eth0.gc_thresh3却忘了接口名在实际环境中可能动态变化(如cloud-init重命名网卡为ens3),导致配置不生效。更稳妥的做法是:
- 优先修改
default层级(影响所有未显式覆盖的接口); - 若必须按接口定制,确认接口名稳定(可用
ip -br link查); - 写入后务必执行
sysctl -p,并用sysctl net.ipv4.neigh.default.gc_thresh3验证是否加载成功; - 避免混用
/proc/sys/直接写和sysctl -w——前者不触发内核校验逻辑,可能绕过阈值约束检查。
调大上限后内存真的扛得住吗
每条ARP/ND条目在内核中占用约512字节(含结构体+哈希链指针),8192条就是约4MB,看似不多。但容易被忽略的是:
- 容器环境里,每个网络命名空间都维护独立邻居表,宿主机上跑100个Pod,若每个命名空间都达到
gc_thresh3,内存开销翻百倍; - ARP表膨胀常伴随
res_failed计数飙升(查看/proc/net/stat/nf_conntrack或/proc/net/neighbour/*目录下的统计文件),说明GC频繁失败,可能已拖慢网络栈; - 物理内存小于4GB的设备,建议
gc_thresh3上限不超过2048,否则OOM killer可能介入杀进程。
真实压力下,比盲目调大更有效的是:用ip neigh show nud failed定位长期卡在失败状态的条目,再结合tcpdump -i any arp看是否上游交换机未响应,从根源减少无效条目生成。
局域网连接多≠必须堆ARP条目数
如果目标只是支撑更多终端接入(比如DHCP服务端连2000台设备),其实不需要让本机ARP表存满2000条——多数通信由交换机二层转发完成,本机只需缓存网关、DNS服务器等关键节点。真正需要调参的,是那些作为LVS、BGP反射器、或运行arping探测服务的节点。后者往往因高频主动探测,快速填满缓存。此时应优先检查net.ipv4.neigh.default.base_reachable_time_ms(默认30000ms)是否过长,缩短它可加速老化,比硬扩容量更安全。


















