Vlanタグの深淵を覗く:802.1Qがパケットに刻む「身分証」の正体
ネットワークエンジニアとして現場に立っていると、ふとした瞬間に「なぜ通信が繋がらないのか」という壁にぶち当たります。レイヤー2のトラブルは往々にして、目に見えない「タグ」が原因であることが多いものです。
特に IEEE 802.1Q は、現代の仮想化ネットワークやクラウド基盤を支える屋台骨でありながら、意外と「中身をちゃんと理解していない」というエンジニアが少なくありません。今日は、パケットがスイッチを渡り歩く際に挿入される、あの4バイトの「小さな身分証」について、現場の視点から紐解いていきましょう。
—
1. 4バイトの魔術:IEEE 802.1Qタグの構造
通常のイーサネットフレームに、突如として割り込む 4バイト の領域。これが 802.1Q タグです。送信元MACアドレスとタイプフィールドの間に挟み込まれるこの領域は、大きく分けて2つの要素で構成されています。
TPID (Tag Protocol Identifier):16ビット
値は常に 0x8100 です。これはスイッチに対して「このフレームにはタグが付いていますよ」と伝える合図です。もし上位の機器が 0x8100 を認識できなければ、それはただの「壊れたパケット」として破棄される運命にあります。
TCI (Tag Control Information):16ビット
ここがネットワークの「階級社会」を決定づける領域です。
- PCP (Priority Code Point):3ビット
CoS (Class of Service) とも呼ばれます。0〜7の8段階で、パケットの優先度を決定します。QoS(Quality of Service)の設計において、音声や映像など、遅延を許容できないトラフィックに高い値を割り当てるために使われます。
- DEI (Drop Eligible Indicator):1ビット
かつては CFI と呼ばれていました。輻輳が発生した際、「このパケットは捨ててもいいよ」というフラグを立てるためのものです。
- VID (VLAN Identifier):12ビット
VLANのIDです。 0 から 4095 までの値を持ち、 1 から 4094 が実用範囲です。これにより、物理的に同じスイッチを通る通信を論理的に切り分けます。
—
2. パケットの行方:トランクポートの舞台裏
Web APIを設計する際、L7(アプリケーション層)のエンジニアは「IPアドレスさえ合っていれば届く」と考えがちですが、インフラ側ではこのタグが剥がされたり(Untagged)、付けられたり(Tagged)しながらパケットが流れています。
特にトラブルの温床となるのは、「タグの付け忘れ」と「ネイティブVLANの不一致」です。
Linuxでタグを確認する
サーバーサイドエンジニアであれば、tcpdump を使って実際に流れているタグを覗いてみるのが一番の近道です。
# eth0インターフェースでVLANタグを含むパケットをキャプチャする
# -e オプションでリンク層ヘッダを表示させるのがコツです
tcpdump -i eth0 -e vlan
これで vlan 10 のような表示が出れば、そのパケットはタグ付きで流れています。もしここで何も表示されないのに通信が疎通しない場合、スイッチ側のポート設定が「Untagged(アクセスポート)」になっている可能性を疑ってください。
—
3. 実務で役立つ設定と検証のTips
クラウド環境やコンテナ基盤(Dockerのブリッジネットワークなど)では、このVLANタグが意識されないレベルで自動制御されていますが、物理アプライアンスやオンプレミスのルーターを触る際は、以下のような設定が必要になります。
Cisco IOS風の設定例
GigabitEthernet0/1 ポートをトランクポートとして設定し、VLAN 10と20を通す例です。
interface GigabitEthernet0/1
switchport trunk encapsulation dot1q ! 802.1Qを使用することを明示
switchport mode trunk ! トランクモードへ移行
switchport trunk allowed vlan 10,20 ! 必要なVLANのみを通す(セキュリティの鉄則)
Pythonでパケットを解析する(Scapy使用)
自動化ツールや監視スクリプトを書く際、Scapy は非常に強力です。
from scapy.all import sniff, Dot1Q
def packet_callback(packet):
# パケットが802.1Qタグを持っているかチェック
if packet.haslayer(Dot1Q):
vlan_id = packet[Dot1Q].vlan
priority = packet[Dot1Q].prio
print(f"VLAN ID: {vlan_id}, Priority: {priority}")
# ネットワークインターフェースを監視
sniff(iface="eth0", prn=packet_callback, filter="vlan")
—
4. 最後に:なぜ境界防御を知るべきか
ゼロトラストの時代においても、ネットワークレイヤーの基礎は変わりません。「境界」という概念が物理からIDベースに移行しても、パケットがスイッチという物理的(あるいは仮想的)な箱を通る際、その通信が適切に隔離・優先制御されているかを担保するのは、エンジニアの責任です。
Web APIのレスポンスが遅いと感じたとき、アプリケーションのコードだけを見ていては一生解決できない問題があります。そのパケットがどのVLANを通り、QoSでどう優先制御されているのか。その「通信の裏側」を想像できる力こそが、凄腕のエンジニアへの第一歩です。
現場のトラブルは、往々にして教科書に載っていない「設定の僅かな食い違い」から生まれます。ぜひ、今回の解説を足がかりに、ご自身の環境のネットワーク構成を見つめ直してみてください。それでは、また次回の深掘りでお会いしましょう。
コメント