Bueno, no sé cuál es exactamente el problema, pero intentaré encontrar la dirección correcta para resolverlo.
El ENOBUFS
el código se devuelve cuando sk_alloc()
o dst_alloc()
es fallido No puedo encontrar ninguna otra aparición de ENOBUFS
en el código fuente relacionado con los sockets.
Además, no puedo encontrar ninguna ruta desde el SYSCALL_DEFINE3(connect)
a sk_alloc()
, y creo que el socket no debe asignarse durante connect()
llame donde obtiene el error, por lo que creo que no es probable que el sk_alloc()
causó el problema.
El dst_alloc()
es probable que se use para verificar rutas durante el connect()
, no puedo encontrar la ruta exacta, debe estar en algún lugar dentro:SYSCALL_DEFINE3(connect)
-> .connect()
-> ip4_datagram_connect()
-> ip_route_connect()
El dst_alloc()
asigna una entrada en un caché SLAB correspondiente, y en realidad puede fallar si el caché está lleno. En realidad, las entradas antiguas deben eliminarse si eso sucede, pero tal vez haya casos en los que aún devuelva un error.
Así que creo que puedes moverte en esta dirección. El tamaño de caché de dst puede cambiar a través de /proc/sys/net/ipv4/route/max_size
. Primero, verifique si la configuración (o cualquier otra configuración en sys.net.ipv4.route
) se cambia por "ajustes de TCP aleatorios que se muestran en Google".
En los núcleos anteriores a 3.6, ENOBUFS podría haberlo afectado por el tráfico normal de IPv4/v6, cuando el límite de net.ipv4.route.max_size o net.ipv6.route.max_size se agotó, en consecuencia.
A partir del kernel 3.6, se eliminó el caché de enrutamiento y net.ipv4.route.max_size perdió su influencia en la cantidad de entradas de dst. Entonces, en general, eso ya no sería posible.
Sin embargo, aún puede encontrarse con este error como yo, al usar IPSec. Después de cierta cantidad de túneles IPSec creados, no pude hacer ping al host remoto:
# ping 10.100.0.1
connect: No buffer space available
ping de iputils crea un descriptor de archivo de prueba y usa connect() en él para vincular el dst ip. Cuando sucede, el kernel crea la entrada de caché dst para el AF dado, y el límite de entradas de caché xfrm4 dst ya se agotó en mi caso. Este límite está controlado por la configuración de 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.
Me encontré con esto usando el kernel 3.10.59, donde el límite predeterminado es muy bajo:1024. A partir del kernel 3.10.83, este límite se incrementó a 32768 y sería mucho más difícil de alcanzar.
Entonces, emití:
# sysctl net.ipv4.xfrm4_gc_thresh=32768
y lo hizo por mí.
Ruta aproximada en kernel para mi caso con 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.