---
title: スイッチング、ブリッジング、そしてVXLAN
url: https://doc.liz6.com/ja/networking/01-l2-data-link/03-switching-bridging-and-vxlan
locale: ja
area: networking
tags:
- networking
- l2-data-link
date: 2026-06-30
modified: 2026-07-16
description: STPによるループ防止からVLANによる分離、そしてVXLANによるレイヤー3横断トンネルへ——レイヤー2ネットワークの進化史は、「ブロードキャストドメインをいかに小さく切り分け、トンネルをいかに遠くまで伸ばすか」という歴史そのものです。MAC学習とSTP収容を理解すれば、データセンターネットワークが現在の姿になった理由が見えてきます。
---

# スイッチング、ブリッジング、そしてVXLAN

> STPによるループ防止からVLANによる分離、そしてVXLANによるレイヤー3横断トンネルへ——レイヤー2ネットワークの進化史は、「ブロードキャストドメインをいかに小さく切り分け、トンネルをいかに遠くまで伸ばすか」という歴史そのものです。MAC学習とSTP収容を理解すれば、データセンターネットワークが現在の姿になった理由が見えてきます。

## 概要

スイッチはMAC学習によって転送パスを自動構築し、手動設定なしでイーサネットを数千ノード規模に拡張可能にします。Linux bridgeも同様の機能をソフトウェアで実装しています。コンテナやVMはveth pairを介してbridgeに接続され、bridgeがL2転送を担当します。STP/RSTPはループによるブロードキャストストームを防ぎ、VXLANはIPネットワーク上に仮想L2ネットワークを重ね合わせ、4094というVLANの制限を1600万まで拡張します。これらはデータセンターや家庭向けネットワークにおけるL2仮想化の基盤です。

## MAC学習: 分散ハッシュマップ

各スイッチはMACアドレステーブル（フィルタリングデータベース）を維持しています。

<svg viewBox="0 0 720 420" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="MAC学習、宛先アドレスによるテーブル参照に基づく転送分岐、およびエントリの老化・削除の全体フロー">
  <defs>
    <marker id="mlArrow" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker>
  </defs>
  <rect width="720" height="420" fill="#ffffff"/>
  <text x="360" y="26" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">MAC学習と老化: スイッチが自己修復する分散ハッシュマップ</text>

  <text x="40" y="50" font-size="13" font-weight="700" fill="#1f2933">① 学習: フレーム到着時に送信元MACを記録</text>
  <rect x="40" y="60" width="175" height="36" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="127" y="82" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">フレームがポートNに到着</text>
  <line x1="215" y1="78" x2="239" y2="78" stroke="#475569" stroke-width="1.6" marker-end="url(#mlArrow)"/>
  <rect x="241" y="60" width="175" height="36" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="328" y="82" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">送信元MACを取得</text>
  <line x1="416" y1="78" x2="440" y2="78" stroke="#475569" stroke-width="1.6" marker-end="url(#mlArrow)"/>
  <rect x="442" y="60" width="238" height="36" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="561" y="82" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">保存 (MAC → ポートN)</text>

  <line x1="40" y1="108" x2="680" y2="108" stroke="#e2e8f0" stroke-width="1"/>

  <text x="40" y="126" font-size="13" font-weight="700" fill="#1f2933">② 転送: フレームの宛先MACに基づき転送先を決定</text>
  <rect x="270" y="134" width="180" height="30" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="360" y="153" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">MACテーブル参照 (宛先MACで検索)</text>
  <line x1="360" y1="164" x2="150" y2="178" stroke="#475569" stroke-width="1.6" marker-end="url(#mlArrow)"/>
  <line x1="360" y1="164" x2="360" y2="178" stroke="#475569" stroke-width="1.6" marker-end="url(#mlArrow)"/>
  <line x1="360" y1="164" x2="570" y2="178" stroke="#475569" stroke-width="1.6" marker-end="url(#mlArrow)"/>
  <rect x="50" y="180" width="200" height="42" rx="6" fill="#ccfbf1" stroke="#99f6e4"/>
  <text x="150" y="199" text-anchor="middle" font-size="12" font-weight="700" fill="#115e59">既知 → ユニキャスト転送</text>
  <text x="150" y="215" text-anchor="middle" font-size="10" fill="#0f766e">対応するポートへ (フラッディングしない!)</text>
  <rect x="260" y="180" width="200" height="42" rx="6" fill="#ffedd5"/>
  <text x="360" y="199" text-anchor="middle" font-size="12" font-weight="700" fill="#9a3412">未知 → フラッディング</text>
  <text x="360" y="215" text-anchor="middle" font-size="10" fill="#c2410c">全ポートへ送信 (受信ポートを除く)</text>
  <rect x="470" y="180" width="200" height="42" rx="6" fill="#e2e8f0"/>
  <text x="570" y="199" text-anchor="middle" font-size="12" font-weight="700" fill="#334155">ブロードキャスト/マルチキャスト → フラッディング</text>
  <text x="570" y="215" text-anchor="middle" font-size="10" fill="#475569">(常に全ポートへ送信)</text>

  <line x1="40" y1="236" x2="680" y2="236" stroke="#e2e8f0" stroke-width="1"/>

  <text x="40" y="254" font-size="13" font-weight="700" fill="#1f2933">③ 老化: 各エントリにはエイジングタイマーがある (デフォルト300秒)</text>
  <rect x="270" y="262" width="180" height="28" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="360" y="280" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">エイジングタイマー 300秒</text>
  <line x1="360" y1="290" x2="190" y2="302" stroke="#475569" stroke-width="1.6" marker-end="url(#mlArrow)"/>
  <line x1="360" y1="290" x2="530" y2="302" stroke="#475569" stroke-width="1.6" marker-end="url(#mlArrow)"/>
  <rect x="50" y="304" width="280" height="40" rx="6" fill="#dcfce7" stroke="#4ade80"/>
  <text x="190" y="322" text-anchor="middle" font-size="12" font-weight="700" fill="#166534">同じ送信元MACが再度出現</text>
  <text x="190" y="338" text-anchor="middle" font-size="10" fill="#15803d">→ タイマーをリセットし、存続継続</text>
  <rect x="390" y="304" width="280" height="40" rx="6" fill="#ffedd5"/>
  <text x="530" y="322" text-anchor="middle" font-size="12" font-weight="700" fill="#9a3412">タイマー期限切れ → エントリ削除</text>
  <text x="530" y="338" text-anchor="middle" font-size="10" fill="#c2410c">→ 次回フラッディング (再学習)</text>

  <rect x="40" y="356" width="640" height="54" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="56" y="378" font-size="12.5" fill="#3730a3">インサイト: これにより、一定期間アイドル状態だったデバイスで一時的なパケットロスが発生する理由が説明できます。</text>
  <text x="56" y="397" font-size="12.5" fill="#3730a3">スイッチがデバイスを忘れる → 次のフレームでフラッディング → 1パケットが失われるが、直後に再学習される。</text>
</svg>

学習と転送は同時に行われます。フレームを受信すると、まず送信元を学習し（MACテーブルを更新）、次に宛先を調べます。もし宛先が送信元ポートと同じ場合、転送しません（フィルタリングし、ループを防ぐ）。

## Linux Bridge

```c
// net/bridge/
// bridgeは本質的に仮想スイッチであり、FDB (Forwarding Database) に MAC→port の対応を保持する

struct net_bridge_fdb_entry {
    unsigned char       addr[ETH_ALEN];     // MAC
    struct net_bridge_port *dst;            // 出口ポート
    struct hlist_node   fdb_node;           // ハッシュテーブル
    struct hlist_node   vlan_node;          // VLANごとのリスト
    unsigned long       updated;            // 最終更新時刻 (jiffies)
    unsigned long       used;               // 最終使用時刻 (jiffies)
    u16                 vlan_id;
    // フラグ: sticky, added_by_user, added_by_external_learn, offloaded
};
```

bridgeと物理スイッチの違い:
1. 物理スイッチ: MACテーブルはハードウェアASICに存在 → ポートごとの超高速検索
2. Linux bridge: MACテーブルはハッシュテーブル（ソフトウェア）に存在 → ハードウェアより約10倍遅いが、ソフトウェアスイッチ（<10Gbps）には十分
3. Linux bridgeでは `ageing_time` を設定可能:

```bash
# MACエイジング時間 (デフォルト300秒):
cat /sys/class/net/br0/bridge/ageing_time
echo 60 > /sys/class/net/br0/bridge/ageing_time   # 1分

# FDBの確認:
bridge fdb show br br0
bridge fdb add <MAC> dev eth0 master static       # 静的エントリ (老化しない)
```

### HairpinとBridge-NF

bridge-nf (ブリッジ上でのnetfilter): iptablesを、bridgeを通過するフレームに対して実行できる。重要なパス (`net/bridge/br_netfilter.c`):
- NF_BR_PRE_ROUTING: フレームがbridgeポートに刚到着した時点
- NF_BR_FORWARD: フレームが1つのポートから別のポートへ転送される時点
- NF_BR_POST_ROUTING: フレームがbridgeポートから送信される直前

これにより、bridge上でiptablesを使用して透明なファイアウォール/フィルタリング/ログ記録が可能だが、パフォーマンスオーバーヘッドが発生する。

## STP (802.1D)

ループの問題: 2つのスイッチ間に2本のケーブルがある場合 → ループ防止メカニズムがない → ブロードキャストフレームが無限ループ → ブロードキャストストーム → ネットワーク全体のパニック。

```
STPの核心: 生成木上で転送し、冗長リンクは待機状態（ブロック）にする

選挙:
  1. ルートブリッジ: 最小ブリッジID (優先度 + MAC)
  2. 各非ルートブリッジ: ルートポートを選択 (ルートへの最短パス)
  3. 各セグメント: 指定ポートを選択 (このセグメントの転送を担当)
  4. それ以外のポート → ブロック (転送せず、BPDUのみ受信)

BPDU (Bridge Protocol Data Unit):
  EtherType: 0x0026 (LLC) → DSAP/SSAP=0x42 (STP)
  2秒ごとに送信 (ハロータイマー)

STP BPDUの内容:
  プロトコルID: 0
  バージョン: 0 (STP) または 2 (RSTP)
  タイプ: 0 (構成BPDU) または 0x80 (TCN)
  フラグ: TC (トポロジー変更) + TCA (トポロジー変更確認)
  ルートID: 優先度 (2バイト) + MAC (6バイト)
  ルートパスコスト: (4バイト)
  ブリッジID: 優先度 + MAC
  ポートID: 優先度 (4ビット) + ポート番号 (12ビット)
  メッセージ年齢 / 最大年齢 / ハロータイム / フォワードディレイ

収容時間:
  STP: 30〜50秒 (リスニング→学習→転送、各段階15秒)
  RSTP (802.1w): 1〜3秒 (提案/合意メカニズム)
```

## VXLAN (RFC 7348)

### コア要件: データセンターにおけるL2拡張

VLANは12ビットのVIDしか持たないため、4094の分離ドメインしか提供できない。大規模データセンターではこれ以上の分離が必要（マルチテナント分離）。VXLANは24ビットのVNIを提供し、1600万の分離ドメインを実現する。

### 封装

```
VXLAN封装:
  [外側Ethernet][外側IP][外側UDP宛先ポート=4789][VXLANヘッダ 8バイト][内側Ethernet][内側IP][内側ペイロード]

VXLANヘッダ:
  フラグ (1バイト): ビット3 = I (VNI有効), ビット0-2/4-7 = 予約済み
  予約済み (3バイト): ゼロ
  VNI (3バイト): 仮想ネットワーク識別子 — 24ビット識別子
  予約済み (1バイト): ゼロ

なぜUDPを使うか:
  - ECMP: ルーターはUDP送信元ポート（エントロピー）に基づいてマルチパス負荷分散が可能
  - NAT透過: UDPはNATを通過可能（GRE/IPIPのように特別な処理が必要ない）
  - ファイアウォールフレンドリー: 宛先ポート=4789で固定 → ACL設定が容易
```

### VTEP

```
VTEP (VXLANトンネルエンドポイント):
  封装/解封装の接点 (Linux: vxlanデバイス)

  作成: ip link add vxlan100 type vxlan id 100 remote 10.0.0.2 dstport 4789 dev eth0

  転送ロジック:
    1. ローカルVMがフレーム送信 → bridgeがMAC参照 → 宛先MACがローカルにない？
    2. MACが別のVTEPにある場合 → FDB参照: MAC→リモートVTEP IP
    3. 封装: VXLANヘッダ + 外側IP/UDPを追加 → リモートVTEP IPへルーティング
    4. リモート側: vxlanデバイスが受信 → 解封装 → 外側ヘッダを削除 → bridge処理

  ARP抑制 (VXLANフラッディングの削減):
    VXLANにおけるマルチキャスト/ブロードキャストは全VTEPへ複製される必要がある → 帯域幅の無駄
    → VTEPでのARPプロキシ: ローカルで直接ARP応答 (ネットワークへのフラッディング不要)
    → L2-population: コントロールプレーン (例: Open vSwitch) から MAC→VTEP マッピングを学習
```

## 参考文献

- **IEEE**: 802.1D, 802.1w, 802.1Q
- **RFC**: 7348 (VXLAN), 7348 付録A (ARP抑制の推奨事項)
- **ソースコード**: `net/bridge/` (bridge + STP), `drivers/net/vxlan/` (VXLANドライバ)
- **LWN**: "VXLAN and overlay networks in the kernel"

*キーワード: MAC学習, FDB, Linux bridge, STP, RSTP, BPDU, VXLAN, VTEP, VNI, ARP抑制, オーバーレイネットワーク*
