50人規模のオフィスのネットワーク管理をしていて、何度も遭遇した場面がある。管理スイッチで部署ごとにVLANを分割し——経理部がVLAN 10、ITがVLAN 20、サーバーがVLAN 30——しかしLinuxゲートウェイサーバーには物理NICが1枚しかなく、スイッチに接続されているだけ。追加NICなしで、そのサーバーから3つのVLANすべてを同時に見えるようにするにはどうすればいいか?
VLAN 802.1Qサブインターフェースは、まさにこの問題を解決するために生まれた。N個のVLANにN枚のNICが必要なのではなく、スイッチ側でトランクポートを1つ用意して、Linux側で正しく設定するだけでいい。
現実の問題:なぜ通常の方法ではNIC1枚では足りないのか
ネットワーク管理を始めたばかりのsysadminの多くは、「VLANが1つ=NICが1枚」という発想で考える。その方法でも動くが、スケールしない——サーバーのNICポートは通常2〜4個しかないのに、本番環境では5〜10個以上のVLANが必要になることは珍しくない。
管理スイッチはトランクポートという仕組みをサポートしている。アクセスポートが1つのVLANしか通さないのに対し、トランクポートはIEEE 802.1Q規格に従って各EthernetフレームにVLAN IDをタグ付けする。Linuxはこのタグ付きフレームを受け取り、VLAN IDを解析して、対応するサブインターフェースに転送する。
実際にこの方法を使っているユースケースは以下の通りだ:
- 複数の内部VLANのルーター/ゲートウェイとして動くサーバー
- VMにVLANをパスする必要があるKVM/ProxmoxハイパーバイザーVM
- 複数のネットワークセグメントのトラフィックを監視するモニタリングサーバー
- マルチVLANを処理するソフトウェアファイアウォール(nftables、iptables)
設定に入る前に理解しておくべき基本概念
802.1Qフレームタギングの仕組み
IEEE 802.1Q規格はEthernetフレームに4バイトのヘッダーを追加し、その中にVLAN ID(12ビット、範囲1〜4094)が格納される。タグのないフレームをuntagged(ネイティブVLAN)、タグ付きフレームをtaggedと呼ぶ。
アクセスポートはエンドデバイス(PC、プリンターなど)に送信する際にタグを外す。トランクポートはフォワード時にタグをそのまま保持する——Linuxサーバーに接続するのはこちらのポートだ。
Linux上のサブインターフェース
Linuxは物理インターフェースenp3s0に紐付けられたenp3s0.10のような仮想インターフェースを作成する——各VLANを同じケーブル上の「専用チャンネル」とイメージするとわかりやすい。カーネルモジュール8021qがタグ付け/タグ外しを自動で処理する。enp3s0.10経由でパケットを送信するとカーネルがフレームにVLAN 10のタグを付加し、enp3s0上でタグ10のフレームを受信するとカーネルがenp3s0.10に転送する。
実践:VLANサブインターフェースをステップごとに設定する
ステップ1:カーネルモジュール8021qの確認
# モジュールがロードされているか確認
lsmod | grep 8021q
# 出力がなければ手動でモジュールをロード
sudo modprobe 8021q
# 起動時に自動ロードするよう設定
echo "8021q" | sudo tee /etc/modules-load.d/8021q.conf
Ubuntu 20.04+、Debian 11+、Rocky Linux 8+ではこのモジュールがカーネルに標準搭載されている——追加パッケージのインストールは不要だ。
ステップ2:物理インターフェースの特定と準備
# 現在のインターフェース一覧を表示
ip link show
# 出力例:
# 2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
# link/ether 00:1a:2b:3c:4d:5e brd ff:ff:ff:ff:ff:ff
物理インターフェースがenp3s0で、スイッチのトランクポートにVLAN 10(経理)、20(IT)、30(サーバー)が設定されているとする。
重要な注意事項:物理インターフェースはUP状態にしておく必要があるが、IPアドレスは割り当てない。IPはサブインターフェースに割り当てる——物理インターフェースにではない。最初にこのミスをして、両方にIPを割り当てた結果、パケットルーティングが混乱してデバッグが非常に困難になった経験がある。
# 物理インターフェースをUPにする(IPは割り当てない)
sudo ip link set enp3s0 up
ステップ3:VLANサブインターフェースの作成(テスト用の一時設定)
# VLAN 10用のサブインターフェースを作成してIPを割り当てる
sudo ip link add link enp3s0 name enp3s0.10 type vlan id 10
sudo ip addr add 192.168.10.1/24 dev enp3s0.10
sudo ip link set enp3s0.10 up
# VLAN 20
sudo ip link add link enp3s0 name enp3s0.20 type vlan id 20
sudo ip addr add 192.168.20.1/24 dev enp3s0.20
sudo ip link set enp3s0.20 up
# VLAN 30
sudo ip link add link enp3s0 name enp3s0.30 type vlan id 30
sudo ip addr add 192.168.30.1/24 dev enp3s0.30
sudo ip link set enp3s0.30 up
# すぐに確認する
ip addr show | grep -A3 "enp3s0\."
# カーネルが認識しているVLANの詳細を確認
cat /proc/net/vlan/config
/proc/net/vlan/configの出力はこのようになる:
VLAN Dev name | VLAN ID
Name-Type: VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD
enp3s0.10 | 10 | enp3s0
enp3s0.20 | 20 | enp3s0
enp3s0.30 | 30 | enp3s0
ステップ4:Netplanで永続化設定する(Ubuntu 20.04+)
ipコマンドによる設定は一時的なもので、再起動すると消えてしまう。永続化するにはNetplanファイルを作成する:
# /etc/netplan/01-vlan.yaml
network:
version: 2
ethernets:
enp3s0:
dhcp4: false
dhcp6: false
vlans:
enp3s0.10:
id: 10
link: enp3s0
addresses: [192.168.10.1/24]
enp3s0.20:
id: 20
link: enp3s0
addresses: [192.168.20.1/24]
enp3s0.30:
id: 30
link: enp3s0
addresses: [192.168.30.1/24]
# 設定を適用する
sudo netplan apply
# 確認する
ip link show type vlan
ステップ5:NetworkManagerで永続化設定する(RHEL/CentOS/Rocky)
# nmcliでVLAN接続を作成する
nmcli connection add type vlan con-name vlan10 dev enp3s0 id 10 \
ip4 192.168.10.1/24
nmcli connection add type vlan con-name vlan20 dev enp3s0 id 20 \
ip4 192.168.20.1/24
nmcli connection add type vlan con-name vlan30 dev enp3s0 id 30 \
ip4 192.168.30.1/24
# 有効化する
nmcli connection up vlan10
nmcli connection up vlan20
nmcli connection up vlan30
ステップ6:VLAN間ルーターとして使う場合はIPフォワーディングを有効化する
このLinuxサーバーをゲートウェイとして——VLAN間のトラフィックをルーティングする場合——IPフォワーディングを有効化する必要がある:
# 永続化:/etc/sysctl.confに追加する
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# 確認する
sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 1
ステップ7:動作確認とトラブルシューティング
# VLAN 10内のマシンからゲートウェイアドレスにpingを試みる
ping 192.168.10.1
# パケットをキャプチャして802.1Qタグ付きフレームかどうかを確認する
# -eフラグでEthernetヘッダーを表示——出力に"vlan 10"が表示されるはず
sudo tcpdump -i enp3s0 -e vlan
# 特定のVLAN IDでフィルタリングする
sudo tcpdump -i enp3s0 vlan 10
サブインターフェースがパケットを受信しない?最もよくある原因はスイッチのトランク設定が正しくないことだ。スイッチ側を確認しよう:
# Cisco IOS — サーバー接続ポートをトランクに設定する
# switchport mode trunk
# switchport trunk allowed vlan 10,20,30
# HP/Aruba ProCurve
# vlan 10,20,30 tagged A1
# Mikrotik (RouterOS)
# /interface bridge vlan add bridge=bridge1 vlan-ids=10,20,30 tagged=ether1
データセンター管理の現場から学んだこと
初心者がよくつまずくポイントがMTUだ。802.1Q規格はフレームヘッダーに4バイトを追加する。スイッチやアップリンクでジャンボフレームを設定していない場合、1497バイト以上のパケットが明確なエラーメッセージなしにフラグメント化される——これは非常にデバッグが難しい。必要に応じてMTUを確認・調整しよう:
# サブインターフェースのデフォルトMTUは通常、物理インターフェースと同じ(1500)
ip link show enp3s0.10
# 大きなフレームで問題が発生する場合は、MTUを下げてみる
sudo ip link set enp3s0.10 mtu 1496
# Netplanの場合、各vlanエントリにmtuを追加する:
# enp3s0.10:
# id: 10
# link: enp3s0
# mtu: 1496
# addresses: [192.168.10.1/24]
私が管理している小規模データセンターでは、KVMホストの1つのインターフェース上でこの設定が数十のVLAN(管理VLAN、ストレージ、本番、DMZ)に対して安定稼働している。追加NICは一切不要で、PCIeスロットも節約でき、ケーブル配線も大幅にすっきりした。
最後にもう一点:サブインターフェースの命名は<physical>.<vlan-id>形式(例:enp3s0.10)が最も一般的で読みやすい。vlan-accountingのような任意の名前を付けることもできるが、深夜2時にデバッグするとき、enp3s0.10という名前のほうがはるかにわかりやすい。
まとめ
振り返ってみると、このセットアップは多くの人が思うよりずっとシンプルだ。追加ハードウェア不要、特殊なドライバーも不要、カーネルがモジュール8021qでネイティブサポートしている。覚えておくべき核心は:物理インターフェースにはIPを割り当てない、正しいVLAN IDでサブインターフェースを作成する、スイッチ側は対象VLANを許可したトランクポートにする——この3点だ。
VLANの数が増えるにつれて、NetplanやNetworkManagerを使った設定は手作業のスクリプトと比べて管理・監査がはるかに容易になる。次の自然なステップはnftablesを追加してVLAN間のトラフィックを制御することだ——本番環境とDMZが同じNICをトランクで共有する場合は特に重要になる。

