MTU,MSS の計算と最適化の便利な手段をまとめる

MTU/MSS の計算

IP ヘッダや Ethernet フレームの計算は結構大変だけれどもこのサイトを使えばわりとラクに導出できます。 https://baturin.org/tools/encapcalc/

たとえば MTU 1454 の環境(フレッツ網で ISP と PPPoE で接続した場合)の MSS は次の画像のとおり 1414 と計算可能です。

この MTU 1454 の根拠は,フレッツ網では PPPoE で接続する際,NTT の収容ビルから事業者装置までの間は L2TP で接続しており,そこで PPPoE ヘッダを認証用の PPP ヘッダだけ残して取り払い,PPP over L2TP の状態にすると,IP (20 byte) + UDP (8 byte) + PPP (2 byte) + L2TP (16 byte) = 46 byte なので,1500 - 46 = 1454 byte になります。参考サイト

さきほどのサイトでは L2TPv3 の計算はできるけど L2TP の計算が出来ないのが惜しいところ。

MTU の最適化

前述の手段で計算した値をルーターやクライアントに設定しても良いですが,既に通信が可能な環境ならばヒューリスティックに最適な MTU を導出することもできます。

ping コマンド

PS C:\Users\orumin> ping -f -l 1424 -n 1 8.8.8.8

8.8.8.8 に ping を送信しています 1424 バイトのデータ:
8.8.8.8 からの応答: バイト数 =68 (1424 を送信) 時間 =3ms TTL=119

8.8.8.8 の ping 統計:
    パケット数: 送信 = 1、受信 = 1、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 3ms、最大 = 3ms、平均 = 3ms
たとえば Windows なら,このようにして ping のパケットサイズを指定し DF ビットを立てます(=分割を禁止する)。こうすると,MTU を超過するようなパケットを送出すると以下のようになります。
PS C:\Users\orumin> ping -f -l 1425 -n 1 8.8.8.8

8.8.8.8 に ping を送信しています 1425 バイトのデータ:
パケットの断片化が必要ですが、DF が設定されています。

8.8.8.8 の ping 統計:
    パケット数: 送信 = 1、受信 = 0、損失 = 1 (100% の損失)、

これで最適なサイズは 1424 だとわかりますが,この数字はデータサイズなので,ここに IP ヘッダ (20 byte) と ICMP ヘッダ (8 byte) を足した 1424 + 20 + 8 = 1452 byte が私の環境で最適な MTU となります。

これは IPoE で IPv6 を貰った上で IPv4 over IPv6 (DS-Lite) を利用している環境なので,MTU 1500 - IPv6 (40 byte) - encap_limit (8 byte) = 1452 です。https://www.spinics.net/lists/netdev/msg143874.html

ping のオプションについて,Linux と macOS(FreeBSD ユーザーランド)でのオプションはそれぞれ以下のとおり。

$ ping -c 1 -s 1424 -M do 8.8.8.8 # Linux
$ ping -c 1 -s 1424 -D 8.8.8.8 # macOS

traceroute コマンド

また,世の中には Path MTU Path MTU Discovery (ご指摘感謝 https://twitter.com/ichinose_iroha/status/1278822907053932544) というものがあり,途中経路で ICMP が破棄されない環境なら,ルーターが ICMP 経由で適切な MTU を返してくれることにより,MTU が自動で最適な値に設定できます。参考サイト

ここで,traceroute のコマンドオプションによって PMTU PMTU 探索を使って適切な MTU を取得することが可能です

$ traceroute -F -N 1 --mtu 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 65000 byte packets
 1  192.168.11.1 (192.168.11.1)  0.485 ms F=1500  0.456 ms  0.465 ms
 2  ike-gw10.transix.jp (14.0.9.78)  3.856 ms F=1452  3.530 ms  3.245 ms
 ..

F=xxxxの値を確認すると,最初に CPE で F=1500 として渡してますが,次に DS-Lite の AFTR で NAPT されたあとに返ってくる F= の値が 1452 になっており,この環境の適切な MTU が 1452 であることが把握可能です。

ちなみにこれを DS-Lite ではなく PPPoE 経由にしてみると,

$ sudo traceroute -F -N 1 --mtu -i enp2s0 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 65000 byte packets
 1  192.168.1.1  0.395 ms F=1500  0.408 ms  0.357 ms
 2  xxxxxxxxxxxxxxxx (xxx.xxx.xxx.xxx)  3.415 ms F=1454  3.373 ms  3.356 ms

たしかに F=1454 になっており,本記事冒頭で計算した MTU に合致していますね。

PMTU PMTU 探索 は便利ですが,PMTU を信頼してこちら側で MTU を指定していない時,途中経路に ICMP を返さないヤツとかが居ると Path MTU Black Hole になってしまい,こちら側で適切な MTU が設定できなくて TCP のセッションがタイムアウトするといった可能性があります (RFC2923) 参考サイト

最後に余談ですが,たとえば SINET などはジャンボフレームに対応しており MTU が 9140 bytes とされています(念のためちょっと少なめの 9000 byte あたりに設定することを推奨されています)。そのため,インターネットへの接続が SINET を経由している学術機関などではもう少し大きいパケットを送れる可能性があります。ただし大学→SINET のアクセス回線がフレッツの可能性もあるので,そこらへんは自分の所属機関に問合せたほうが早いでしょう。