Yah, saya tidak tahu persis apa masalahnya, tetapi saya akan mencoba mencari arah yang tepat untuk menyelesaikannya.
ENOBUFS
kode dikembalikan saat sk_alloc()
atau dst_alloc()
gagal. Saya tidak dapat menemukan kemunculan ENOBUFS
lainnya dalam kode sumber yang terkait dengan soket.
Saya juga tidak dapat menemukan jalur apa pun dari SYSCALL_DEFINE3(connect)
ke sk_alloc()
, dan menurut saya soket tidak boleh dialokasikan selama connect()
call di mana Anda mendapatkan kesalahan, jadi saya pikir tidak mungkin sk_alloc()
menyebabkan masalah.
dst_alloc()
kemungkinan digunakan untuk memeriksa rute selama connect()
, saya tidak dapat menemukan jalur yang tepat untuk itu, pasti ada di suatu tempat di dalam:SYSCALL_DEFINE3(connect)
-> .connect()
-> ip4_datagram_connect()
-> ip_route_connect()
dst_alloc()
mengalokasikan entri dalam cache SLAB yang sesuai, dan mungkin gagal jika cache penuh. Sebenarnya entri lama harus dihapus jika itu terjadi, tapi mungkin ada kasus ketika masih mengembalikan kesalahan.
Jadi saya pikir Anda dapat pindah ke arah ini. Ukuran cache pertama dapat diubah melalui /proc/sys/net/ipv4/route/max_size
. Pertama, periksa apakah pengaturan (atau pengaturan lain di sys.net.ipv4.route
) diubah oleh "tweak TCP acak yang ditampilkan di Google".
Di kernel sebelum 3.6, Anda bisa terkena ENOBUFS untuk lalu lintas IPv4/v6 reguler, ketika batas net.ipv4.route.max_size atau net.ipv6.route.max_size telah habis.
Dimulai dengan kernel 3.6, cache perutean dihapus, dan net.ipv4.route.max_size kehilangan pengaruhnya terhadap jumlah entri dst. Jadi, secara umum, itu tidak mungkin lagi.
Namun, Anda masih bisa mengalami kesalahan ini seperti saya, saat menggunakan IPSec. Setelah terowongan IPSec dibuat dalam jumlah tertentu, saya tidak dapat melakukan ping ke host jarak jauh:
# ping 10.100.0.1
connect: No buffer space available
ping dari iputils membuat deskriptor file uji, dan menggunakan connect() di atasnya, untuk mengikat ip dst. Ketika itu terjadi, entri cache dst untuk AF yang diberikan dibuat oleh kernel, dan batas entri cache xfrm4 dst sudah habis dalam kasus saya. Batas ini dikontrol oleh pengaturan 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.
Saya mengalami ini menggunakan kernel 3.10.59, di mana batas default sangat rendah - 1024. Mulai dari kernel 3.10.83, batas ini dinaikkan menjadi 32768, dan akan jauh lebih sulit untuk dicapai.
Jadi, saya mengeluarkan:
# sysctl net.ipv4.xfrm4_gc_thresh=32768
dan itu berhasil untuk saya.
Perkiraan jalur di kernel untuk kasus saya dengan 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.