ハングしている接続

このトピックでは、クラウド・ネットワークとオンプレミス・ネットワーク間の通信で見られる最も一般的な問題の1つである、接続してホストにpingを送信できているのに接続がハングするという問題について説明します。

問題と解決策のサマリー

症状:Virtual Cloud Network (VCN)が、Site-to-Site VPNまたはOracle Cloud Infrastructure FastConnectを使用して既存のオンプレミス・ネットワークに接続します。接続の一方の側のホストは反対側のホストにpingを送信できますが、接続を使用した通常のトラフィックはハングします。例:

  • この接続を介してSSHでホストにログインできますが、ログイン後に接続がハングします。
  • Virtual Networking Computing (VNC)接続を開始できますが、セッションがハングします。
  • SFTPダウンロードを開始できますが、ダウンロードがハングします。

一般的な問題: 接続の片側または両側でPath Maximum Transmission Unit Discovery (PMTUD)が機能していない可能性があります。これが接続の両側で機能していないと、双方が送信しようとしているパケットが接続に対して大きすぎるかどうかを判断して、それに応じた調整をすることができません。最大転送単位(MTU)およびPMTUDの概要は、MTUの概要およびPMTUDの概要を参照してください。

PMTUDを修復するための解決策:

次の図は、オンプレミス・ネットワークがサイト間VPNを介してVCNに接続されているシナリオの例で、ソリューションの各部分を表すコールアウトが付いています。

この図は、ハングしている接続を修復するための解決策の各部分を示しています
  1. ホストがPMTUDを使用していることを確認します: オンプレミス・ネットワーク内のホストがPMTUDを使用していない(つまり、パケットにDon't Fragmentフラグが設定されていない)場合、送信しようとしているパケットが接続に対して大きすぎるかどうかを調べる方法がありません。接続のOracle側のインスタンスでは、デフォルトでPMTUDが使用されます。インスタンスでその構成を変更しないでください。また、サーバーに、ICMPタイプ3コード4を許可するファイアウォール・ルールがあることを確認してください。
  2. VCNセキュリティ・リストとインスタンス・ファイアウォールの両方でICMPタイプ3コード4のメッセージが許可されていることを確認します: PMTUDが使用されている場合、送信側のホストが接続に対して大きすぎるパケットを送信すると、特別なICMPメッセージが返されます。このメッセージを受信すると、ホストはパケットのサイズを接続に収まるように動的に更新できます。ただし、インスタンスでこれらの重要なICMPメッセージを受信するには、それらを受け入れるようにVCNのサブネットのセキュリティ・リストとインスタンス・ファイアウォールの両方を構成する必要があります。

    ヒント

    (TCP、UDP、またはICMPトラフィックに対して)ステートフル・セキュリティ・リスト・ルールを使用している場合は、ネットワーキング・サービスにより接続が追跡され、ICMPタイプ3コード4のメッセージが自動的に許可されるため、セキュリティ・リストにこれらのメッセージを許可する明示的なルールがあることを確認する必要はありません。ステートレス・ルールでは、ICMPタイプ3コード4メッセージのイングレス・セキュリティ・リストに明示的なルールが必要です。インスタンス・ファイアウォールが正しく設定されていることを確認します。

    ホストがこれらのメッセージを受信しているかどうかを確認するには、PMTUDの破損場所の検出を参照してください。

  3. オンプレミス・ルーターがDon't Fragmentフラグに従うことを確認します:ルーターがフラグに従わず、PMTUDの使用を無視した場合、断片化されたパケットがVCN内のインスタンスに送信されます。これは、望ましいことではありません(フラグメンテーションを避ける理由を参照)。VCNのセキュリティ・リストは最初のフラグメントのみを認識するように構成されている可能性が高く、それ以外のフラグメントがドロップされることにより、接続がハングします。これを避けるために、ルーターはPMTUDを使用し、Don't Fragmentフラグを適用して、その接続を介して送信する断片化されていないパケットの正しいサイズを決定する必要があります。

MTUとPMTUDの概要、およびネットワーク接続の両側でPMTUDが機能しているか確認する方法を引き続きお読みください。

フラグメンテーションを避ける理由

なぜフラグメンテーションを避ける必要があるのか、疑問に思われるかもしれません。1つ目の理由は、アプリケーションのパフォーマンスが低下することです。フラグメンテーションがあると、フラグメントの再構築と失われたフラグメントの再転送が必要になります。再構築および再送信には、時間とCPUリソースが必要です。

2つ目の理由は、最初のフラグメントのみにソースと宛先のポート情報が含まれていることです。つまり、ファイアウォールまたはVCNのセキュリティ・リストは、通常はポート情報を評価するように構成されているため、他のパケットを削除することを意味します。ファイアウォールおよびセキュリティ・リストでフラグメンテーションに対処するには、その権限を通常よりも強力に構成する必要がありますが、それは望ましくありません。

MTUの概要

インターネット・プロトコル(IP)ネットワーク上の2つのホスト間の通信では、パケットが使用されます。各パケットには、ソースと宛先のIPアドレスおよびデータのペイロードが含まれています。2つのホスト間の各ネットワーク・セグメントは、1つのパケットで伝送できるバイト数を表す最大転送単位(MTU)を持っています。

標準のインターネットMTUサイズは、1500バイトです。これは、大半のホーム・ネットワークや多くの企業ネットワーク(およびそのWi-Fiネットワーク)にも該当します。Oracle Cloud Infrastructureのデータ・センターなど、一部のデータ・センターのMTUは、それより大きい場合があります。すべてのOCIコンピュート・インスタンスで、デフォルトで9000のMTUが使用されます。Oracle Linux 8ホストでは、ip address showコマンドを使用して、そのホストのネットワーク接続のMTUを表示できます(または、Red Hat Linuxではip linkを使用します)。たとえば、Oracle Linux 8インスタンスからの出力を次に示します(MTUは赤色のイタリックで強調表示されています)。

ip address show <interface-x>
<interface-x>: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 01:00:5E:90:10:10 brd ff:ff:ff:ff:ff:ff
    ... 

比較のために、企業ネットワークに接続されたOracle Linux 8ホストからの出力を次に示します:

ip address show <interface-y>
<interface-y>: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 01:00:5E:90:10:20 brd ff:ff:ff:ff:ff:ff
    ...

そのMTUは、より一般的な1500バイトになっています。

企業VPNを介してホストが接続する場合、VPNトンネルはトラフィックをIPSecパケット内にカプセル化してローカル・ネットワーク経由で送信する必要があるため、MTUはさらに小さくなります。例:

ip address show <interface-z>
<interface-z>: flags=81d1<UP,POINTOPOINT,RUNNING,NOARP,PROMISC,MULTICAST> mtu 1300 
... 

2つのホストは、互いに送信できるパケットの大きさをどのようにして判断するのでしょうか。HTTP、SSH、FTPなど、多くのタイプのネットワーク・トラフィックでは、ホストはTCPを使用して新しい接続を確立します。各ホストは、2つのホスト間の最初の3方向ハンドシェーク中に、可能な最大ペイロード・サイズを示す最大セグメント・サイズ(MSS)を送信し合います。これはMTUより小さい値です。(TCPがインターネット・プロトコル(IP)内部で実行されるため、TCP/IPと呼ばれます。セグメントとTCPの関係は、パケットとIPの関係に似ています。)

tcpdumpアプリケーションを使用すると、ハンドシェイク中に共有されたMSS値を確認できます。tcpdumpの例を次に示します(MSSは赤色のイタリックで強調表示されています):

12:11:58.846890 IP 192.168.0.25.22 > 10.197.176.19.58824: Flags [S.], seq
2799552952, ack 2580095593, win 26844, options [mss 1260,sackOK,TS val
44858491 ecr 1321638674,nop,wscale 7], length 0

前のパケットは、SSH接続により、企業VPNに接続されたラップトップからインスタンスに送信されたものです。ラップトップでインターネット接続に使用されるローカル・ネットワークのMTUは、1500バイトです。VPNトンネルでは、1300バイトのMTUが適用されます。その後、SSH接続の試行時に、(IP接続内部で実行されている)TCPによって、1260バイト以下のTCPセグメントがサポートされることがOracle Cloud Infrastructureインスタンスに通知されます。企業VPN接続を使用する場合、通常、VPNに接続されたラップトップのMTUとMSSは、インターネット経由で通信するどの場合と比べても最小になります。

2つのホストのMTUが、そのどちらにも直接接続されていない両者間の中間ネットワーク・リンクのMTUよりも大きいとき、さらに複雑になります。次の図に例を示します。

この図は、ネットワーク接続全体の各地点における異なるMTUレベルを示しています

この例では、2つのサーバーがあり、それぞれが9000バイトのMTUをサポートする各自のルーティング済ネットワークに直接接続されています。これらのサーバーは異なるデータ・センター内にあります。各データ・センターは、1500バイトのMTUをサポートするインターネットに接続します。サイト間VPN IPSecトンネルが2つのデータ・センターを接続しています。そのトンネルはインターネットを経由するため、トンネル内部のMTUはインターネットよりも小さくなります。この図では、そのMTUは1380バイトです。

2つのサーバーが(たとえば、SSHを使用して)通信を試行すると、双方は3方向のハンドシェイク中にMSSを約8960にすることに合意します。最初のSSH接続設定時の最大パケット・サイズは通常1380バイト未満なので、最初のSSH接続は成功する可能性があります。片側が2つのエンドポイント間の最小リンクより大きいサイズのパケットを送信しようとしたときに、Path MTU Discovery (PMTUD)が重要になります。

PMTUDの概要

Path MTU Discoveryは、RFC 1191およびRFC 8899 で定義されています。これは、通信する2つの各ホストに対して、送信するパケット内にDon't Fragmentフラグを設定するように要求することにより機能します。一方のホストから送信されたパケットがルーターに到達したが、そのエグレス(アウトバウンド)インタフェースのMTUがパケット長よりも小さい場合、ルーターはそのパケットをドロップします。また、ルーターは、ICMPタイプ3コード4のメッセージをホストに返します。このメッセージは、「Destination Unreachable, Fragmentation Needed and Don't Fragment Was Set」という内容です(RFC 792で定義されています)。これは、ルーターがホストに対して、「大きすぎるパケットを断片化しないようにそちらから指示されましたが、このパケットは大きすぎるのでこちらからは送信しません。」と伝えているということです。また、ルーターは、そのエグレス・インタフェースを介して許可される最大サイズ・パケットをホストに通知します。送信側のホストは、メッセージに示されたルーターよりも小さい値になるように、そのアウトバウンド・パケットのサイズを調整します。

この例は、インスタンスが、8000バイトのパケットおよびDon't Fragmentフラグを設定して(つまり、PMTUDを使用して)ホスト(203.0.113.2)にインターネット経由でpingを送信しようとしたときの結果を示しています。返されたICMPメッセージは、赤色のイタリックで強調表示されています:

ping 203.0.113.2 -M do -s 8000

PING 203.0.113.2 (203.0.113.2) 8000(8028) bytes of data.
From 10.0.0.2 icmp_seq=1 

Frag needed and DF set (mtu = 1500)

レスポンスは予期したとおりのものです。宛先ホストは、MTUが1500バイトであるインターネットを経由します。送信側のホストのローカル・ネットワーク接続のMTUが9000バイトであっても、そのホストからの8000バイトのパケットは宛先ホストに到達できず、それを示すICMPメッセージが返されます。PMTUDは正しく機能しています。

比較のために、宛先ホストがサイト間VPN IPSecトンネルを経由する場合の同じpingを次に示します:

ping 192.168.6.130 -M do -s 8000
PING 192.168.0.130 (192.168.0.130) 8000(8028) bytes of data.
From 192.0.2.2 icmp_seq=1 Frag needed and DF set 

(mtu = 1358)

ここでは、VPNルーターは、このパケットを宛先に送信するためのアウトバウンド・インタフェースがVPNトンネルであると判断します。そのトンネルはインターネットを経由するため、トンネルはインターネットの1500バイトのMTUのリンクに収まる必要があります。その結果、トンネル内部で許可されるパケットは最大1360バイトになります(後からルーターによってこの値が1358に下げられたため、さらに混乱を招きやすくなっています)。

PMTUDの破損場所の検出

接続のどこかでPMTUDが機能していない場合は、その原因と壊れている場所を特定する必要があります。一般的な原因は、(パケットに収まらない制約付きリンクのあるルーターからの) ICMPタイプ3コード4のパケットが送信側ホストに返されないことです。これは、ホストとルーターの間、およびVPNトンネルの両側(またはその他の制約付きMTUリンク)で、そのような種類のトラフィックがブロックされている場合に発生することがあります。

接続の各側からのpingの試行

破損したPMTUDに関するトラブルシューティングを行うには、接続の各側でPMTUDが機能しているかどうかを判別する必要があります。この例では、接続がサイト間VPNを使用すると想定してみます。

ping送信の方法: PMTUDの概要に示したように、大きすぎてVPNトンネルに収まらないとわかっているパケット(たとえば、1500バイト以上のパケット)を使用して、接続の相手側のホストにpingを送信します。送信側のホストで使用されているオペレーティング・システムによっては、Don't Fragmentフラグが設定されているか確認するために、pingコマンドの書式を少し変える必要がある場合があります。UbuntuとOracle Linuxではいずれも、pingコマンドで-Mフラグを使用します。

-Mフラグに関する埋込みヘルプ情報を次に示します:

-M pmtudisc_opt
Select Path MTU Discovery strategy. pmtudisc_option may be either do
(prohibit fragmentation, even local one), want (do PMTU discovery, fragment
locally when packet size is large), or dont (do not set DF flag).

pingの例を次に示します(-Mフラグを使用、結果のICMPメッセージは赤色のイタリックで強調表示されています)

ping -M do

 -s 1500 192.168.6.130
PING 192.168.0.130 (192.168.0.130) 1500(1528) bytes of data.
From 10.0.0.2 icmp_seq=1 

Frag needed and DF set (mtu = 1358)

良い: PMTUDが機能している

結果に「From x.x.x.x icmp_seq=1 Frag needed and DF set (mtu = xxxx)」という行が含まれる場合、トンネルのその側のPMTUDは機能しています。ICMPメッセージのソース・アドレスは、トラフィックを送信しようとしているトンネルのパブリックIPアドレスです(たとえば、前出のUbuntuの例では203.0.113.13)。

また、接続の反対側からもpingを送信して、その側からPMTUDが機能していることを確認します。接続の両側は、その間のトンネルが大きなパケットを収容できない場合を認識する必要があります。

悪い: 自分側の接続をテストして、pingが成功する場合

オンプレミス・ネットワーク内のホストからpingを送信してpingが成功した場合は、エッジ・ルーターが「フラグメントしない」フラグを適用していない可能性があります。かわりに、ルーターは大きいパケットを断片化しています。最初のフラグメントは宛先ホストに到達するため、pingは成功しますが、これが誤解を招きます。ping以外のことを実行しようとすると、2つ目以降のフラグメントはドロップされ、接続がハングします。

ルーターの設定でDon't Fragmentフラグが適用されることを確認します。ルーターのデフォルト構成ではフラグが適用されますが、誰かがデフォルトを変更した可能性もあります。

悪い: 接続のVCN側をテストして、ICMPメッセージが表示されない場合

接続のVCN側からテストして、レスポンスにICMPメッセージが表示されない場合は、ICMPパケットがインスタンスに到達する前に何かがドロップされた可能性があります。

次の2つの問題が考えられます:

  • セキュリティ・リスト:ネットワーキング・・セキュリティ・リストに、ICMPタイプ3コード3のメッセージ4がインスタンスに到達することを許可するイングレス・ルールが含まれていない可能性があります。これが問題になるのは、ステートレス・セキュリティ・リスト・ルールを使用している場合のみです。ステートフル・ルールを使用している場合、接続は追跡され、ICMPメッセージは自動的に許可されるため、それを許可する特定のセキュリティ・リスト・ルールは必要ありません。ステートレス・ルールを使用している場合は、インスタンスのサブネットに、ソース0.0.0.0/0および任意のソース・ポートからのICMPトラフィック・タイプ3コード4を許可するイングレス・ルールを含むセキュリティ・リストがあることを確認してください。詳細は、セキュリティ・リスト(特にセキュリティ・リストでのルールの更新)を参照してください。
  • インスタンス・ファイアウォール: (OSで設定されている)インスタンスのファイアウォール・ルールに、ICMPタイプ3コード4のメッセージがインスタンスに到達することを許可するルールが含まれていない可能性があります。特にLinuxインスタンスの場合、ICMPタイプ3コード4のメッセージを許可するようにiptablesまたはfirewalldを構成します。

PMTUDの必要性の回避

PMTUDの使用をお薦めします。ただし、状況によっては、これに依存する必要がないようにサーバーを構成できる場合もあります。VCN内のインスタンスがサイト間VPNを介してオンプレミス・ネットワーク内のホストと通信する場合について考えてみます。オンプレミス・ネットワークのIPアドレスの範囲はわかっています。そのアドレス範囲内のホストと通信する際に使用する最大MTUを指定する特殊ルートを、インスタンスに追加できます。VCN内部のインスタンス間通信には、引き続き9000バイトのMTUが使用されます。

次の情報は、Linuxインスタンスにそのルートを設定する方法を示しています。

インスタンスのデフォルト・ルート表には、通常は2つのルートがあります。1つはデフォルト・ルート(デフォルト・ゲートウェイ用)で、もう1つはローカル・ルート(ローカル・サブネット用)です。例:

ip route show
default via 10.0.6.1 dev ens3
10.0.6.0/27 dev ens3  proto kernel  scope link  src 10.0.6.9

オンプレミス・ネットワークのアドレス範囲と、より小さいMTUサイズを設定して、同じデフォルト・ゲートウェイを指す別のルートを追加できます。たとえば、次のコマンドでは、オンプレミス・ネットワークは1.0.0.0/8、デフォルト・ゲートウェイは10.0.6.1、オンプレミス・ネットワークに送信されるパケットの最大MTUサイズは1300です。

ip route add 1.0.0.0/8 via 10.0.6.1 mtu 1300

更新されたルート表は次のようになります:

ip route show
default via 10.0.6.1 dev ens3
1.0.0.0/8 via 10.0.6.1 dev ens3  mtu 1300
10.0.6.0/27 dev ens3  proto kernel  scope link  src 10.0.6.9

VCN内部のインスタンス間通信には、引き続き9000 MTUが使用されます。ただし、オンプレミス・ネットワークとの通信では最大1300が使用されます。この例では、オンプレミス・ネットワークとVCNの間の接続に、1300より小さいMTUを使用する部分がないことを前提としています。

重要

インスタンスを再起動した場合、前のコマンドは永続しません。ルートをOS内の構成ファイルに追加すると、そのルートを永続的にすることができます。たとえば、Oracle Linuxの場合、/etc/sysconfig/network-scripts/route-<interface>というインタフェース固有ファイルを使用します。詳細は、ご使用のLinuxバージョンのドキュメントを参照してください。