ネットワークの海を漂うパケットの挙動に思いを馳せる日々、皆さんはいかがお過ごしでしょうか。シニアネットワークエンジニアの私です。
Web APIの設計やモダンなクラウドインフラの構築において、私たちは日々「アプリケーション層」の美しさに酔いしれがちです。しかし、その背後でJSONやgRPCのペイロードを包み込み、ミリ秒単位の狂いもなくdestinationへと運び去っているのは、泥臭いレイヤー2およびレイヤー3の物理・論理のルールに他なりません。
今回は、そんなネットワークの基礎でありながら、小規模から中規模のネットワーク設計において今なお現役で暴れ回る「Router-on-a-Stick(スティックルーター方式)」を取り上げます。IEEE 802.1Qのトランクリンク、サブインターフェース、そしてパケットカプセル化の深淵を覗いてみましょう。
—
1. なぜRouter-on-a-Stickなのか? その思想と背景
仮想LAN(VLAN)は、物理的なスイッチのポート構成に縛られることなく、ブロードキャストドメインを論理的に分割するための強力なL2技術です。しかし、異なるVLANに属するホスト同士が通信(例えば、VLAN 10のWebサーバーから、VLAN 20のDBサーバーへのAPIリクエスト)を行うためには、原則としてL3デバイスであるルーターによるルーティングが必要です。
理想を言えば、VLANごとにルーターの物理インターフェースを1つずつ割り当てたいところですが、コストやポート数の制約、そしてハードウェア資源の観点からそれは非現実的です。
そこで登場するのが、Router-on-a-Stickです。
1本の物理ケーブル(およびスイッチのトランクポート)の上に複数のVLANトラフィックを多重化し、ルーター側の1つの物理インターフェースを論理的な「サブインターフェース」に分割してルーティングを行わせます。文字通り、1本の「棒(Stick)」にルーターをぶら下げるようなコンパクトな構成です。
—
2. パケットの旅:IEEE 802.1Qカプセル化の仕組み
では、VLAN間をパケットが移動するとき、ワイヤー上では何が起きているのでしょうか。ここで鍵となるのが、IEEE 802.1Q規格によるタグ付け(Tagging)です。
通常のイーサネットフレーム(Ethernet II)の中に、4バイトの「VLANタッグ(TPID + TCI)」が挿入されることで、スイッチやルーターはそのフレームがどのVLANに属しているかを識別します。
通信シーケンスの全体像
VLAN 10(IP: 192.168.10.10)のクライアントから、VLAN 20(IP: 192.168.20.20)のサーバーへリクエストが飛ぶ際のパケットの挙動を追ってみましょう。
1. ホストAの送信:
クライアント(VLAN 10)は、宛先IPが別サブネットであることを検知し、デフォルトゲートウェイ(ルーターのサブインターフェースIP)宛てにイーサネットフレームを作成します。この時点では、フレームにVLANタグはついていません(アクセスポート接続のため、スイッチが内側で付与します)。
2. スイッチのトランクポート:
スイッチは、VLAN 10のアクセスポートから受け取ったフレームに VLAN ID = 10 の802.1Qタグを付与し、Router-on-a-Stick用のトランクポートへと送り出します。
3. ルーターのサブインターフェースでの受信・カプセル化解除(Decapsulation):
ルーターは GigabitEthernet0/0.10 というサブインターフェースでこのフレームを受け取ります。ここで VLAN ID = 10 のタグが剥がされ、L3パケットとしてルーティングエンジンに渡されます。
4. ルーティングと再カプセル化(Encapsulation):
ルーターはルーティングテーブルを参照し、宛先が 192.168.20.0/24 であることを確認。今度は GigabitEthernet0/0.20 サブインターフェースへとパケットをルーティングします。その際、新しく VLAN ID = 20 の802.1Qタグを付与してフレームを再構築します。
5. スイッチからサーバーへ:
スイッチのトランクポートを経由してVLAN 20のアクセスポートに到達する際、タグが外され、プレーンなイーサネットフレームとしてサーバー(VLAN 20)に届きます。
—
3. 実践:Ciscoルーターとスイッチの設定例
現場で最も遭遇するCisco IOS環境をベースに、具体的なコンフィギュレーションを見ていきましょう。
ここでは、ルーターの物理インターフェース GigabitEthernet0/0 を使って、VLAN 10(Web)とVLAN 20(DB)を収容します。
ルーター側の設定(Router-on-a-Stick)
! 物理インターフェース自体のIPアドレスは設定せず、no shutdownだけを行う
interface GigabitEthernet0/0
no ip address
no shutdown
! VLAN 10用のサブインターフェース定義
interface GigabitEthernet0/0.10
description Web Server Network
encapsulation dot1Q 10 ! IEEE 802.1Qカプセル化を指定し、VLAN ID 10を紐付け
ip address 192.168.10.1 255.255.255.0
! VLAN 20用のサブインターフェース定義
interface GigabitEthernet0/0.20
description Database Server Network
encapsulation dot1Q 20 native ! 必要に応じてnativeVLANの指定も可能だが基本はVLAN ID指定
ip address 192.168.20.1 255.255.255.0
スイッチ側の設定(トランクポートとアクセスポート)
! ルーターと接続するポートをトランクモードに設定
interface GigabitEthernet0/1
switchport trunk encapsulation dot1q
switchport mode trunk
switchport nonegotiate
no shutdown
! VLAN 10のホストが接続されるポート
interface GigabitEthernet0/2
switchport mode access
switchport access vlan 10
spanning-tree portfast
no shutdown
! VLAN 20のホストが接続されるポート
interface GigabitEthernet0/3
switchport mode access
switchport access vlan 20
spanning-tree portfast
no shutdown
—
4. 現場の罠:Router-on-a-Stickの致命的なボトルネック
ここまで美しく完結しているRouter-on-a-Stickですが、シニアエンジニアとして声を大にして警告しておきたいのが、「ボトルネック問題」です。
1本の物理リンクがすべてのVLAN間トラフィックを背負う
ルーターとスイッチの間を結ぶ物理リンクは1本だけです。仮にギガビットイーサネット(1Gbps)を採用していた場合、VLAN 10とVLAN 20の間で大量のデータ同期や、重いWeb APIのレスポンスやり取りが発生すると、双方向(Full-Duplex)であっても最大1Gbpsの帯域をすべてのVLANで奪い合うことになります。
CPUベースのパケット処理
L3スイッチ(MLS: Multilayer Switch)によるハードウェア(ASIC)ベースのルーティングとは異なり、一般的なルーターのサブインターフェース処理はCPUに負荷をかけます。パケット数(PPS: Packets Per Second)が増大すると、ルーターのCPU使用率が跳ね上がり、レイテンシーの悪化やパケットロスを引き起こします。
—
5. デバッグと検証:パケットの往来を確認する
もし「VLAN間の通信ができない」「APIリクエストがタイムアウトする」というトラブルシューティングに直面したら、以下の手順でデバッグを行います。
1. ルーターでのパケットキャプチャ(Cisco Embedded Packet Capture: EPC)
現場で「本当にパケットがルーターまで届いているか?」を確かめる最も確実な方法です。
! キャプチャバッファの定義
monitor capture buffer BUF size 2048 max-packet 128 linear
! キャプチャポイントの定義(受信・送信インターフェースを指定)
monitor capture point ip int Gi0/0.10 both
! バッファとポイントの関連付け
monitor capture point associate BUF Gi0/0.10
! キャプチャの開始
monitor capture point start all
! --- ここでテスト通信(pingやcurl等)を実行 ---
! キャプチャ結果の確認
show monitor capture buffer BUF dump
! キャプチャの停止と解放
monitor capture point stop all
no monitor capture point all
no monitor capture buffer BUF
2. アプリケーション層からの疎通確認(Pythonコード例)
インフラが正しくルーティングされているかを検証するために、Pythonの requests ライブラリを用いて、異なるVLAN間のAPIエンドポイントに対して定期的にリクエストを送り、ステータスコードとレイテンシーを計測するスクリプトの例です。
import time
import requests
from requests.exceptions import RequestException
# 宛先APIサーバーのエンドポイント(VLAN 20に属するサーバー)
API_ENDPOINT = "http://192.168.20.20/api/v1/health"
def check_inter_vlan_route():
print(f"[*] Starting Inter-VLAN routing check to {API_ENDPOINT}...")
for i in range(1, 6):
try:
start_time = time.time()
# タイムアウトを3秒に設定してリクエスト送信
response = requests.get(API_ENDPOINT, timeout=3.0)
elapsed_time = (time.time() - start_time) * 1000 # ミリ秒変換
print(f"[{i}] Status: {response.status_code} | Latency: {elapsed_time:.2f} ms")
except RequestException as e:
print(f"[{i}] ERROR: Failed to reach destination through Router-on-a-Stick -> {e}")
time.sleep(1)
if __name__ == "__main__":
check_inter_vlan_route()
—
まとめ
Router-on-a-Stickは、限られたハードウェア資源の中でVLAN間の壁を軽々と越えさせる、非常にエレガントな設計手法です。しかし、その裏側ではIEEE 802.1Qによる厳密なタグの付与と剥離が行われており、物理リンクの帯域とルーターのCPUという物理的な限界と常に隣り合わせであることを忘れてはなりません。
モダンな大規模環境ではレイヤー3スイッチによるSVI(Switched Virtual Interface)やルーテッドポートへ移行すべきですが、小規模拠点やコスト制約の厳しい環境では、今なおエンジニアの強力な味方です。
ネットワークの背後でパケットがどのようにカプセル化され、どこを通って流れていくのか――その一連のストーリーを頭の中に描けるようになると、インフラのトラブルシューティングはぐっと面白くなります。次のシステム設計や障害対応の現場で、ぜひこの知識を役立ててください。
コメント