连接时“没有可用的缓冲区空间”

use*_*942 6 linux buffer

当进程在 Linux 虚拟机上调用“connect”时,我看到错误消息“没有可用的缓冲区空间”。我在追查原因时遇到了麻烦-希望有人可以提供帮助!

我检查了以下内容:

(1) 文件句柄:

cat /proc/sys/fs/file-nr
4672 0 810707 
Run Code Online (Sandbox Code Playgroud)

我正在阅读它(已分配,未使用,可用),所以这看起来不错。

(2) 套接字或 TCP 内存:

cat /proc/sys/net/ipv4/tcp_mem
191889 255854 383778

cat /proc/net/sockstat
sockets: used 579
TCP: inuse 169 orphan 0 tw 245 alloc 187 mem 5
UDP: inuse 31 mem 4
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0
Run Code Online (Sandbox Code Playgroud)

读到这里总共只有 579 个正在使用的套接字,页面总数远低于最大值。

Google 上显示了许多随机 TCP 调整 - 我希望在答案中是 (1) 我即将用完的资源,(2) 如何确定当前值以及 (3) 如何调整天花板。我发现的大多数页面都缺少除 (3) 之外的所有内容!

** 更新 #1 **

在 Flup 的建议下,我在它发生时做了一个 systrace(使用 ping):

socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
connect(4, {sa_family=AF_INET, sin_port=htons(1025), sin_addr=inet_addr("10.140.0.65")}, 16) = -1 ENOBUFS (No buffer space available)
Run Code Online (Sandbox Code Playgroud)

** 更新 #2 **

我对 linux 内核源代码了解不多,但我进行了一番挖掘,在 connect() 路径中我能看到 ENOBUFS 的唯一地方在这里:http : //lxr.free-electrons.com/source/net /ipv4/af_inet.c?v=3.11#L353

这看起来像是在内核中分配东西,尽管使用kmem_cache_allocsecurity_sk_alloc...?

小智 5

在 3.6 之前的内核中,当 net.ipv4.route.max_size 或 net.ipv6.route.max_size限制耗尽时,常规 IPv4/v6 流量可能会受到 ENOBUFS 的影响。

从内核 3.6 开始,路由缓存被删除,net.ipv4.route.max_size 失去了对 dst 条目数量的影响。因此,一般来说,这将不再可能。

但是,在使用 IPSec 时,您仍然可能会像我一样遇到此错误。创建一定数量的 IPSec 隧道后,我无法 ping 远程主机:

# ping 10.100.0.1
connect: No buffer space available
Run Code Online (Sandbox Code Playgroud)

iputils 中的 ping 创建测试文件描述符,并在其上使用 connect() 来绑定 dst ip。当发生这种情况时,给定 AF 的 dst 缓存条目由内核创建,并且在我的情况下 xfrm4 dst 缓存条目限制已经耗尽。该限制由 sysctl 设置控制:

xfrm4_gc_thresh - INTEGER
    The threshold at which we will start garbage collecting for IPv4
    destination cache entries.  At twice this value the system will
    refuse new allocations.
Run Code Online (Sandbox Code Playgroud)

我在使用内核 3.10.59 时遇到了这个问题,其中默认限制非常低 - 1024。从内核 3.10.83 开始,此限制增加到 32768,并且更难达到

所以,我发出:

# sysctl net.ipv4.xfrm4_gc_thresh=32768
Run Code Online (Sandbox Code Playgroud)

它为我做到了。

对于我的 IPSec 案例,内核中的大致路径:

ip4_datagram_connect() -> ip_route_connect() -> ip_route_output_flow() ->
xfrm_lookup() -> xfrm_resolve_and_create_bundle() ->
... -> xfrm_alloc_dst() -> dst_alloc() with xfrm4_dst_ops, where gc is set.
Run Code Online (Sandbox Code Playgroud)