LinuxでのVLAN 802.1Q設定ガイド:1枚の物理NICで複数のVLANをサブインターフェースとトランキングで実現する

Network tutorial - IT technology blog
Network tutorial - IT technology blog

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をトランクで共有する場合は特に重要になる。

Share: