[Amazon VPC]ハードウェアVPN接続のMTUとTCP MSSの最適値を探す

はじめに

ハードウェアVPN接続に関する前回までの記事はこちらです。

さて、Management Consoleの[VPN Connections]画面から、各機器に合わせた設定ファイルをダウンロード出来ることは上記の記事でご説明しました。

この設定ファイルの内容を見てみると、ちょっと気になる部分があります。例えばGeneric Vendorだと...

IPSec ESP (Encapsulating Security Payload) inserts additional headers to transmit packets. These headers require additional space, which reduces the amount of space available to transmit application data. To limit the impact of this behavior, we recommend the following configuration on your Customer Gateway: - TCP MSS Adjustment : 1387 bytes

Configure your tunnel to fragment at the optimal size: - Tunnel interface MTU : 1436 bytes

となっています。MTUについてはAmazon Virtual Private Cloud Network Administrator Guide (API Version 2013-10-15)に

 Your interface should be set to a 1436 byte Maximum Transmission Unit (MTU)

と記載されている通り、AWSとしてはMTUを1436byesに設定するよう推奨しています。

ハードウェアVPN接続のIPSecトンネルで使われるハッシュアルゴリズムはSHA-1、暗号化アルゴリズムはAESですので、仮に回線のMTUが1500bytesだった場合、

(((1500 - 20(IP header) - 8(ESP header) - 12(Authentication Data)) - 16(Initial Vector)).div(16)*16) - 2(ESP Trailer) = 1438bytes

なので、Tunnel MTUは1438bytesになります。AWSの推奨MTUが1436bytesになっているのは安全値として余裕を持っているためでしょう。

しかし、一般的にTCP MSSは

MTU - 20byes(IP header) - 20(TCP header)

になりますので、MTUが1436bytesの場合TCP MSSは1396bytesが最適値に思えます。

何故1387bytesなんでしょう?というのが今回のスタート地点です。

答え:IPヘッダは固定長では無いから

以下はIPヘッダのフォーマットです。

IPheader

一列が32bitですので4bytesになります。このうち「オプション」については可変長であり、0bytesから最大40bytesまで拡大します。このオプションが0bytesである場合、IPヘッダは20bytesになりますが、オプションが最大まで使われた場合、IPヘッダは60bytesになります。オプションの種類についてはRFC 791に詳細が記載されていますが、代表的なものだとソースルーティングのオプションなどがあります。

一般的な通信ではオプションヘッダが使われることはあまりありませんが、ここで重要なのは可変長であるという事実です。AWSではオプションヘッダが使われることも考慮し、安全側に倒した設計となっています。このため

MTU - 20byes(IP header) - 20(TCP header) - 9bytes(reserve)

の値がTCP MSとして設定されています。

ではMTUは1436bytesが適正値なのでしょうか?

答えは否です。

これは良く知られた事実ですが、フレッツシリーズに代表されるNTTのIP通信網は、MTUが1454bytesになっています。詳しくはNTTが技術参考資料として提示している「IP 通信網サービスのインタフェース ― フレッツシリーズ ―」(※PDF)を参照して下さい。MTU値を超えるパケットはフラグメント(分割)され転送効率が悪化してしまいます。

例えばフレッツ回線でハードウェアVPN接続したCiscoルータからVPCにあるEC2に対して、DF(フラグメント禁止)bitを立てて、パケットサイズを1436bytesに指定してPingを実行すると、到達出来ません。

Router#ping 172.31.3.104 df-bit size 1436
Type escape sequence to abort.
Sending 5, 1436-byte ICMP Echos to 172.31.3.104, timeout is 2 seconds:
Packet sent with the DF bit set
.....
Success rate is 0 percent (0/5)

これはNTTのIP通信網のMTUである1454bytesから更にIPSecトンネル分のパケットヘッダが付与されているためです。

今回はCiscoルータのiOSからPingを行っていますが、iOSのPIngのsize指定はIPパケット全体のサイズ指定となります。

WindowsやLinuxのPingコマンドの場合はpayload(ヘッダを除いたサイズ)を指定しますので、MTUはsize + 20(IP header) + 8(ICMP header)になります。

フレッツ回線でのMTUの最適値は?

前述した計算式で、MTUが1454bytesとして計算すると、

(((1454 - 20(IP header) - 8(ESP header) - 12(Authentication Data)) - 16(Initial Vector)).div(16)*16) - 2(ESP Trailer) = 1390bytes

なので、Tunnel MTUは1390byteにするべきです。もちろん余裕を持ってより小さくしても構いません。

実際に試してみました。

Router#ping 172.16.0.100 df-bit size 1391
Type escape sequence to abort.
Sending 5, 1391-byte ICMP Echos to 172.16.0.100, timeout is 2 seconds:
Packet sent with the DF bit set
.....
Success rate is 0 percent (0/5)
Router#ping 172.16.0.100 df-bit size 1390
Type escape sequence to abort.
Sending 5, 1390-byte ICMP Echos to 172.16.0.100, timeout is 2 seconds:
Packet sent with the DF bit set
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 4/6/8 ms

1391bytesでは到達出来ず、1390bytesでは成功しました。ですので、フレッツ回線を使用される場合は1390bytesがMTUの最適値と考えて良いでしょう。

TCP MSSはどうでしょう?このハードウェアVPN接続でIPヘッダのオプションを使うような通信が一切無いのであれば、MTUから40bytesを引いた1350bytesで良いですが、どのような通信が発生するか分からない場合や今後の拡張性を加味したい場合は、AWSの推奨値通り49bytesを引いた1341bytesにしても良いかも知れません。

どちらにせよ、MTUやTCP MSSは回線や通信の種類によって様々ですので、AWSの推奨値に捕われること無く適切な値を検証し設定したいものです。

まとめ

AWSにクローズした環境については国や地域による設定値の差はありませんが、オンプレミス環境と接続する際にはこういった回線環境の違いが設定値の違いとなって現れる場合があります。今後も様々な検証を行ってBlogに書いていきたいと思います!