Khi số lượng khách thuê (tenant) vượt quá vài chục, không gian 4094 VLAN của chuẩn 802.1Q bắt đầu trở nên chật chội. QinQ — còn gọi là Double VLAN, 802.1ad, hay 802.1Q-in-802.1Q — giải quyết bài toán này bằng cách đóng gói thêm một VLAN tag bên ngoài, nâng tổng số VLAN khả dụng lên xấp xỉ 16 triệu. Đây là kỹ thuật cốt lõi trong hạ tầng ISP, cloud provider, và môi trường cần phân tách lưu lượng sạch giữa nhiều tenant trên cùng một đường vật lý.
Quick Start — Dựng QinQ trong 5 phút
Mình sẽ đi thẳng vào ví dụ thực tế. Giả sử bạn có interface eth0 và cần tạo một interface QinQ với outer VLAN (S-VLAN) 100 và inner VLAN (C-VLAN) 10.
Bước 1: Kiểm tra kernel hỗ trợ 8021q
# Kiểm tra và load kernel module
modinfo 8021q
sudo modprobe 8021q
lsmod | grep 8021q
Bước 2: Tạo S-VLAN (outer tag — phía provider)
# Tạo outer VLAN interface với protocol 802.1ad
sudo ip link add link eth0 name eth0.100 type vlan proto 802.1ad id 100
sudo ip link set eth0.100 up
Bước 3: Tạo C-VLAN (inner tag — phía tenant) chồng lên S-VLAN
# Tạo inner VLAN chồng lên outer VLAN
sudo ip link add link eth0.100 name eth0.100.10 type vlan proto 802.1Q id 10
sudo ip link set eth0.100.10 up
# Gán IP và kiểm tra
sudo ip addr add 192.168.10.1/24 dev eth0.100.10
ip addr show eth0.100.10
Bước 4: Xác nhận QinQ hoạt động
# Xem cấu trúc interface lồng nhau
ip link show | grep -E 'eth0|vlan'
# Capture frame để xác nhận double tag xuất hiện trên wire
sudo tcpdump -i eth0 -n -e 'vlan' 2>/dev/null | head -20
Nếu thấy output kiểu 802.1Q vlan #100, p 0, 802.1Q vlan #10 trong tcpdump thì QinQ đã hoạt động đúng.
Hiểu QinQ từ trong ra ngoài
Cấu trúc frame so với 802.1Q thông thường
Standard 802.1Q Frame:
| Dst MAC | Src MAC | 0x8100 | PCP+DEI+VID (4B) | EtherType | Payload |
QinQ (802.1ad) Frame:
| Dst MAC | Src MAC | 0x88A8 | S-VID outer (4B) | 0x8100 | C-VID inner (4B) | EtherType | Payload |
EtherType 0x88A8 là dấu hiệu nhận biết outer tag của 802.1ad. Switch và router dựa vào đây để phân biệt frame QinQ với 802.1Q thông thường.
S-VLAN và C-VLAN — ai quản lý phần nào?
- S-VLAN (Service VLAN / outer tag): Gán và quản lý bởi nhà cung cấp dịch vụ. Mỗi tenant nhận một S-VLAN riêng và không được tự thay đổi giá trị này.
- C-VLAN (Customer VLAN / inner tag): Thuộc phạm vi quản lý của tenant. Tenant A và Tenant B đều có thể dùng C-VLAN 10 mà không xung đột — vì S-VLAN của họ đã khác nhau.
Điểm mấu chốt: mỗi tenant có riêng 4094 C-VLAN hoàn toàn độc lập. Tổng cộng: 4094 S-VLAN × 4094 C-VLAN ≈ 16 triệu combination.
Cấu hình multi-tenant thực tế
Scenario: 3 tenant dùng chung eth0
#!/bin/bash
# setup-qinq-tenants.sh
PHYS_IF="eth0"
# --- Tenant A: S-VLAN 100 ---
ip link add link $PHYS_IF name ${PHYS_IF}.100 type vlan proto 802.1ad id 100
ip link set ${PHYS_IF}.100 up
# C-VLAN 10 (management), C-VLAN 20 (production)
ip link add link ${PHYS_IF}.100 name ${PHYS_IF}.100.10 type vlan proto 802.1Q id 10
ip link add link ${PHYS_IF}.100 name ${PHYS_IF}.100.20 type vlan proto 802.1Q id 20
ip link set ${PHYS_IF}.100.10 up
ip link set ${PHYS_IF}.100.20 up
ip addr add 10.100.10.1/24 dev ${PHYS_IF}.100.10
ip addr add 10.100.20.1/24 dev ${PHYS_IF}.100.20
# --- Tenant B: S-VLAN 200 ---
ip link add link $PHYS_IF name ${PHYS_IF}.200 type vlan proto 802.1ad id 200
ip link set ${PHYS_IF}.200 up
# C-VLAN 10 — cùng ID với Tenant A nhưng hoàn toàn độc lập
ip link add link ${PHYS_IF}.200 name ${PHYS_IF}.200.10 type vlan proto 802.1Q id 10
ip link set ${PHYS_IF}.200.10 up
ip addr add 10.200.10.1/24 dev ${PHYS_IF}.200.10
# --- Tenant C: S-VLAN 300 ---
ip link add link $PHYS_IF name ${PHYS_IF}.300 type vlan proto 802.1ad id 300
ip link set ${PHYS_IF}.300 up
ip link add link ${PHYS_IF}.300 name ${PHYS_IF}.300.10 type vlan proto 802.1Q id 10
ip link set ${PHYS_IF}.300.10 up
ip addr add 10.300.10.1/24 dev ${PHYS_IF}.300.10
echo "QinQ interfaces ready for 3 tenants"
ip link show type vlan
Lưu cấu hình bền vững qua reboot với systemd-networkd
Dùng ip link trực tiếp sẽ mất sau reboot. Để cấu hình bền vững, tạo file .netdev và .network:
# /etc/systemd/network/10-svlan100.netdev
[NetDev]
Name=eth0.100
Kind=vlan
[VLAN]
Protocol=802.1ad
Id=100
# /etc/systemd/network/20-cvlan100-10.netdev
[NetDev]
Name=eth0.100.10
Kind=vlan
[VLAN]
Protocol=802.1q
Id=10
# /etc/systemd/network/20-cvlan100-10.network
[Match]
Name=eth0.100.10
[Network]
Address=10.100.10.1/24
sudo systemctl restart systemd-networkd
networkctl status eth0.100.10
Tips thực tế từ kinh nghiệm vận hành
MTU — bẫy phổ biến nhất với QinQ
Mỗi VLAN tag thêm 4 byte vào header. QinQ có 2 tag = 8 byte overhead. Nếu MTU của interface vật lý vẫn giữ nguyên 1500, frame lớn sẽ bị drop im lặng hoặc bị fragmented mà không có cảnh báo rõ ràng — rất khó phát hiện.
# Tăng MTU trên physical interface để chứa double tag
sudo ip link set eth0 mtu 1508 # 1500 + 4 (outer tag) + 4 (inner tag)
# Xác nhận MTU hiện tại của các interface
ip link show eth0 | grep mtu
ip link show eth0.100.10 | grep mtu
Câu chuyện debug intermittent packet loss
Lần debug network issue khó nhất của mình là khi intermittent packet loss chỉ xảy ra vào giờ cao điểm — sáng sớm và chiều muộn bình thường hoàn toàn. Ban đầu mình nghĩ do bandwidth saturation, nhưng nhìn vào metrics thì bandwidth còn dư rất nhiều.
Sau vài ngày capture trực tiếp trên wire bằng tcpdump mới tìm ra: MTU mismatch trên QinQ interface. Frame cỡ lớn từ SSH session và file transfer bị drop. Giờ cao điểm nhiều connection cùng gửi frame gần max size nên mới lộ ra, còn giờ thấp điểm thì không ai đụng đến threshold đó.
Cách tìm MTU threshold chính xác:
# Cờ -M do bật Don't Fragment — frame bị drop sẽ báo lỗi ngay thay vì im lặng
ping -M do -s 1472 192.168.10.2 # 1472 payload + 28 (IP+ICMP header) = 1500 byte
ping -M do -s 1464 192.168.10.2 # Giảm dần để tìm ngưỡng
ping -M do -s 1492 192.168.10.2
# Nếu nhận được "Frag needed" hoặc timeout → MTU quá nhỏ
# Tìm giá trị lớn nhất không bị drop — đó là MTU thực tế của path
Kiểm tra NIC có hỗ trợ 802.1ad hardware offload không
Không phải NIC nào cũng hỗ trợ hardware offload cho 802.1ad. Nếu không, kernel vẫn xử lý được qua software, nhưng throughput sẽ bị ảnh hưởng với traffic cao.
# Kiểm tra offload features
ethtool -k eth0 | grep -E 'vlan|tx-vlan|rx-vlan'
# Xem NIC có hỗ trợ rx-vlan-filter không
ethtool -k eth0 | grep vlan-filter
Dọn dẹp interface khi không cần nữa
# Xóa theo thứ tự từ trong ra ngoài (inner trước, outer sau)
sudo ip link del eth0.100.10
sudo ip link del eth0.100.20
sudo ip link del eth0.100
# Xóa tất cả VLAN interface cùng lúc
for iface in $(ip link show type vlan | grep -oP '^\d+: \K[\w.]+'); do
ip link del "$iface" 2>/dev/null
done
QinQ là công cụ mạnh nhưng đòi hỏi kỷ luật trong quản lý MTU và theo dõi cấu trúc interface lồng nhau. Một khi đã hiểu luồng S-VLAN → C-VLAN, bạn có thể mở rộng hạ tầng multi-tenant mà không cần thêm phần cứng hay reconfigure toàn bộ network.

