パケットの鼓動を聞け:L2スイッチングの3大基本原理(ラーニング、フィルタリング、フラッディング)の深層
こんにちは。日夜、複雑怪奇に絡み合う配線と格闘し、パケットキャプチャの波形からネットワークの健康状態を診断しているシニアネットワークエンジニアです。
Webアプリケーションの向こう側で美しくJSONを返すAPI、その背後には必ず「鉄と銅と光」でできた物理世界が存在します。どれほど洗練されたAPIを設計しても、それを支えるL2(レイヤー2)スイッチがMACアドレスをどこに飛ばすべきか迷っていれば、レイテンシの悪化やパケットロスという現実に足元をすくわれます。
今回は、現代のLANを支えるL2スイッチの心臓部、「ラーニング(学習)」「フィルタリング(転送/破棄)」「フラッディング(束ねた洪水)」という3大基本動作を、実務でのトラブルシューティングの視点を交えながら徹底的に紐解いていきましょう。
—
1. L2スイッチングの基本概念とMACアドレステーブルの正体
L2スイッチは、OSI参照モデルのデータリンク層で動作し、MACアドレステーブル(Ciscoの世界ではCAMテーブルとも呼ばれます)を基にイーサネットフレームを適切なポートへフォワーディングします。
ルータがIPアドレスという「論理的な住所」を見てルーティングを行うのに対し、L2スイッチはMACアドレスという「ハードウェアに刻まれた固有の名前」を見てスイッチングを行います。ここで重要なのは、スイッチは上位層(IPやTCPなど)の構造を一切気にしていないという点です。彼らにとって世界は「どのポートから、どのMACアドレスを持つフレームが入ってきたか」の連続でしかありません。
MACアドレステーブルの構造とエージングタイム
スイッチのASIC(専用ハードウェア)内部にあるメモリには、次のようなマッピング情報が保持されています。
- MACアドレス: 送信元/宛先の物理アドレス(例:
00:1a:2b:3c:4d:5e) - ポート番号: スイッチの物理インターフェース(例:
GigabitEthernet 0/1) - VLAN ID: 所属する仮想LANの識別子
- エージングタイマー(Aging Timer): エントリの有効期限(Ciscoデフォルトでは通常300秒)
このエージングタイマーが非常に重要です。もし端末がネットワークから取り外されたり、NICが故障したりした場合、エントリが永遠に残るとMACアドレステーブルが溢れ(CAMテーブル飽和攻撃や枯渇)、スイッチがハブと同じ「全ポートへのばら撒き(フラッディング)」モードに落ち込んでパフォーマンスが劇的に低下します。これを防ぐため、一定時間通信がないエントリは自動的にパージされる仕組みになっています。
—
2. 3大基本動作のメカニズム:パケットはスイッチ内でどう処理されるか
L2スイッチにフレームが飛び込んできた瞬間、内部では厳格なアルゴリズムに従って3つの動作のいずれかが実行されます。それぞれの挙動をシーケンスとともに見ていきましょう。
[送信元PC (Port 1)]
│
▼ (フレーム送信)
[L2 スイッチ]
├── 1. ラーニング : Source MAC と Port 1 を紐付けてテーブルを更新
├── 2. フィルタリング : Destination MAC がテーブルにあれば指定ポートのみへ転送(他ポートは遮断)
└── 3. フラッディング : Destination MAC が未知なら、受信ポート以外の全ポートへ同報送信
① ラーニング(Learning:送信元MACアドレスの学習)
スイッチは、あるポートからフレームを受信すると、そのフレームの「送信元MACアドレス(Source MAC)」と、「受信した物理ポート」の組み合わせを瞬時にMACアドレステーブルに記録します。
- 「おっ、
00:1a:2b:3c:4d:5eという端末はPort 1に繋がっているんだな」と覚えるのがこのフェーズです。
② フィルタリング(Filtering:フレームの転送と選択的遮断)
次に、スイッチはそのフレームの「宛先MACアドレス(Destination MAC)」を自身のMACアドレステーブルから検索します。
- 宛先MACアドレスがテーブルに存在する場合、該当するポートにのみフレームを転送します。
- 同時に、他のポートへはフレームを流しません(フィルタリング=遮断します)。これにより、1Gbpsのリンクが複数存在する場合でも、それぞれの通信帯域が独立して確保される(コリジョンフドメインの分割)というスイッチの最大のメリットが生まれます。
③ フラッディング(Flooding:未知の宛先への同報送信)
もし、宛先MACアドレスがMACアドレステーブルに存在しない場合(未知のユニキャスト、あるいはブロードキャスト/マルチキャスト)、スイッチは困ってしまいます。どこに送ればいいか分からないからです。
- この場合、スイッチは受信したポート以外のすべてのポートへ同じフレームをコピーして送信します。これがフラッディングです。
- これにより、宛先の端末がどこにいても必ずフレームを受け取ることができますが、ネットワーク全体の無駄な帯域を消費する原因にもなります。
—
3. 実務で遭遇するトラブルとデバッグ:MACアドレステーブルの揺らぎ
現場でインフラを運用していると、「特定のサーバだけ通信が不安定になる」「ネットワークが突如として重くなる」といった現象に直面します。その多くは、このL2スイッチングの基本原理の裏側で起きています。
トラブル事例:MACフラッピング(MAC Flapping)の恐怖
仮想化環境(VMware ESXiやKVMなど)やコンテナ基盤、あるいはチーミング(LACPなど)を設定したサーバーを接続した際、同じMACアドレスが異なるスイッチポートから交互に学習される現象が発生することがあります。これをMACフラッピングと呼びます。
スイッチのログには以下のような警告が吐き出されます。
%SW_MATM-4-MACFLAP_NOTIF: Host 0050.56a1.2b3c in vlan 10 is flapping between port Gi0/1 and port Gi0/2
なぜこれが起きるのか?
冗長化された物理スイッチ間でループが発生している(STPの設定ミス)、あるいは仮想スイッチのライブマイグレーションやチーミングの設定ミスにより、同一のMACアドレスを持つパケットが別々の物理パスから流入することで、スイッチのMACアドレステーブルが毎秒のように書き換えられてしまうのです。これにより、ASICの処理負荷が跳ね上がり、パケットロスを引き起こします。
ネットワークエンジニアのためのデバッグ・確認コマンド(Cisco IOSの例)
現場でスイッチの内部状態を覗き見るための基本的なCLIコマンドです。障害切り分けの第一歩として必ず実行します。
# MACアドレステーブルの現状を確認する
Switch# show mac address-table dynamic
Mac Address Table
----------------------------------------------------------------
Vlan Mac Address Type Ports
---- ----------- ---- -----
10 001a.2b3c.4d5e DYNAMIC Gi0/1
10 0050.56a1.2b3c DYNAMIC Gi0/2
20 aabb.ccdd.eeff DYNAMIC Gi0/24
# 特定のMACアドレスがどこで学習されているか精査する
Switch# show mac address-table address 001a.2b3c.4d5e
# ポートごとのエラーカウンタやパケットドロップを確認する
Switch# show interfaces GigabitEthernet 0/1 counters
—
4. モダンなインフラ・Webエンジニアリングへの応用
「自分はAPIの設計やコンテナのオーケストレーション(Kubernetesなど)がメインだから、L2のスイッチングなんて関係ない」と思っていませんか? それは大きな誤解です。
例えば、KubernetesのCilium(eBPF/XDPベースのネットワー킹)や、Dockerのブリッジネットワーク(bridge ドライバ)の内部では、仮想的なL2スイッチングとMACアドレスの学習・転送がソフトウェア(LinuxブリッジやOVS:Open vSwitch)によって完全に再現されています。
コンテナ間の通信でパケットが迷子になったり、ARPテーブルの解決に失敗してAPIリクエストがタイムアウトしたりする原因の背後には、こうしたL2レイヤーのパケット処理メカニズムが深く絡んでいます。
Pythonによる簡易的なMACアドレステーブル・シミュレータ
L2スイッチの脳内(ラーニングとフィルタリングのアルゴリズム)をコードで非常にシンプルな形で表現してみましょう。概念の理解に役立ててください。
class SimpleL2Switch:
def __init__(self):
# MACアドレステーブルの初期化 (Key: MACアドレス, Value: ポート番号)
self.mac_table = {}
def receive_frame(self, src_mac: str, dest_mac: str, ingress_port: int) -> str:
"""
フレームを受信した際のL2スイッチの振る舞いをシミュレートする
"""
# 1. ラーニング(送信元MACと受信ポートの紐付けを学習・更新)
if src_mac not in self.mac_table:
print(f"[Learning] 新しいMACアドレスを学習: {src_mac} -> Port {ingress_port}")
self.mac_table[src_mac] = ingress_port
# 2 & 3. フィルタリング または フラッディング
if dest_mac in self.mac_table:
egress_port = self.mac_table[dest_mac]
# 宛先が自分自身(受信ポートと同じ)に戻る場合は破棄(セルフフォワーディング防止)
if egress_port == ingress_port:
return f"Drop: 送信元と宛先が同じポート ({ingress_port}) です"
# フィルタリング機能:宛先ポートだけにピンポイントで転送
return f"Forward (Filtering): MAC [{dest_mac}] は Port {egress_port} にのみ転送します"
else:
# フラッディング機能:宛先が不明なので受信ポート以外の全ポートにばら撒く
return f"Flood: MAC [{dest_mac}] は未知のため、全ポートにフラッディングします"
# --- 実行・検証シミュレーション ---
switch = SimpleL2Switch()
# シナリオ1: PC-A (Port 1) から PC-B (Port 2) へ初回のパケット送信(宛先はまだ未学習)
print("--- シナリオ1 ---")
print(switch.receive_frame(src_mac="AA:AA:AA:AA:AA:AA", dest_mac="BB:BB:BB:BB:BB:BB", ingress_port=1))
# シナリオ2: PC-B (Port 2) から PC-A (Port 1) へ返信(スイッチはすでにPC-Aを学習済み)
print("\n--- シナリオ2 ---")
print(switch.receive_frame(src_mac="BB:BB:BB:BB:BB:BB", dest_mac="AA:AA:AA:AA:AA:AA", ingress_port=2))
# シナリオ3: PC-C (Port 3) から 誰も知らない PC-X へ送信
print("\n--- シナリオ3 ---")
print(switch.receive_frame(src_mac="CC:CC:CC:CC:CC:CC", dest_mac="XX:XX:XX:XX:XX:XX", ingress_port=3))
このコードを実行すると、初回は宛先が分からないため Flood が起き、2回目以降はテーブルにエントリが存在するためピンポイントな Forward (Filtering) に切り替わる挙動がよく分かります。
—
5. おわりに:基盤を知るエンジニアは強い
L2スイッチの3大基本原理(ラーニング、フィルタリング、フラッディング)は、ネットワーク技術の歴史の中でも最も美しく、かつ効率的なアルゴリズムの一つです。
クラウドやコンテナ、そしてマイクロサービスという抽象化された世界の裏側でも、この物理・L2レイヤーの基本原則は1秒間に何億回も高速なASICやソフトウェアの内部で繰り返されています。
「なぜこの通信が遅いのか」「なぜブロードキャストストームが起きるのか」。その答えに迷ったときは、原点に立ち返り、パケットがスイッチのどのポートを叩き、MACアドレステーブルをどう書き換えているのかを脳内でトレースしてみてください。
その深い洞察力こそが、あなたを真のインフラストラクチャー・エキスパートへと導くはずです。
コメント