【実務・中級編】 pingでのDFフラグ(Don’t Fragment)設定とMTUパスの検証手法 – トラブルシューティング&ネットワーク運用監視実践ガイド

「パケットが泣いている」:MTUの壁とDFフラグが教えるネットワークの真実

夜中の3時、データセンターのフロアで轟音を響かせる冷却ファンの音を聞きながら、ふと考えることがあります。我々が叩いているコマンドの裏側で、パケットは一体どんな旅をしているのか、と。

特に厄介なのが「MTU(Maximum Transmission Unit)問題」です。クラウド環境やVPN越しに通信をする際、なぜか特定のパケットだけがドロップする。Web APIを叩いてもレスポンスが返ってこず、curl が虚しくタイムアウトを繰り返す……そんな時、教科書通りのマニュアルを眺めていても解決はしません。

今回は、現場のエンジニアなら避けては通れない「DFフラグを用いたMTUパスの検証」について、泥臭い知見を共有しましょう。

—

1. なぜ「フラグメント」は悪者なのか?

ネットワークの基礎知識として、IPヘッダーには DF (Don't Fragment) というビットがあります。これを立てて送出すると、途中のルーターはパケットを分割(フラグメンテーション)することが許されません。

もし、そのパケットがルーターの通過可能な最大サイズ(MTU)を超えていたらどうなるか? ルーターは律儀に「これ以上は運べないから、ICMP Type 3 Code 4(Destination Unreachable, Fragmentation Needed and DF set)」というエラーを送信元へ投げ返します。

現代の高速なネットワーク運用において、フラグメンテーションは「悪」です。ルーターがわざわざCPUを使ってパケットを切り刻むのはオーバーヘッドが大きく、パフォーマンスを著しく低下させるからです。だからこそ、我々は「パケットを分割させない(DFフラグを立てる)」設計を行い、あらかじめ最適なサイズを把握しておく必要があるのです。

—

2. CLIで直感的に「壁」を見抜く

まずは、現場の基本ツールである ping を使って、経路上のボトルネックを特定する手法を叩き込みましょう。

Linux/macOSでの実践

ping コマンドでDFフラグを立てるには、環境に合わせてオプションを変える必要があります。

# Linuxの場合: -M do が「フラグメント禁止」を意味します
# -s でペイロードサイズを指定(IPヘッダー20byte + ICMPヘッダー8byteを考慮すること)
ping -M do -s 1472 192.168.1.1

# macOSの場合: -D が「フラグメント禁止」を意味します
ping -D -s 1472 192.168.1.1

ここで重要なのは、1472 という数字です。イーサネットの標準MTUである 1500 から、IPヘッダー(20byte)とICMPヘッダー(8byte)を引いた値が 1472 になります。これを超えるサイズを指定して ping が通らなくなれば、そこがその経路の限界点です。

—

3. アプリケーションコードで「MTUの壁」を再現する

API開発者が疎通確認を行う際、curl やPythonを使って「実際の通信経路」のMTUを測定する方法を知っておくと、インフラ担当者との会話が劇的にスムーズになります。

curl での検証

--trace-ascii を併用すると、どこでパケットが詰まっているか、ヘッダーのやり取りが可視化されます。

# MTUを意識した通信テスト
# --limit-rate などで帯域を絞りつつ、失敗する挙動を確認する
curl -v --max-time 5 http://api.example.com/health

Pythonでの実装例

実際のアプリケーションで「大きなデータ」を送信する際のチェックロジックとして活用してください。

import socket
import struct

def check_mtu(host, port, size):
    # ソケットを作成
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # IP_MTU_DISCOVER を IP_PMTUDISC_DO に設定 (DFフラグを立てる)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MTU_DISCOVER, socket.IP_PMTUDISC_DO)
    
    payload = b'A' * size
    try:
        sock.sendto(payload, (host, port))
        print(f"サイズ {size} のパケット送信成功")
    except OSError as e:
        # MTU超過でエラーが発生すると「Message too long」が返ってくる
        print(f"サイズ {size} でエラー発生: {e}")
    finally:
        sock.close()

# 1472バイトが境界線であることを確認するテスト
check_mtu("8.8.8.8", 53, 1472)

—

4. 現場のシニアからの一言:トラブルシューティングの極意

多くの若手が陥る罠があります。それは、「pingが通るから通信は問題ないはずだ」と思い込むことです。

実は、ping(ICMP)は通るのに、TCP 通信だけがタイムアウトするケースが多々あります。原因の多くは「Path MTU Discovery (PMTUD)」がどこかでブロックされていることによる「ブラックホールルーター」問題です。

  • ファイアウォールの設定: セキュリティポリシーでICMPの Fragmentation Needed パケットを全て破棄していないか?
  • MSS Clamping: ルーターの設定で ip tcp adjust-mss が適切に設定されているか?

トラブルに直面したとき、パケットのサイズだけを見るのではなく、「そのパケットがどんなヘッダー情報を持って旅立ち、途中でどの門前払いを食らったのか」を想像してください。

ネットワークは「魔術」ではなく、ただの「物理法則と論理」の積み重ねです。DFフラグを操り、MTUという見えない壁を可視化できるようになれば、あなたはもう一人前のトラブルシューターです。さあ、次はどのパケットを追いかけに行きましょうか?

コメント

タイトルとURLをコピーしました