パケットの裏側を覗き見ろ!IEEE 802.1Q VLANタグ構造とTPID・TCIの深層解説
ネットワークエンジニアとして現場に立っていると、「VLANなんてスイッチの設定画面で vlan 10 と打ってポートを割り当てれば終わりだろ」と思っている若いエンジニアにしばしば出会う。
だが、ちょっと待ってほしい。
クラウド全盛の今、Web APIやコンテナ、仮想化基盤の設計に携わるエンジニアであっても、一度トラブルシューティングの泥沼にハマれば、パケットキャプチャの画面に現れる呪文のような16進数の羅列と格闘しなければならない瞬間が必ずやってくる。
今回は、スイッチのポートを流れるイーサネットフレームの姿かたちを根本から変える、IEEE 802.1QのVLANタギング、その心臓部である TPID と TCI の構造にスポットを当てる。
パケットが物理ワイヤーをどのように駆け抜け、スイッチのASICがどうやってそれを処理しているのか、そのリアルな挙動を紐解いていこう。
—
1. なぜVLANタグが必要なのか?:イーサネットの限界と802.1Qの誕生
レガシーなイーサネット(IEEE 802.3)のフレーム構造は非常にシンプルだ。
宛先MACアドレス、送信元MACアドレス、そして「おや?」と思わせるタイプ/長さフィールド、データ、FCS(フレームチェックシーケンス)が続く。ここに「仮想的にネットワークを分割したい」という要件を持ち込んだとき、フレームの中に所属するグループ(VLAN ID)の情報を埋め込む必要が生じた。
そこで登場したのが、1998年にIEEEで策定された IEEE 802.1Q だ。
既存のイーサネットフレームの構造を完全に破壊することなく、MACアドレスの直後に「タグ」と呼ばれる4オクテット(32ビット)の領域をこっそり挿入することで、L2スイッチの世界を劇的に拡張した。
しかし、この4オクテットの挿入によって、最大フレームサイズ(MTU)の制限である1500バイトが1504バイトに膨れ上がる(Q-in-Qなどの多重タギングを含めればさらに増える)。この「ベビー・ジャイアント・フレーム」を許容できない古いネットワーク機器やNICが原因で、現場では数々の奇怪な通信断トラブルを引き起こしてきた。歴史とは常に、こうした「1バイトの拡張」の積み重ねなのだ。
—
2. 802.1Qタグの内部構造:TPIDとTCIの正体
IEEE 802.1Qタグの4オクテット(32ビット)は、大きく2つのフィールドに分けることができる。前半の2オクテットが TPID、後半の2オクテットが TCI だ。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TPID (16 bits) | TCI (16 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
それぞれのフィールドが持つ意味を、実務的な視点で深掘りしていこう。
TPID (Tag Protocol Identifier) : 16ビット
- 標準値:
0x8100
TPIDは、この直後に続くフレームがIEEE 802.1QのVLANタグ付きフレームであることを示す「目印(マジックナンバー)」だ。
通常の非タグ(Untagged)フレームであれば、宛先MACアドレス(6バイト)と送信元MACアドレス(6バイト)の直後には、0x0800(IPv4)や ಮಹತ್ 0x86DD(IPv6)といったEtherTypeが来る。
しかし、スイッチやNICが受信したデータの位置に 0x8100 を検知すると、ハードウェア(ASIC)は瞬時に「お、これはVLANタグ付きフレームだな」と判断し、次の2オクテットをTCIとして解釈モードに入る。
> 実務でのTips:
> プロバイダ網などで使われるQ-in-Q(IEEE 802.1ad)環境では、外側のタグのTPIDとして 0x88A8 などが使われる。Wiresharkなどでパケットキャプチャを見た際、このTPIDが想定外の値(例えばCisco独自の 0x9100 や古い機器の独自実装)になっていると、スイッチ間でタグが正しく解釈されず、ネイティブVLAN以外がすべてブラックホールに消えるという古典的かつ厄介な障害に直面することになる。
TCI (Tag Control Information) : 16ビット
TCIは、実際のVLAN制御情報を詰め込んだ16ビットのコンテナだ。内部はさらに3つのサブフィールドに分かれている。
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|PCP|C| VID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1. PCP (Priority Code Point) : 3ビット
- QoS(Quality of Service)のための優先度制御(CoS: Class of Service)に使われる。
000(最低、ベストエフォート)から111(最高、ネットワーク制御用)までの8段階があり、VoIPや動画ストリーミングなどの遅延にシビアなトラフィックを優先転送させるために用いられる。
2. CFI (Canonical Format Indicator) / DEI (Drop Eligible Indicator) : 1ビット
- 以前はCFIと呼ばれ、Token Ringなどのアーキテクチャとの互換性を示していたが、現代のイーサネットではほぼ
0(Canonical)固定である。 - 現在の規格(IEEE 802.1ahなど)では DEI (Drop Eligible Indicator) と再定義され、輻輳時にこのビットが立っているフレームを優先的に破棄してよいというマーキングとして使われる。
3. VID (VLAN Identifier) : 12ビット
- 実務で最も馴染み深い、VLANのIDそのものだ。
1から4094までの数値(0と4095は予約済み)を表現できる。2の12乗=4096個の空間を作り出す、まさに仮想ネットワークの基礎である。
—
3. スイッチングの現場:フレームの動きとトランクポートの挙動
では、このVLANタグが実際のネットワーク機器の間をどのように流れていくのか、通信フローを見てみよう。
[Server A (VLAN 10)]
│ (Untagged)
▼
[Access Port (Switch A)] ──(802.1Q Tagged: VID 10)──> [Trunk Port]
│
▼
[Trunk Port (Switch B)]
│ (Untagged)
▼
[Access Port] ──> [Server B (VLAN 10)]
1. アクセスポートへの流入:
端末(サーバーやPC)は通常、VLANの概念を持たないため、送出するイーサネットフレームは「タグなし(Untagged)」である。
スイッチのアクセスポートがこれを受信すると、ポート設定に基づいて自分の脳内(設定)でそのフレームに特定のVLAN ID(例:VLAN 10)を紐付ける。
2. トランクポートからの送出:
スイッチ間を接続するトランクポートを通る際、スイッチのASICはフレームのMACアドレスの直後に、0x8100 のTPIDと、VID 10 が書き込まれたTCIを合体させた 4バイトのタグを挿入(タグ付け) してワイヤー上に送り出す。
3. 対向スイッチでの受信と剥離:
対向のスイッチのトランクポートがこのタグ付きフレームを受信する。ASICはTPID 0x8100 を検知し、TCIからVID 10 を読み取る。宛先ポートが同じVLAN 10のアクセスポートであれば、タグを綺麗に剥ぎ取って(Untaggedにして) 端末へと送り出す。
この一連の動作が、ハードウェア(ASIC)レベルでラインレート(回線速度の限界)にてミリ秒単位以下のレイテンシで実行されている。これこそが、スイッチングハブが単なる「中継器」ではなく「知的なL2デバイス」たる所以だ。
—
4. 実務で役立つ設定とデバッグの作法
インフラエンジニアとして、この802.1Qの仕組みを意識しなければならないシーンは、トラブルシューティングの現場だけではない。例えば、Linuxサーバー上で仮想マシンやコンテナ(Dockerなど)に直接VLANを収容するような設計・構築を行う際にも、この知識は不可欠だ。
以下に、Linux(RHEL / Ubuntu系)のネットワーク設定ファイル(Netplan形式)と、パケットキャプチャを検証するためのPythonスクリプトの例を示す。
設定例:Linuxにおける802.1Qサブインターフェースの構築 (Netplan)
物理NICである eth0 の上で、VLAN ID 100 のタグ付きトラフィックを終端させる設定例だ。
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: no
# 物理インターフェース自体にはIPを持たせず、トランクとして機能させる
vlans:
eth0.100:
id: 100
link: eth0
addresses:
- 192.168.100.10/24
gateway4: 192.168.100.1
nameservers:
addresses:
- 8.8.8.8
> インフラ運用の知見:
> この設定を投入した後、もし通信ができなくなった場合は、対向のCiscoやYAMAHAなどのスイッチ側で switchport trunk allowed vlan add 100 が正しく設定されているか、あるいはネイティブVLANのミスマッチ(Native VLAN Mismatch)が起きていないかを疑うべきだ。タグなしで送られてきたパケットをスイッチがどのVLANとして処理するのかの認識違いは、レイヤー2における最も古典的かつ頻発する障害の一つである。
デバッグ例:PythonとScapyによる802.1Qフレームの構築と解析
ネットワークプログラミングやセキュリティ診断において、意図的にVLANタグを付与したパケットを生成したい場合がある。Pythonの強力なパケット操作ライブラリ Scapy を使えば、TPIDとTCIを自由自在に操ったフレームを作成・送信できる。
from scapy.all import Ether, Dot1Q, IP, ICMP, sendp
# 1. イーサネットヘッダーの作成
# 2. Dot1QレイヤーでVLAN ID(VID)とPCP(優先度)を指定する
# (ScapyのDot1Qレイヤーは内部で自動的にTPID '0x8100' を付与する)
packet = (
Ether(dst="ff:ff:ff:ff:ff:ff", src="00:11:22:33:44:55")
/ Dot1Q(vlan=100, prio=3) # VLAN ID: 100, PCP: 3 (高優先度)
/ IP(dst="192.168.100.254")
/ ICMP()
)
# 3. 物理インターフェース(例: eth0)からレイヤー2パケットとして送出
print(
"[*] VLAN 100のタグ付きICMPパケットを構築し、eth0から送出します..."
)
try:
sendp(packet, iface="eth0", verbose=False)
print("[+] パケットの送信に成功しました。")
except Exception as e:
print(f"[-] エラーが発生しました: {e}")
このようなスクリプトを書いて実際にパケットを飛ばし、Wiresharkや tcpdump -nnvvv -i eth0 vlan などのコマンドでキャプチャ結果を眺めてみるとよい。
パケットのdump結果に 802.1Q Virtual LAN、ID: 100、Priority: 3 といった文字列が綺麗に浮かび上がってくるのを確認できた瞬間、ネットワークの解像度が一段と跳ね上がるはずだ。
—
5. おわりに:パケットが見えるエンジニアになれ
クラウドやコンテナ技術の発展により、現代のアプリケーションエンジニアやインフラエンジニアは、物理的なスイッチやVLANタグの存在を意識せずともシステムを構築できるようになった。
しかし、ひとたび「なぜかパケットがドロップする」「マルチテナント環境で異音(意図せぬ通信の混入)がする」という深層のトラブルに直面したとき、最後に頼りになるのは、教科書的な知識ではなく、パケットの1バイト1バイトがたどる挙動を頭の中で正確にトレースできる「エンジニアとしての勘と洞察力」だ。
IEEE 802.1Qの TPID と TCI。
たった4オクテットの小さな世界だが、そこにはネットワーク設計の美しさと、現場の泥臭い歴史がぎっしりと詰まっている。この構造を血肉にしたあなたなら、もうどんな難解なL2トラブルが目の前に現れても、臆することなくパケットアナライザを開き、冷静に真実を暴き出せるはずだ。
コメント