2017-01-10 10 views
1

私は非常に奇妙な状況に遭遇しました。sendto()はエラーコードENETDOWNを返します

私のプログラムでは、sendto()関数は、ネットワークが稼動しており、tryingが成功しても、エラーコードENETDOWN(Network is down)を返します。

ストリームは、UDPストリームが複数のゲートウェイを介して他のネットワークに接続されている場合にのみ発生します。時々いつも起こるとは限らない。 同じサブネットワーク下で同じコードを実行すると、ENETDOWNのようなエラーはありません。

したがって、トレースsendto()は、カーネル領域に機能します。 の機能は、ip_finish_output2()iop_output.cを呼び出してhh->hh_output()を呼び出し、ENETDOWNエラーコードを返します。

機能がdev_queue_xmit()に割り当てられ、dev.cに割り当てられ、パケットがネットワークに送信されます。

問題が発生した場合は、のにあるneigh_blackhole()の機能に割り当てられているようです。 neigh_blackhole()-ENETDOWNコードを返します。

しかし、neigh_destroy()が呼び出された時期とその理由がわかりません。

私はこの問題を数週間苦労しています。

答えて

0

ホストは、レイヤ3アドレスを保持している間にホストがレイヤ2アドレスを変更したり、もはや到達可能でないなど、さまざまな理由で近隣ノードが削除されると主張されています。 thisを参照してください。また、ネイバーのゲートウェイがICMPリダイレクトを送信し、リダイレクトの処理がカーネル内で有効になっている場合は削除できます。

ネイバーが削除中の場合、無条件に-ENETDOWNを返すneigh_blackholeにパケットがディスパッチされます。コードhereを参照してください。

マニュアルページsendto()の場合、このような状況では-ENETDOWNが得られないはずですが、これは間違っているようです。

これが発生したときにネットワークキャプチャを試み、宛先に到達できないことを示すICMPメッセージ、またはARPパケットを介して宛先(または重複したIPアドレス)のMACアドレスが変更されたことを確認します。宛先から到着したパケットのMACアドレス。

+0

私のプログラムが動作しているマシンがICMPリダイレクトメッセージを受信した場合、ネイバーは削除できますか? – shin2011

+1

「ホスト向けのリダイレクト」コードと新しいゲートウェイアドレスを持つICMPリダイレクトメッセージが表示されます。 – shin2011

+0

私は、ICMPリダイレクトがこれを引き起こすかどうかを確認するためにカーネルコードを調べていませんが、確かに可能です。私は一時的なものとして-ENETDOWNエラーを処理し、再試行することをお勧めします。遅れていても、バックオフを使っている可能性もあります。 –

1

私のテストマシンは以下のように配置されています。 テストマシン---ゲートウェイ(1.1.1.1)---ファイアウォール(1.1.1.2)---ネットワーク---宛先。

私のテストマシンと、テストマシンの宛先とゲートウェイアドレスとの間の初めてのUDP接続確立は1.1.1.1です。 テストマシンの宛先間でトラフィックに問題はありません。しばらくした後、または突然、 "Network is Down"エラー(エラー番号100、ENETDOWN)で送信トラフィックが失敗します。 この時点で、テストマシンで宛先にpingを試みると、ping応答がOKになります。 テストマシンのパケットフロントをキャプチャすると、ICMPリダイレクトメッセージはゲートウェイ(1.1.1.1)から送信されます。その情報は「ホスト向けリダイレクト」で、新しいゲートアドレスは「1.1.1.2」です。 テストマシンのOS(Linux 3.0.35)がICMPリダイレクトメッセージを受信すると、hh-> hh_output()の仮想関数ポインタがev_queue_xmit()からneigh_blackhole()に変更されます。やがて、neigh_blackhole()は-ENETDOWNコードを返します。

したがって、テストマシンのゲートアドレスを1.1.1.2に変更してください。その後、「Network is down」エラーは再び発生しません。

奇妙な動作だと思います。 sendto()関数はENETDOWNコードをマニュアルページとして返しません。しかし、ENETDOWNコードが返されます。 とにかく、ネットワークインターフェイスが更新されていても、sendto()関数が-ENETDOWNを返すと、このエラーをどのように克服できますか? UDPストリームを再接続しますか?

この問題は、Linuxカーネル3.0.35のバグです。

私がこの問題について知っているか見つかったら、ここで更新します。 誰かが私と同様の問題を抱えている場合は、私のケースを参照してください。