802.1Qタグの心臓部「TCI」を読み解く:L2レイヤーでQoSとVLANを自在に操る技術
ネットワークの現場に身を置いていると、「なぜか特定のトラフィックだけ遅延する」「異なる部門間で通信が混ざってセキュリティ上の懸念がある」といったトラブルに幾度となく直面します。こうしたL2の混沌を整理し、現代の複雑なネットワーク基盤を支えている立役者こそ、今回スポットを当てる IEEE 802.1Q、そしてその中核である TCI(Tag Control Information) です。
教科書を開けば「16ビットのフィールドで構成され……」と無機質に書かれていますが、パケットキャプチャを開き、Wiresharkの生データを睨みながらデバッグを重ねてきたエンジニアなら、この16ビットがいかに機微に満ち、インフラ全体のパフォーマンスとセキュアなルーティングを左右する重要データである身をもって知っているはずです。
今回は、Web APIやクラウドインフラの設計・運用に携わるエンジニアの皆さんに向け、このTCIフィールドのディープな内部構造と、QoS(Quality of Service)およびVLAN(Virtual LAN)制御の実務的な仕組みを、現場の知見を交えて徹底解説します。
—
1. IEEE 802.1QとTCIフィールドの全体像
従来のフラットなイーサネットフレーム(Ethernet II)は、ブロードキャストドメインの肥大化や、優先度制御の欠如という致命的な弱点を抱えていました。これを解決するために登場したのがIEEE 802.1Qです。
標準的なイーサネットフレームの宛先MACアドレス(6バイト)と送信元MACアドレス(6バイト)の間に、4バイト(32ビット)の「Q-Tag」が挿入されます。
+---------------------+---------------------+-------------------+---------------------+
| 宛先MACアドレス | 送信元MACアドレス | TPID (0x8100) | TCI (16ビット) |
| (6 Bytes) | (6 Bytes) | (2 Bytes) | (詳細はこの下) |
+---------------------+---------------------+-------------------+---------------------+
このQ-Tagの前半2バイトは TPID(Tag Protocol Identifier) と呼ばれ、標準では 0x8100 が入り、「ここから先は802.1Qのタグが付いているぞ」とスイッチングHubやNICに告げるマジックナンバーとして機能します。
そして、その後続の残りの2バイト(16ビット)こそが、今回深掘りする TCI(Tag Control Information) です。
—
2. TCIを構成する3つの要素:PCP・DEI・VIDの正体
16ビットのTCIフィールドは、以下のように厳密にビット分割されています。
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PCP |D| VID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- PCP(Priority Code Point): 上位3ビット
- DEI(Drop Eligible Indicator): 1ビット(旧CFI)
- VID(VLAN Identifier): 下位12ビット
それぞれの役割と、現場でどう作用するかを紐解いていきましょう。
① PCP(Priority Code Point):3ビットのQoSプライオリティ
3ビットで表現できる数値は 0 から 7 までの8段階。IEEE 802.1pで規定されているこの値は、L2レイヤーにおけるクラス分け(Class of Service: CoS)の基盤となります。
音声や動画ストリーミング、あるいはWeb APIの超低遅延が求められる制御パケットに対して高い数値を割り当て、ベストエフォートのトラフィックと差別化します。
7: Network Control(ルーティングプロトコル等、最優先)6: Internetwork Control5: Voice(遅延にシビアな音声データ、推奨される値)4: Video(動画データ)3: Controlled Load2: スペア / 未使用1: Background(背景通信、ファイル転送など)0: Best Effort(デフォルト)
実務では、Cisco等のスイッチにおいて mls qos コマンドやポリシーマップを駆使し、IPヘッダーのToS/DiffServ(DSCP)値とこのPCP値を相互にマッピング(Trust設定)する設計が必須となります。
② DEI(Drop Eligible Indicator):1ビットの破棄優先度
かつてはCFI(Canonical Format Indicator)と呼ばれていた1ビットですが、現代のEthernet全盛の時代においては DEI として再定義されました。
0: 通常のフレーム(輻輳時も容易には破棄されない)- コールバックやネットワーク負荷が高い輻輳時において、このビットが
1に立っているフレームは「優先的に破棄してもよい(Drop Eligible)」とみなされ、QoSキューのバッファ溢れ対策として最初に切り捨てられます。
③ VID(VLAN Identifier):12ビットのVLAN ID
12ビットで表現できる数値は $2^{12} = 4096$。 0 (0x000) と 4095 (0xFFF) は予約されているため、実際にユーザーが利用できるのは 1 から 4094 までのVLAN IDです。
L2スイッチはこのVIDを見て、「どのポートのVLANグループにこのフレームを転送すべきか」をハードウェアレベル(ASIC)で超高速に判断しています。
—
3. 実務で遭遇するトラブルとデバッグ手順
インフラ構築やコンテナ(Docker/Kubernetes)のCNI(Container Network Interface)設定において、タグ付きパケット(Trunk)とタグなしパケット(Access)のミスマッチは障害の定番です。
例えば、ハイパーバイザーの仮想スイッチ(vSwitch)やLinuxのブリッジ設定でVLANのネイティブID(Native VLAN / PVID)がミスマッチを起こすと、予期せぬパケットの漏洩やループが発生します。
トラブルシューティングの鉄則
パケットが想定通りのVLAN IDやPCP値を持っているか確認するには、机上の空論ではなく、現場では tcpdump や tshark によるライブキャプチャが最も確実です。
# 特定のインターフェース(eth0)でIEEE 802.1Qタグを含むパケットをキャプチャし、詳細を表示する
sudo tcpdump -i eth0 -e -nn "vlan"
このコマンドの -e オプションが極めて重要で、これによってイーサネットヘッダー(MACアドレスやVLAN ID)が標準出力に露出します。出力結果の中に vlan 100 のような記述が見えれば、TCIのVID部分が正しく 0x064(10進数で100)として処理されている証拠になります。
—
4. インフラ・開発現場における設定とコード例
理論を学んだところで、実務でどのようにこの知識が活きるのか、具体的な設定ファイルやコードスニペットを見てみましょう。
A. Linux(iproute2)におけるVLANインターフェースの作成
物理NIC eth0 の上に、VID 200 を持つ仮想VLANインターフェース eth0.200 を立ち上げる実用スクリプト(Bash)です。
#!/bin/bash
# ネットワークインターフェースのVLANサブインタフェース作成スクリプト
PHYS_DEV="eth0"
VLAN_ID="200"
VLAN_DEV="${PHYS_DEV}.${VLAN_ID}"
echo "Creating VLAN interface ${VLAN_DEV} with VID ${VLAN_ID}..."
# 1. 物理インターフェースがDOWNしている場合はUPさせる
sudo ip link set dev ${PHYS_DEV} up
# 2. 802.1Q VLANデバイスの追加
sudo ip link add link ${PHYS_DEV} name ${VLAN_DEV} type vlan id ${VLAN_ID}
# 3. IPアドレスの割り当てとインターフェースの有効化
sudo ip addr add 192.168.200.10/24 dev ${VLAN_DEV}
sudo ip link set dev ${VLAN_DEV} up
echo "VLAN interface ${VLAN_DEV} is now active and ready."
B. Pythonを用いたネットワークプログラミングでの考慮点
通常のWebアプリケーション開発者(Web API設計など)が直接TCIを叩くことは稀ですが、DPDK(Data Plane Development Kit)や低レイヤーのパケットジェネレータ、SDN(Software-Defined Networking)のコントローラー(RyuやFloodlightなど)をPythonで実装する際には、イーサネットフレームの構築時にTCIを明示的に埋め込む必要があります。
以下は、Pythonの scapy ライブラリを用いて、VIDとPCP(QoS優先度)を指定したカスタムイーサネットフレームを構築・送信するスニペットです。
from scapy.all import Dot1Q, Ether, IP, TCP, sendp
# 宛先・送信元MACアドレスの設定
dst_mac = "52:54:00:12:34:56"
src_mac = "52:54:00:65:43:21"
# 1. イーサネットフレームの基本構築
eth = Ether(dst=dst_mac, src=src_mac)
# 2. 802.1Qタグの付与 (TCIの組み立て)
# prio=5 -> PCPに上位3ビットを設定 (音声クラス等の高優先度)
# vlan=100 -> VIDに下位12ビットを設定 (VLAN 100)
dot1q = Dot1Q(prio=5, vlan=100)
# 3. ペイロード(IPパケットやTCPなど)の結合
ip = IP(dst="192.168.100.50")
tcp = TCP(dport=443, sport=55555, flags="S")
# フレーム全体の結合(Ether / Dot1Q / IP / TCP)
packet = eth / dot1q / ip / tcp
print(f"[*] Sending tagged packet with PCP={dot1q.prio}, VID={dot1q.vlan}...")
# 物理インターフェース(例: eth0)からレイヤー2パケットとして送出
# ※実行にはroot権限が必要です
try:
sendp(packet, iface="eth0", verbose=False)
print("[+] Packet transmitted successfully.")
except Exception as e:
print([-] Failed to transmit packet: {e})
このコードを実行すると、送出されるパケットのTCIフィールドには、PCP 5(バイナリ 101)とVID 100(バイナリ 000001100100)が正確に合成された16ビット値が書き込まれ、スイッチ側でQoSとVLANの二重の制御を受けることになります。
—
5. まとめ
IEEE 802.1QのTCIフィールド(PCP・DEI・VID)は、わずか16ビットという極めて小さな領域でありながら、現代の大規模ネットワークの「セキュリティの分離(VLAN)」と「品質保証(QoS)」の双方を司る極めて重要なキーパーツです。
インフラエンジニアであれ、クラウドネイティブな環境でネットワークの底辺を支える開発者であれ、パケットがワイヤー上を流れる際にこの16ビットがどのように解釈されているかをイメージできるかどうかが、トラブルシューティングのスピードや、堅牢なネットワークアーキテクチャ設計の明暗を分けます。
次にネットワークの遅延やルーティングの不整合に直面したときは、ぜひコマンドやコードの表面だけでなく、パケットの深層にあるこの「16ビットの物語」に思いを馳せてみてください。きっと、問題解決への最短ルートが見えてくるはずです。
コメント