web-dev-qa-db-ja.com

接続時に「使用可能なバッファスペースがありません」

Linux仮想マシンでプロセスが「接続」を呼び出すと、「利用可能なバッファスペースがありません」というエラーメッセージが表示されます。原因の追跡に問題があります-誰かが助けてくれることを願っています!

私は以下をチェックしました:

(1)ファイルハンドル:

cat /proc/sys/fs/file-nr
4672 0 810707 

私はこれを(割り当て済み、未使用、使用可能)と読んでいるので、問題ありません。

(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

これを使用している合計579のソケットとして読むと、ページの合計は最大値をはるかに下回ります。

たくさんのランダムTCP微調整がGoogleに表示されています-回答で期待しているのは、(1)不足しているリソース、(2)現在のリソースを特定する方法です。値と(3)天井の調整方法。私が見つけたほとんどのページには、(3)以外のすべてが欠けています!

**アップデート#1 **

Flupの提案で、(pingを使用して)発生したときにsystraceを実行しました。

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)

**アップデート#2 **

Linuxカーネルソースについてはあまり知りませんが、Digを使用していて、connect()パスの中でENOBUFSを確認できる唯一の場所はここにあります http://lxr.free-electrons.com /source/net/ipv4/af_inet.c?v=3.11#L35

これはkmem_cache_allocsecurity_sk_alloc...を使用してカーネルに割り当てているようです。

6
user611942

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

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.

私はカーネル3.10.59を使用してこれに遭遇しました。デフォルトの制限は非常に低い-1024です。カーネル3.10.83から、この制限は32768に増加し、 ヒットするのがはるかに困難になります

だから、私は発行しました:

# sysctl net.ipv4.xfrm4_gc_thresh=32768

そしてそれは私のために事をしました。

私の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.
3
Alexey Zyryanov

まあ、正確には何が問題なのかはわかりませんが、問題を解決するための正しい方向を見つけようと思います。

sk_alloc()またはdst_alloc()のいずれかが失敗すると、ENOBUFSコードが返されます。ソケットに関連するソースコードでENOBUFSの他の出現箇所を見つけることができません。

また、SYSCALL_DEFINE3(connect)からsk_alloc()へのパスを見つけることができず、エラーが発生するconnect()の呼び出し中にソケットを割り当てることはできないため、sk_alloc()が問題の原因である可能性は低いと思います。

dst_alloc()は、connect()の間にルートをチェックするために使用される可能性があります。正確なパスが見つかりません。どこかにある必要があります: SYSCALL_DEFINE3(connect) -> .connect() -> ip4_datagram_connect() -> ip_route_connect()

dst_alloc()は、対応するSLABキャッシュにエントリを割り当てます。キャッシュがいっぱいの場合、実際には失敗する可能性があります。その場合、実際には古いエントリを削除する必要がありますが、それでもエラーが返される場合があります。

ですから、この方向に進むことができると思います。 dstキャッシュサイズは/proc/sys/net/ipv4/route/max_size。最初に、設定(またはsys.net.ipv4.route)は、「ランダムにTCP Googleに表示される微調整」によって変更されます。

3