Cấu hình QinQ (802.1ad VLAN Stacking) trên Linux: Dual-Tagging để cô lập Multi-Tenant

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Bối cảnh & Lý do

Lúc 2:15 sáng, pager trực on-call của chúng tôi liên tục báo động trên khắp 40 node. Một tenant doanh nghiệp tầm trung trên cụm hypervisor vừa khởi tạo 3 node database thì ngay lập tức một nửa cụm của họ bị mất kết nối. Nguyên nhân gốc rễ là một lỗi kinh điển: xung đột VLAN.

Cả Tenant A và Tenant B đều xây dựng môi trường nội bộ trên VLAN 100. Trong khi đó, tầng distribution của chúng tôi lại xử lý tất cả các frame dưới dạng lưu lượng 802.1q gắn single-tag tiêu chuẩn. Do vậy, broadcast domain của hai bên bị nhập làm một ngay lập tức. Chỉ trong vòng 90 giây, các switch Arista top-of-rack đã ghi nhận hơn 14.000 thông báo MAC flap, làm rớt hàng nghìn gói tin của khách hàng.

Chuẩn IEEE 802.1q sử dụng định danh VLAN 12-bit, cung cấp tối đa 4.094 broadcast domain có thể sử dụng. Tại các trung tâm dữ liệu colocation multi-tenant hoặc dịch vụ managed hosting phục vụ từ 50 khách hàng trở lên, dải ID này cạn kiệt rất nhanh. Nghiêm trọng hơn, bạn không thể can thiệp vào quy hoạch địa chỉ nội bộ của khách hàng. Tenant A có thể yêu cầu VLAN 100 cho tầng web, trong khi Tenant B lại dùng VLAN 100 cho lưu trữ Ceph. Việc viết lại tag sẽ phá vỡ quy trình tự động hóa của họ, còn gỡ bỏ tag sẽ làm hỏng toàn bộ topology mạng.

Chuẩn IEEE 802.1ad—thường được biết đến với tên gọi QinQ—giải quyết triệt để vấn đề này. Tiêu chuẩn này đóng gói một Customer VLAN tag bên trong theo chuẩn 802.1q (C-TAG, EtherType 0x8100) vào trong một Service VLAN tag bên ngoài (S-TAG, EtherType 0x88a8). Mạng core của bạn sẽ thực hiện chuyển mạch hoàn toàn dựa trên S-TAG bên ngoài. Tag nội bộ của khách hàng được giữ nguyên vẹn cho đến khi lưu lượng đến đúng VM hoặc router gateway của họ.

Dù các giải pháp mạng overlay bằng phần mềm như VXLAN và Geneve đang chiếm ưu thế trên các hạ tầng hyperscale cloud, các mô hình bare-metal và edge node Linux cấp độ nhà mạng vẫn phụ thuộc rất nhiều vào QinQ. Kỹ thuật dual-tagging thuần Layer 2 loại bỏ hoàn toàn phần overhead 50 byte đóng gói UDP của VXLAN, mang lại thông lượng line-rate tối đa mà không tiêu tốn chu kỳ xử lý của CPU.

Cài đặt & Yêu cầu tiên quyết

Mọi nhân Linux hiện đại từ phiên bản 3.10 trở đi đều hỗ trợ 802.1ad. Tuy nhiên, các bản phân phối máy chủ dạng rút gọn hiếm khi tự động nạp kernel module cần thiết trong quá trình khởi động.

Nạp module 8021q ngay lập tức:

sudo modprobe 8021q

Thiết lập nạp module tự động khi khởi động lại để việc restart máy chủ theo lịch trình không làm gián đoạn kết nối:

echo "8021q" | sudo tee /etc/modules-load.d/8021q.conf

Cài đặt bộ công cụ mạng và giám sát cần thiết:

# Debian, Ubuntu hoặc Proxmox VE
sudo apt-get update && sudo apt-get install -y iproute2 ethtool tcpdump

# RHEL, AlmaLinux hoặc Rocky Linux
sudo dnf install -y iproute ethtool tcpdump

Tiếp theo, hãy kiểm tra khả năng của interface vật lý. Một Ethernet frame không gắn tag tiêu chuẩn có kích thước 1518 byte bao gồm cả header và FCS. Việc xếp chồng hai tag 4-byte sẽ đẩy kích thước frame tối thiểu này lên 1526 byte. Nếu card mạng (NIC) vật lý hoặc port switch loại bỏ bất kỳ gói tin nào vượt quá 1500 byte, QinQ sẽ âm thầm đánh rớt payload. Kiểm tra trạng thái liên kết trên interface uplink (ở đây chúng ta sử dụng eth0):

ethtool eth0 | grep -i speed
ip link show eth0

Cấu hình

Hãy luôn cấu hình hạ tầng mạng từ lớp phần cứng bên dưới lên đến namespace của khách hàng. Tuyệt đối không khai báo các sub-interface trước khi xác nhận link cha đã sẵn sàng hoạt động.

1. Điều chỉnh MTU của Interface vật lý

Trước tiên, hãy tăng MTU của interface cha. Bạn cần tối thiểu 1508 byte để bù cho cả hai tag 4-byte trong khi vẫn duy trì payload IP tiêu chuẩn 1500 byte. Nếu switch vật lý hỗ trợ jumbo frame, hãy đặt trực tiếp lên 9000 byte:

sudo ip link set dev eth0 mtu 9000
sudo ip link set dev eth0 up

2. Tạo Service VLAN lớp ngoài (802.1ad)

Gán cho Tenant A một Service VLAN ID lớp ngoài là 1000. Truyền tham số proto 802.1ad để buộc Linux ghi EtherType 0x88a8 vào header lớp ngoài thay vì giá trị mặc định 0x8100:

sudo ip link add link eth0 name eth0.1000 type vlan proto 802.1ad id 1000
sudo ip link set dev eth0.1000 mtu 8996 up

3. Xếp chồng Customer VLAN (802.1q)

Khởi tạo Customer VLAN bên trong trực tiếp trên interface S-TAG lớp ngoài. Interface này sẽ xử lý tag 802.1q tiêu chuẩn (EtherType 0x8100). Trong kịch bản này, Tenant A sử dụng VLAN nội bộ là 100:

sudo ip link add link eth0.1000 name eth0.1000.100 type vlan proto 802.1q id 100
sudo ip link set dev eth0.1000.100 mtu 8992 up

4. Cô lập các Tenant xung đột bằng Network Namespace

Bây giờ hãy xét đến Tenant B. Họ cũng cấu hình VLAN 100 với dải IP riêng hoàn toàn trùng lặp (192.168.100.1/24). Gán cho Tenant B một S-TAG lớp ngoài là 2000 trên cùng máy chủ vật lý:

# S-TAG lớp ngoài cho Tenant B
sudo ip link add link eth0 name eth0.2000 type vlan proto 802.1ad id 2000
sudo ip link set dev eth0.2000 mtu 8996 up

# C-TAG lớp trong cho Tenant B (tái sử dụng VLAN ID 100 mà không gây xung đột)
sudo ip link add link eth0.2000 name eth0.2000.100 type vlan proto 802.1q id 100
sudo ip link set dev eth0.2000.100 mtu 8992 up

Việc gán các subnet IP trùng lặp vào bảng định tuyến mặc định sẽ gây ra hiện tượng kernel ARP flux và làm sai lệch bảng định tuyến. Hãy cô lập chúng triệt để bằng network namespace:

# Tạo các routing domain cô lập
sudo ip netns add tenant-a
sudo ip netns add tenant-b

# Chuyển các interface của khách hàng vào namespace tương ứng
sudo ip link set dev eth0.1000.100 netns tenant-a
sudo ip link set dev eth0.2000.100 netns tenant-b

# Cấu hình an toàn các dải IP trùng lặp bên trong từng namespace
sudo ip -n tenant-a addr add 192.168.100.1/24 dev eth0.1000.100
sudo ip -n tenant-a link set dev eth0.1000.100 up

sudo ip -n tenant-b addr add 192.168.100.1/24 dev eth0.2000.100
sudo ip -n tenant-b link set dev eth0.2000.100 up

Cả hai tenant hiện đều có thể chạy đồng thời dải mạng 192.168.100.0/24 trên VLAN 100 nội bộ. Luồng lưu lượng của họ hoàn toàn không bao giờ giao nhau.

5. Cấu hình cố định với systemd-networkd

Các lệnh thực thi qua ip link sẽ biến mất khi khởi động lại máy chủ. Hãy dùng systemd-networkd để duy trì cấu trúc phân tầng dual-tag vĩnh viễn.

Định nghĩa netdev S-TAG lớp ngoài trong tệp /etc/systemd/network/10-eth0.1000.netdev:

[NetDev]
Name=eth0.1000
Kind=vlan

[VLAN]
Id=1000
Protocol=802.1ad

Định nghĩa netdev C-TAG xếp chồng trong tệp /etc/systemd/network/20-eth0.1000.100.netdev:

[NetDev]
Name=eth0.1000.100
Kind=vlan

[VLAN]
Id=100
Protocol=802.1q

Liên kết VLAN lớp ngoài với interface vật lý trong tệp /etc/systemd/network/05-eth0.network:

[Match]
Name=eth0

[Network]
VLAN=eth0.1000
LinkLocalAddressing=no

Kiểm tra & Xử lý sự cố

Khi các interface đã hoạt động, hãy kiểm tra từng lớp trong cấu trúc mạng trước khi định tuyến tải công việc của khách hàng.

1. Kiểm tra cờ Protocol của Interface

Truy vấn metadata của interface bằng lệnh ip -d link show:

ip -d link show eth0.1000

Xác nhận trường protocol khớp với 802.1ad:

vlan protocol 802.1ad id 1000 <REORDER_HDR>

Kiểm tra interface khách hàng lồng bên trong:

ip -n tenant-a -d link show eth0.1000.100

Bạn sẽ thấy đóng gói chuẩn 802.1q:

vlan protocol 802.1q id 100 <REORDER_HDR>

2. Xác thực ở mức đường truyền với tcpdump

Bắt gói tin là cách phản ánh chính xác nhất thực tế trên đường truyền. Chạy tcpdump trên interface nền tảng với tùy chọn -e để kiểm tra trực tiếp các trường header 802.1:

sudo tcpdump -e -n -i eth0 vlan

Tạo lưu lượng thử nghiệm từ namespace của Tenant A:

sudo ip netns exec tenant-a ping -c 2 192.168.100.2

Kết quả bắt gói sẽ hiển thị cả hai tag xuất hiện trong frame header:

02:42:10.198302 52:54:00:12:34:56 > 52:54:00:ab:cd:ef, ethertype 802.1Q-QinQ (0x88a8), vlan 1000, p 0, ethertype 802.1Q (0x8100), vlan 100, p 0, IPv4 (0x0800), length 98: 192.168.100.1 > 192.168.100.2: ICMP echo request, id 412, seq 1

Kết quả đầu ra xác nhận việc đóng gói lớp ngoài qua 0x88a8 bọc lấy tag 0x8100 ở lớp trong.

3. Các cạm bẫy trong môi trường Production: Hardware Offload & MTU Blackhole

Nếu gói tin xuất hiện trong kết quả bắt gói đi nhưng đầu bên kia không nhận được gì, hãy kiểm tra hai vấn đề sau đầu tiên:

  • NIC Hardware Offloading: Các bộ điều khiển mạng (controller) 10G/25G thế hệ cũ (như Intel 82599ES dùng driver ixgbe hoặc các thiết bị ảo hóa virtio_net đời đầu) thường gặp lỗi khi phân tích các VLAN xếp chồng. Chúng có thể bóc tách hoặc làm hỏng tag 0x88a8 bên ngoài ở mức phần cứng. Hãy tắt tính năng VLAN hardware offloading để Linux kernel trực tiếp xử lý các thao tác gắn tag:
sudo ethtool -K eth0 rxvlan off txvlan off
  • MTU Blackhole: Các gói ping ICMP nhỏ 56 byte có thể truyền thành công nhưng các luồng truyền dữ liệu lớn hơn lại bị treo vô thời hạn. Hãy kiểm tra điều này bằng cách bật cờ Don’t Fragment (DF):
sudo ip netns exec tenant-a ping -s 1472 -M do 192.168.100.2

Nếu lệnh ping bị timeout, một port switch ở phía upstream đang đánh rớt các frame vượt kích thước 1508 byte. Bạn có hai phương án: Hoặc tăng MTU của port switch lên tối thiểu 1508 byte (hoặc 9000 cho jumbo frame), hoặc giảm MTU của sub-interface khách hàng xuống 1492 byte.

Share: