【実務・中級編】 ユニキャストMACアドレス、マルチキャストMACアドレス、ブロードキャストMACアドレス – インフラ・物理&L2/L3ネットワーク基礎実践ガイド

MACアドレスのDNAを暴く:ユニキャスト・マルチキャスト・ブロードキャストの深層と実務

ネットワークエンジニアとして現場を渡り歩いていると、レイヤ3(IP)のルーティングやレイヤ7のAPI設計ばかりに目が行きがちです。しかし、どれほど洗練されたマイクロサービスアーキテクチャを構築しようとも、最終的にパケットは必ずレイヤ2の泥臭い世界、すなわちイーサネットフレームへとカプセル化され、物理的な銅線や光ファイバーの上を駆け抜けていきます。

今回は、そのL2世界の主役である「MACアドレス」の正体に迫ります。特に、宛先をどのように識別しているのかを決める「I/Gビット(Individual/Group bit)」の仕組みと、ユニキャスト、マルチキャスト、ブロードキャストがスイッチングハブや端末のNIC(Network Interface Card)の内部でどのように扱われているのか、実務的な視点で徹底的に紐解いていきましょう。

教科書をなぞるだけの説明はもう終わりにしましょう。パケットキャプチャの向こう側で見えている真実を、シニアエンジニアの視点でお届けします。

—

1. MACアドレスの構造と「I/Gビット」という運命の分かれ道

MACアドレスは48ビット(6バイト)の識別子であり、通常は 00:1A:2B:3C:4D:5E のような16進数表記で表されます。しかし、この48ビットの並びを単なる「機械の背番号」だと思ってはいけません。

実は、先頭バイト(最も左のバイト)の、一番右側のビット(LSB:Least Significant Bit)が、そのフレームの運命を決定づけています。これがI/Gビット(Individual/Group bit)です。

[先頭バイトの8ビット表現]
  7   6   5   4   3   2   1   0  (ビット位置)
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   | I | -> I/Gビット (0: ユニキャスト, 1: マルチキャスト/ブロードキャスト)
+---+---+---+---+---+---+---+---+
                            ^
                            ここに注目!
  • I/Gビット = 0 (Individual): ユニキャストMACアドレス

特定の1台のNICだけに宛てられた通信です。送信元MACアドレスは必ずこの「0」になります(自分がグループの送信元になることは論理的にあり得ないため)。

  • I/Gビット = 1 (Group): マルチキャスト または ブロードキャストMACアドレス

特定のグループ、あるいは同一セグメント上の全ノードに向けて一斉送信するためのものです。

現場でトラブルシューティングを行う際、Wiresharkなどでキャプチャしたフレームの先頭バイトをパッと見て、このI/Gビットが立っているかどうかを確認するだけで、そのトラフィックが「1対1の対話」なのか「1対多のバラマキ」なのかが一瞬で判別できます。この視点を持つだけでも、障害切り分けのスピードが段違いに上がります。

—

2. 三大アドレスの挙動とスイッチングの裏側

では、これら3つのアドレスタイプが、L2スイッチや各ホストのNICの内部でどのように処理されているのか、具体的な挙動を見ていきましょう。

① ユニキャストMACアドレス(I/G = 0)

最も一般的な通信です。例えば、Webサーバー(AA:BB:CC:11:22:33)からクライアント(DD:EE:FF:44:55:66)へデータを送る場合、宛先MACアドレスにはクライアントの固有のアドレスが指定されます。

  • L2スイッチの挙動:

スイッチは受信したフレームの宛先MACアドレスを自身のMACアドレステーブル(CAMテーブル)と照合します。テーブルにエントリが存在すれば、該当するポートにのみフレームを転送(Unicast Forwarding)します。無駄なトラフィックを流さない、非常に効率的な仕組みです。

② マルチキャストMACアドレス(I/G = 1)

特定のグループに参加している複数のホストにのみデータを配送します(例: OSPFやVRRPなどのルーティングプロトコル、IPマルチキャストなど)。

  • イーサネットのマルチキャストの仕様:

IEEE 802では、先頭の24ビット(OUI)のうち特定のプレフィックス(01:00:5Eなど、IPv4マルチキャストの場合)を使用し、I/Gビットが確実に 1 になるように予約されています。

  • L2スイッチとNICの挙動:

初期のハブと異なり、現代のスイッチはマルチキャストをデフォルトでは「フラッディング(全ポート転送)」させません(IGMPスヌーピング等の機能により、参加者がいるポートにのみ転送します)。また、NIC側でもハードウェアレベルでフィルタリングを行い、自機が参加していないマルチキャストフレームはOSに渡す前に破棄します。

③ ブロードキャストMACアドレス(FF:FF:FF:FF:FF:FF)

同一セグメント(ブロードキャストドメイン)に存在するすべてのデバイスの耳に強制的に届く、最強にして最悪の通信手段です。お馴染みの FF:FF:FF:FF:FF:FF は、すべてのビットが 1(もちろんI/Gビットも 1)で構成されています。

  • L2スイッチの挙動:

宛先が FF:FF:FF:FF:FF:FF のフレームを受信した場合、スイッチは受信ポート以外のすべてのポートへ無条件にフレームを転送(Flooding)します。

  • 実務上の注意点:

ARPリクエストやDHCPディスカバーなど、相手のMACアドレスやIPが分からない初期段階で必須ですが、不用意なブロードキャストの嵐(ブロードキャストストーム)は、エンドホストのCPU負荷(割り込み処理の増大)を跳ね上げ、ネットワーク全体を麻痺させます。VLANによるブロードキャストドメインの適切な分割が不可欠な理由がここにあります。

—

3. 実務で役立つ!PythonによるL2/L3パケット解析・生成スニペット

インフラエンジニアやバックエンドエンジニアであっても、APIの疎通だけでなく、ネットワークの低レイヤで何が起きているかをプログラムから検証できるスキルは大きな武器になります。

ここでは、Pythonの強力なライブラリである Scapy を使って、ユニキャストやブロードキャストのイーサネットフレームを意図的に構築・送信し、I/Gビットの挙動をコードベースで理解するサンプルを紹介します。

from scapy.all import Ether, IP, TCP, sendp, get_if_hwaddr

# 実務Tips: テスト環境やコンテナ等でデフォルトのインターフェース名を指定する
# 例として Linux環境の 'eth0' を想定
INTERFACE = "eth0"

def send_custom_ethernet_frames(target_ip):
    """
    指定されたインターフェースから、ユニキャストおよびブロードキャストの
    レイヤ2フレームを構築して送信するサンプルコード。
    """
    
    # 自ホストのMACアドレスを動的に取得
    try:
        my_mac = get_if_hwaddr(INTERFACE)
        print(f"[*] 自ホストのMACアドレス: {my_mac} (I/Gビット = 0 [ユニキャスト])")
    except Exception as e:
        print(f"[-] インターフェース {INTERFACE} の取得に失敗しました: {e}")
        return

    # 1. ユニキャストフレームの構築
    # 宛先MACに特定の存在(例: ゲートウェイやテスト用サーバーのMAC)を指定
    # ここでは便宜上、自ホスト宛てのユニキャストとする
    uni_ether = Ether(src=my_mac, dst=my_mac, type=0x0800)
    uni_payload = IP(dst=target_ip) / TCP(dport=80, flags="S")
    
    print("[*] ユニキャストフレームを送信します...")
    # sendpはL2(データリンク層)レベルでパケットを送出する関数
    sendp(uni_ether / uni_payload, iface=INTERFACE, verbose=False)

    # 2. ブロードキャストフレームの構築
    # 宛先MACにオール1 (FF:FF:FF:FF:FF:FF) を指定。I/Gビットは強制的に 1 になる。
    bc_ether = Ether(src=my_mac, dst="ff:ff:ff:ff:ff:ff", type=0x0800)
    
    print("[*] ブロードキャストフレーム(ARPやL2ブロードキャスト模倣)を送信します...")
    sendp(bc_ether / uni_payload, iface=INTERFACE, verbose=False)
    
    print("[+] 送信完了。Wireshark等のパケットキャプチャで先頭バイトのI/Gビットを確認してください。")

if __name__ == "__main__":
    # 検証用のターゲットIP(ローカルのダミーIP等)
    TARGET_IP = "192.168.1.254"
    # ※実際の実行には管理者権限(sudo)が必要です
    # send_custom_ethernet_frames(TARGET_IP)
    print("このスクリプトはScapy環境(sudo python3 script.py)で実行してください。")

コードの解説と現場のTips

  • Ether(dst="ff:ff:ff:ff:FF:FF"): この指定を行うことで、Scapyは自動的にL2ヘッダーの宛先をオール1に設定します。Wiresharkでキャプチャすると、このフレームの Destination MAC の先頭バイトが奇数(マルチキャスト/ブロードキャスト特性を示す値)になっていることが確認できます。
  • sendp()関数: 通常の send() はL3(IP)層からパケットを組み立てますが、sendp() はL2(イーサネットフレーム)そのものを直にワイヤー上に放り込みます。L2の挙動をデバッグする際には必須の関数です。

—

4. ネットワーク設計・運用の現場で陥る「落とし穴」と対策

最後に、実務の現場でこのMACアドレスの特性(特にマルチキャスト・ブロードキャスト)に起因して発生するトラブルと、その処方箋を共有します。

トラブル事例:マルチキャスト/ブロードキャストストームによるCPUスパイク

ある日突然、L2スイッチに接続された一部のサーバー群が一斉に高負荷(CPU使用率100%)に陥り、Web APIのレスポンスが完全に途絶えたという障害がありました。

  • 原因の追跡:

ネットワークアナライザでキャプチャしたところ、ループバック(L2ループ)が発生しており、無数のブロードキャストおよびマルチキャストフレームがスイッチ間を無限に周回(フラッディングの連鎖)していました。サーバーのNICは、自分宛てではない膨大なフレームの割り込み処理(ハードウェア割り込み)を延々と処理させられ、カーネルがフリーズ寸前になっていたのです。

  • 実務での対策:

1. STP(Spanning Tree Protocol)/ RSTP / MSTPの徹底: L2ループを物理的・論理的に根絶するため、冗長化構成では必ずSTP系プロトコルを有効化し、ポートファストやBPDUガード等のエッジ保護を実装する。
2. ストームコントロール(Storm Control)の設定: スイッチ側で、ブロードキャストやマルチキャスト、未知のユニキャストトラフィックが帯域の一定割合(例: 5%など)を超えた場合に、自動的にドロップする機能を有効化しておく。

—

まとめ

普段何気なく使っているIPアドレスの裏側には、必ずこのMACアドレスとL2スイッチの泥臭いせめぎ合いが存在しています。

  • MACアドレスの先頭バイトのLSBにある「I/Gビット」が、その通信の性質(1対1か、1対多か)を決定づけている。
  • ユニキャストは効率的な転送、ブロードキャストはネットワーク全体の負荷になり得る諸刃の剣。
  • インフラを設計・運用する上では、L2のブロードキャストドメインの設計と、ストーム対策がシステムの安定性を左右する。

ネットワークの基礎は、いつの時代もエンジニアの足元を支える最強の武器です。次回のトラブルシューティングの際には、ぜひパケットの「I/Gビット」に思いを馳せてみてください。きっと、問題の本質がより鮮明に見えてくるはずです。

コメント

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