Vận hành các cổng mạng riêng ảo (VPN), trạm chuyển tiếp biên và proxy trung chuyển dưới áp lực lưu lượng cực lớn luôn đặt ra những thách thức kiến trúc nan giải. Trên các giao diện mạng chuẩn 40GbE và 100GbE hiện đại, số lượng gói tin đổ về hệ thống thường xuyên chạm ngưỡng từ 20 đến 50 triệu gói mỗi giây (Mpps).

Ở ngưỡng tốc độ này, ngăn xếp mạng truyền thống của nhân Linux bộc lộ rõ ranh giới giới hạn xử lý gói tin (PPS). Theo quy trình mặc định, mỗi gói tin đi vào đều phải trải qua các bước cấp phát bộ đệm vòng của driver, khởi tạo cấu trúc dữ liệu Socket Buffer (sk_buff), tra cứu bảng định tuyến IP, đi qua các móc kiểm tra theo dõi kết nối Netfilter (conntrack) và xử lý khoá tài nguyên trong nhân.

Dù có sự hỗ trợ của kỹ thuật phân phối phần cứng Receive Side Scaling (RSS), chi phí CPU cho việc cấp phát và giải phóng cấu trúc sk_buff vẫn giới hạn năng lực chuyển tiếp của một lõi CPU ở mức khoảng 2 đến 4 Mpps.

Để giải phóng toàn diện hiệu năng phần cứng mạng mà vẫn duy trì tính linh hoạt của hệ điều hành Linux, các kỹ sư hệ thống sử dụng khung làm việc eXpress Data Path (XDP) kết hợp với hành động XDP_REDIRECT và hai cấu trúc bản đồ BPF chuyên dụng: devmap và cpumap.

+--------------------------------------------------------------------------+
|          KIẾN TRÚC ĐIỀU HƯỚNG GÓI TIN LINUX EBPF XDP_REDIRECT            |
+--------------------------------------------------------------------------+
|                                                                          |
|       Luồng dữ liệu vào từ đường truyền vật lý (100GbE SFP28)            |
|                           │                                              |
|                           v                                              |
|       Bộ đệm nhận RX Ring của NIC (Truy cập bộ nhớ trực tiếp - DMA)      |
|                           │                                              |
|                           v (Cấu trúc thô xdp_buff - Chưa cấp sk_buff)   |
|      +-------------------------------------------------------------+     |
|      |                   MÓC XỬ LÝ XDP TRONG DRIVER (eBPF)         |     |
|      |                                                             |     |
|      |   - Phân tích tiêu đề L2-L4 (Gói IP, UDP, WireGuard/RiceGuard|     |
|      |   - Tra cứu bản đồ BPF (devmap hoặc cpumap)                 |     |
|      |   - Trả về chỉ thị điều hướng XDP_REDIRECT                  |     |
|      +-------------------------------------------------------------+     |
|              │                                             │             |
|              v (XDP_REDIRECT tới devmap)                   v (cpumap)    |
|      +-------------------------------+             +---------------+     |
|      | BPF_MAP_TYPE_DEVMAP           |             | BPF_CPUMAP    |     |
|      | Đích đến: Hàng đợi TX của NIC |             | Đích đến: CPUN|     |
|      +-------------------------------+             +---------------+     |
|              │                                             │             |
|              v (Chuyển tiếp Zero-Copy)                     v             |
|      Đẩy thẳng dữ liệu ra sợi quang quang học     Tiến trình SoftIRQ lõi |
|      (30+ Mpps / Đạt tốc độ dây vật lý)           (Thực thi giải mã khối)|
|                                                                          |
+--------------------------------------------------------------------------+

Bản chất vận hành của chỉ thị XDP_REDIRECT

Khung làm việc eXpress Data Path (XDP) cung cấp một điểm móc thực thi ngay bên trong trình điều khiển card mạng trước khi nhân hệ điều hành kịp khởi tạo cấu trúc sk_buff. Hoạt động trực tiếp trên cấu trúc thô xdp_buff, một chương trình XDP có thể đưa ra 5 phán quyết xử lý:

  • XDP_DROP: Huỷ bỏ gói tin tức thì tại tầng mạng thấp, thích hợp cho việc giảm thiểu tấn công DDoS.
  • XDP_TX: Đẩy gói tin quay ngược trở lại đúng cổng mạng tiếp nhận.
  • XDP_PASS: Chuyển tiếp gói tin lên ngăn xếp mạng IP tiêu chuẩn của nhân.
  • XDP_ABORTED: Chỉ thị lỗi báo hiệu chương trình eBPF gặp trục trặc.
  • XDP_REDIRECT: Bẻ hướng gói tin thô sang một đích đến mới.

Nếu như giai đoạn đầu XDP chủ yếu được ứng dụng để lọc gói (XDP_DROP), thì các hệ thống mạng chuyển tiếp VPN hiện đại ngày nay dựa hoàn toàn vào XDP_REDIRECT. Thông qua hàm trợ giúp bpf_redirect_map(), chương trình eBPF chuyển hướng luồng dữ liệu sang một card mạng khác hoặc sang một lõi CPU định danh với độ trễ dưới một micro-giây.

Chuyển tiếp tốc độ cao ra cổng mạng với devmap

Cấu trúc devmap (BPF_MAP_TYPE_DEVMAP và BPF_MAP_TYPE_DEVMAP_HASH) lưu trữ một mảng hoặc bảng băm các chỉ số định danh thiết bị mạng đích trong nhân.

Khi chương trình XDP ra lệnh chuyển hướng vào một devmap, gói tin sẽ đi tắt qua toàn bộ tầng mạng phía trên—bỏ qua định tuyến IP, bỏ qua tường lửa Netfilter và bỏ qua các cơ chế xếp hàng đợi (qdisc). Khung xdp_buff được đưa thẳng vào hàng đợi truyền phát (TX ring) của card mạng đích.

+--------------------------------------------------------------------------+
|                  SO SÁNH TIẾN TRÌNH: ĐỊNH TUYẾN IP VÀ XDP DEVMAP         |
+--------------------------------------------------------------------------+
| Giai đoạn xử lý        | Định tuyến IP truyền thống| Chuyển hướng XDP     |
+------------------------+---------------------------+----------------------+
| Điểm móc xử lý vào     | Trình thăm dò NAPI        | Tầng driver card mạng|
| Cấu trúc bộ nhớ        | sk_buff nặng nề (~256 B)  | xdp_buff gọn nhẹ     |
| Quyết định chuyển tiếp | Bảng FIB phân nhánh trie  | Tra cứu BPF Map O(1) |
| Tường lửa & Conntrack  | Quét toàn bộ Netfilter    | Hoàn toàn bỏ qua     |
| Cơ chế đẩy dữ liệu     | dev_queue_xmit (qdisc)    | Thao tác ndo_xdp_xmit|
| Năng lực xử lý tối đa  | ~2-4 Mpps / Lõi           | ~25-35 Mpps / Lõi    |
+--------------------------------------------------------------------------+

Triển khai devmap bằng mã C (eBPF)

Ví dụ dưới đây mô tả chương trình eBPF chuyển tiếp các gói tin trung chuyển qua lại giữa hai cổng mạng 100GbE:

#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <bpf/bpf_helpers.h>

/* Khai báo devmap lưu trữ chỉ số cổng mạng ra */
struct {
    __uint(type, BPF_MAP_TYPE_DEVMAP);
    __uint(max_entries, 64);
    __uint(key_size, sizeof(__u32));
    __uint(value_size, sizeof(__u32));
} tx_port_map SEC(".maps");

SEC("xdp")
int xdp_redirect_forwarder(struct xdp_md *ctx) {
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;

    /* Kiểm tra tiêu đề Ethernet */
    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end)
        return XDP_PASS;

    /* Chỉ xử lý gói tin IPv4 */
    if (eth->h_proto != __constant_htons(ETH_P_IP))
        return XDP_PASS;

    struct iphdr *iph = (void *)(eth + 1);
    if ((void *)(iph + 1) > data_end)
        return XDP_PASS;

    /* Xác định gói tin VPN trung chuyển cần đẩy ra cổng số 2 */
    __u32 target_ifindex = 2;

    /* Thực hiện chuyển tiếp zero-copy ở tầng driver */
    return bpf_redirect_map(&tx_port_map, target_ifindex, 0);
}

char _license[] SEC("license") = "GPL";

Phân phối tính toán mật mã đa lõi với cpumap

Nếu như devmap là giải pháp lý tưởng cho việc chuyển tiếp luồng dữ liệu trung chuyển, thì các giao thức VPN mã hoá (như WireGuard và RiceGuard) lại đòi hỏi năng lực tính toán CPU đáng kể để giải mã các gói dữ liệu ChaCha20-Poly1305 và AES-GCM.

Một điểm nghẽn phổ biến xảy ra khi một lượng lớn gói tin dồn về một hàng đợi nhận duy nhất. Nếu một lõi CPU vừa phải xử lý ngắt phần cứng, vừa phải gánh toàn bộ tải tính toán giải mã, lõi đó sẽ nhanh chóng chạm ngưỡng 100% trong khi các lõi khác hoàn toàn nhàn rỗi.

Bản đồ cpumap (BPF_MAP_TYPE_CPUMAP) giải quyết triệt để vấn đề mất cân đối này:

  1. Phân loại sớm tại driver: Chương trình XDP chạy trên lõi tiếp nhận gói tin ở tốc độ dây, đọc nhanh tiêu đề gói tin.
  2. Tính toán băm luồng: Chương trình tính giá trị băm 4 thành phần (IP nguồn, IP đích, cổng nguồn, cổng đích) để lựa chọn lõi CPU đích.
  3. Đẩy sang hàng đợi của CPU đích: Chương trình thực hiện bpf_redirect_map(&cpu_map, target_cpu, 0).
  4. Cấp phát độc lập: Lõi CPU đích nhận gói tin thô, tự cấp phát cấu trúc sk_buff và chạy các thuật toán giải mã mật mã học trong ngữ cảnh softirq riêng của mình.
Luồng 100GbE đi vào (Một hàng đợi RX)
          │
          v
   Lõi 0 (XDP Phân tích gói)
   [ Tính toán mã băm phân luồng ]
          │
    ┌─────┴─────────────────────────┐
    │ bpf_redirect_map(&cpu_map)    │
    ▼                               ▼
Lõi 1 (Tiến trình SoftIRQ)  Lõi 2 (Tiến trình SoftIRQ)
Cấp phát sk_buff            Cấp phát sk_buff
Giải mã khối RiceGuard      Giải mã khối RiceGuard

Cấu trúc này tách bạch hoàn toàn việc quản lý hàng đợi phần cứng khỏi quá trình tính toán mã hoá, ngăn chặn triệt để tình trạng nghẽn cổ chai softirq trên các máy chủ đa nhân.

Các bước cấu hình và triển khai thực tế

Quy trình triển khai bộ chuyển tiếp XDP trên máy chủ Linux được thực hiện qua các công cụ chuẩn:

Bước 1: Biên dịch chương trình eBPF

Sử dụng trình biên dịch Clang để tạo tệp đối tượng BPF:

clang -O2 -g -target bpf -c xdp_forward.c -o xdp_forward.o

Bước 2: Gắn chương trình XDP vào card mạng tiếp nhận

Kích hoạt chương trình ở chế độ driver bản địa:

# Gắn ở chế độ native driver (chế độ tốc độ cao)
ip link set dev eth0 xdpgeneric off
ip link set dev eth0 xdpdrv object xdp_forward.o section xdp

Bước 3: Đưa thông số cổng mạng đích vào devmap

Gán chỉ số cổng mạng ra vào bản đồ được ghim trên hệ thống:

# Lấy chỉ số ifindex của cổng eth1
IFINDEX_ETH1=$(cat /sys/class/net/eth1/ifindex)

# Cập nhật bản đồ devmap qua bpftool
bpftool map update pinned /sys/fs/bpf/tx_port_map \
    key 2 0 0 0 \
    value $IFINDEX_ETH1 0 0 0

Bước 4: Giám sát thống kê chuyển tiếp

Theo dõi lưu lượng và số lượng gói tin được bẻ hướng:

# Xem thông số XDP trên card mạng
ip -s link show dev eth0

# Đọc nhật ký hoạt động của chương trình BPF
bpftool prog tracelog

Ứng dụng thực tiễn trên hạ tầng RiceGuard và VPNRice

Trong mạng lưới trung chuyển toàn cầu của VPNRice, sự kết hợp giữa XDP_REDIRECT, devmap và cpumap tạo nên những lợi thế vận hành cốt lõi:

  1. Chuyển tiếp trung chuyển đạt tốc độ dây: Các nút trung chuyển biên tiếp nhận và bẻ hướng các gói tin RiceGuard mã hoá giữa các trung tâm dữ liệu qua devmap. Việc loại bỏ cấp phát sk_buff giúp mỗi cổng 100GbE duy trì thông lượng ổn định trên 30 Mpps.
  2. Cân bằng tải không khoá trên kiến trúc NUMA: Các máy chủ VPN tiếp nhận hàng chục nghìn phiên kết nối khách hàng. Nhờ cpumap, các gói tin được chuyển đến các lõi CPU thuộc đúng nút NUMA quản lý bộ nhớ cục bộ, giảm thiểu độ trễ giao tiếp liên socket.
  3. Khả năng chịu tải trước các đợt lưu lượng bất thường: Do các gói tin không hợp lệ bị phát hiện và huỷ ngay tại tầng driver trước khi vào hàng đợi của nhân, hệ thống máy chủ VPNRice luôn duy trì độ phản hồi ổn định ngay cả trong điều kiện mạng biến động.

Lưu ý kỹ thuật khi triển khai môi trường sản xuất

Khi đưa giải pháp XDP vào vận hành thực tế, cần chú trọng các điểm kỹ thuật sau:

  • Khả năng hỗ trợ của driver: Đảm bảo driver card mạng hỗ trợ thao tác ndo_xdp_xmit (như dòng card Mellanox mlx5, Intel i40e/ice hoặc Broadcom bnxt_en).
  • Cấu hình khoảng đệm (Headroom): Kiểm tra thông số vùng đệm gói tin (XDP_PACKET_HEADROOM) để cho phép chỉnh sửa tiêu đề gói tin mà không cần phân bổ lại bộ nhớ.
  • Đồng bộ MTU: Giữ kích thước MTU đồng nhất giữa cổng vào và cổng ra; nếu MTU không khớp, các gói tin vượt quá kích thước cho phép sẽ bị phần cứng huỷ bỏ mà không có thông báo lỗi.

Sự kết hợp của XDP_REDIRECT, devmap và cpumap giúp máy chủ Linux tiêu chuẩn đạt hiệu năng xử lý ngang tầm thiết bị mạng chuyên dụng, tạo nền tảng vững chắc cho hạ tầng VPN hiệu năng cao.