Hướng dẫn cấu hình VLAN 802.1Q trên Linux: Thiết lập Sub-interface và Trunking nhiều VLAN trên cùng một card mạng vật lý

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

Có một tình huống mình đã gặp không ít lần khi quản lý network cho văn phòng 50 người: switch managed đã chia VLAN cho từng phòng ban — kế toán VLAN 10, IT VLAN 20, server VLAN 30 — nhưng server Linux gateway chỉ có một card mạng vật lý nối lên switch. Làm sao để server đó nhìn thấy cả ba VLAN cùng lúc mà không cần cắm thêm NIC?

VLAN 802.1Q sub-interface sinh ra để giải quyết đúng bài toán này. Thay vì cần N card mạng cho N VLAN, chỉ cần một cổng trunk trên switch và cấu hình đúng trên Linux.

Vấn đề thực tế: tại sao một NIC không đủ theo cách thông thường

Hầu hết sysadmin khi mới quản lý network đều nghĩ theo kiểu: 1 VLAN = 1 card mạng. Cách đó hoạt động được, nhưng không scale — server thường chỉ có 2–4 cổng NIC trong khi môi trường production dễ cần 5–10 VLAN trở lên.

Switch managed hỗ trợ cơ chế trunk port: thay vì chỉ cho qua một VLAN (access port), cổng trunk đánh dấu (tag) mỗi Ethernet frame với VLAN ID theo chuẩn IEEE 802.1Q. Linux nhận frame tagged này, phân tích VLAN ID, rồi chuyển lên đúng sub-interface tương ứng.

Trong thực tế mình dùng cách này cho:

  • Server làm router/gateway cho nhiều VLAN nội bộ
  • Hypervisor KVM/Proxmox cần pass VLAN xuống VM
  • Monitoring server cần giám sát traffic trên nhiều segment
  • Firewall phần mềm (nftables, iptables) xử lý multi-VLAN

Khái niệm cốt lõi trước khi bắt tay cấu hình

802.1Q frame tagging hoạt động thế nào

Chuẩn IEEE 802.1Q thêm một header 4 byte vào Ethernet frame, trong đó chứa VLAN ID (12 bit, range 1–4094). Frame chưa được tag gọi là untagged (native VLAN), frame đã có tag gọi là tagged.

Switch access port gỡ tag khi gửi xuống end device (PC, máy in…). Switch trunk port giữ nguyên tag khi forward — đây là cổng bạn cần nối với Linux server.

Sub-interface trên Linux

Linux tạo virtual interface như enp3s0.10 gắn vào physical interface enp3s0 — cứ hình dung mỗi VLAN là một “kênh riêng” trên cùng sợi cáp. Kernel module 8021q tự lo phần tag/untag: gửi packet qua enp3s0.10 thì kernel thêm tag VLAN 10 vào frame; nhận frame có tag 10 trên enp3s0 thì kernel đẩy lên đúng enp3s0.10.

Thực hành: Cấu hình VLAN sub-interface từng bước

Bước 1: Kiểm tra kernel module 8021q

# Kiểm tra module đã load chưa
lsmod | grep 8021q

# Nếu chưa có output, load module thủ công
sudo modprobe 8021q

# Để load tự động mỗi lần boot
echo "8021q" | sudo tee /etc/modules-load.d/8021q.conf

Ubuntu 20.04+, Debian 11+, Rocky Linux 8+ đều đã tích hợp sẵn module này trong kernel — không cần cài thêm package riêng.

Bước 2: Xác định interface vật lý và chuẩn bị

# Liệt kê các interface hiện có
ip link show

# Ví dụ output:
# 2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
#     link/ether 00:1a:2b:3c:4d:5e brd ff:ff:ff:ff:ff:ff

Giả sử interface vật lý là enp3s0, nối lên trunk port của switch với các VLAN: 10 (kế toán), 20 (IT), 30 (server).

Lưu ý quan trọng: Interface vật lý phải ở trạng thái UP nhưng không có IP. IP sẽ được gán lên sub-interface, không phải lên physical interface. Mình từng mắc lỗi này lúc đầu — gán IP lên cả hai chỗ khiến packet routing bị lộn xộn rất khó debug.

# Bật interface vật lý, không gán IP
sudo ip link set enp3s0 up

Bước 3: Tạo VLAN sub-interface (cấu hình tạm thời để test)

# Tạo sub-interface cho VLAN 10 và gán 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
# Kiểm tra ngay
ip addr show | grep -A3 "enp3s0\."

# Xem chi tiết VLAN đã được nhận diện bởi kernel
cat /proc/net/vlan/config

Output /proc/net/vlan/config sẽ trông như này:

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

Bước 4: Cấu hình persistent với Netplan (Ubuntu 20.04+)

Lệnh ip chỉ tạm thời — reboot là bay hết. Để persistent, tạo file 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]
# Apply cấu hình
sudo netplan apply

# Kiểm tra
ip link show type vlan

Bước 5: Cấu hình persistent với NetworkManager (RHEL/CentOS/Rocky)

# Tạo connection VLAN bằng nmcli
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

# Kích hoạt
nmcli connection up vlan10
nmcli connection up vlan20
nmcli connection up vlan30

Bước 6: Bật IP forwarding nếu dùng làm inter-VLAN router

Nếu Linux server này làm gateway — route traffic giữa các VLAN — cần bật IP forwarding:

# Persistent: thêm vào /etc/sysctl.conf
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Kiểm tra
sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 1

Bước 7: Kiểm tra và troubleshoot

# Ping thử từ máy trong VLAN 10 đến địa chỉ gateway
ping 192.168.10.1

# Capture packet để verify frame có tag 802.1Q không
# Cờ -e hiển thị Ethernet header, sẽ thấy "vlan 10" trong output
sudo tcpdump -i enp3s0 -e vlan

# Lọc theo VLAN ID cụ thể
sudo tcpdump -i enp3s0 vlan 10

Sub-interface không nhận packet? Nguyên nhân phổ biến nhất là switch chưa set trunk đúng. Kiểm tra phía switch:

# Cisco IOS — đảm bảo cổng nối server là trunk
# 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

Mấy điều rút ra từ thực tế quản lý datacenter

Điểm mà mình hay thấy người mới vấp nhất là MTU. Chuẩn 802.1Q thêm 4 byte vào frame header. Nếu switch hoặc uplink không config jumbo frame, packet ≥ 1497 byte sẽ bị fragment mà không có error message rõ ràng — rất khó debug. Kiểm tra và điều chỉnh MTU nếu cần:

# MTU mặc định của sub-interface thường bằng physical interface (1500)
ip link show enp3s0.10

# Nếu gặp vấn đề với large frames, thử giảm MTU xuống
sudo ip link set enp3s0.10 mtu 1496

# Với Netplan, thêm mtu vào từng vlan entry:
# enp3s0.10:
#   id: 10
#   link: enp3s0
#   mtu: 1496
#   addresses: [192.168.10.1/24]

Ở datacenter nhỏ mà mình đang quản lý, cấu hình này chạy ổn định cho hàng chục VLAN trên một interface duy nhất của KVM host — VLAN management, storage, production, DMZ. Không cần cắm thêm NIC nào cả, tiết kiệm slot PCIe và giảm cáp đáng kể.

Một lưu ý cuối: đặt tên sub-interface theo format <physical>.<vlan-id> (ví dụ enp3s0.10) là convention phổ biến nhất và dễ đọc nhất. Bạn có thể đặt tên tùy ý như vlan-accounting, nhưng khi debug lúc 2 giờ sáng, cái tên enp3s0.10 rõ ràng hơn nhiều.

Kết luận

Nhìn lại thì setup này đơn giản hơn nhiều người nghĩ: không tốn thêm phần cứng, không cần driver lạ, kernel hỗ trợ native qua module 8021q. Điểm cốt lõi cần nhớ: để interface vật lý không có IP, tạo sub-interface với VLAN ID đúng, và phía switch phải là trunk port cho phép đúng các VLAN đó.

Khi số lượng VLAN tăng lên, cấu hình qua Netplan hay NetworkManager sẽ dễ quản lý và dễ audit hơn nhiều so với script thủ công. Bước tiếp theo tự nhiên là ghép thêm nftables để kiểm soát traffic giữa VLAN — quan trọng khi production và DMZ cùng trunk qua một NIC.

Share: