Експлуатація шлюзів віртуальних приватних мереж (VPN), периферійних ретрансляторів та транзитних вузлів під навантаженням екстремального мережевого трафіку ставить серйозні архітектурні завдання. На сучасних інтерфейсах 40GbE та 100GbE інтенсивність вхідного потоку часто перевищує від 20 до 50 мільйонів пакетів на секунду (Mpps).
За таких показників класичний мережевий стек ядра Linux стикається з фундаментальним обмеженням кількості оброблених пакетів на секунду (PPS). У стандартному контурі кожен вхідний кадр викликає виділення кільцевих буферів драйвера, ініціалізацію дескрипторів Socket Buffer (sk_buff), пошук у таблицях маршрутизації FIB, обробку перевірок у підсистемі відстеження з'єднань Netfilter (conntrack) та блокування ресурсів ядра.
Навіть із використанням апаратного механізму Receive Side Scaling (RSS), накладні витрати процесора на створення та звільнення об'єктів sk_buff обмежують пропускну здатність одного ядра CPU на рівні приблизно 2–4 Mpps.
Щоб досягти повної фізичної швидкості лінії передачі без виходу за межі екосистеми Linux, системні інженери використовують підсистему eXpress Data Path (XDP) у поєднанні з вердиктом XDP_REDIRECT та двома спеціалізованими типами карт BPF: devmap і cpumap.
+--------------------------------------------------------------------------+
| АРХІТЕКТУРА МАРШРУТИЗАЦІЇ ПАКЕТІВ LINUX EBPF XDP_REDIRECT |
+--------------------------------------------------------------------------+
| |
| Вхідний фізичний трафік (100GbE SFP28 / оптоволокно) |
| │ |
| v |
| Кільцевий буфер прийому RX мережевої карти (DMA-доступ) |
| │ |
| v (Сирий буфер xdp_buff - без виділення sk_buff)|
| +-------------------------------------------------------------+ |
| | ТОЧКА ОБРОБКИ XDP У ДРАЙВЕРІ (eBPF) | |
| | | |
| | - Аналіз заголовків L2-L4 (IP, UDP, WireGuard/RiceGuard) | |
| | - Пошук за картою BPF (devmap або cpumap) | |
| | - Видача вердикту переспрямування XDP_REDIRECT | |
| +-------------------------------------------------------------+ |
| │ │ |
| v (XDP_REDIRECT до devmap) v (cpumap) |
| +-------------------------------+ +---------------+ |
| | BPF_MAP_TYPE_DEVMAP | | BPF_CPUMAP | |
| | Ціль: вихідне кільце TX порту | | Ціль: CPU N | |
| +-------------------------------+ +---------------+ |
| │ │ |
| v (Пряме надсилання без копіювання) v |
| Фізична передача на швидкості каналу Обробник SoftIRQ |
| (30+ Mpps на рівні драйвера адаптера) (Дешифрування пакетів)|
| |
+--------------------------------------------------------------------------+
Фундаментальні механізми XDP_REDIRECT
Підсистема eXpress Data Path (XDP) надає можливість виконання коду eBPF безпосередньо у драйвері мережевої карти ще до того, як ядро виділить пам'ять під структуру sk_buff. Працюючи з компактними буферами xdp_buff, XDP може повертати п'ять стандартних вердиктів:
XDP_DROP: Миттєве скидання пакета, призначене для нейтралізації масованих мережевих атак.XDP_TX: Відправлення кадру назад через той самий мережевий інтерфейс.XDP_PASS: Передача пакета у звичайний стек ядра Linux для стандартної обробки.XDP_ABORTED: Фіксація помилки виконання програми з подальшим скиданням пакета.XDP_REDIRECT: Пряме переспрямування необробленого кадру на інший мережевий пристрій або процесорне ядро.
Якщо раніше XDP переважно застосовували для високошвидкісного відкидання пакетів (XDP_DROP), то в сучасних шлюзах VPN ключову роль відіграє XDP_REDIRECT. За допомогою функції ядра bpf_redirect_map() програма скеровує необроблені кадри безпосередньо у потрібний адаптер або на конкретне ядро процесора із затримкою менше мікросекунди.
Високопродуктивна транзитна передача через devmap
Структура devmap (BPF_MAP_TYPE_DEVMAP та BPF_MAP_TYPE_DEVMAP_HASH) зберігає в пам'яті ядра масив або геш-таблицю числових ідентифікаторів цільових мережевих інтерфейсів.
Коли програма XDP спрямовує пакет до devmap, ядро Linux пропускає весь вищий мережевий стек: скасовуються запити до таблиць маршрутизації IP, оминаються ланцюжки Netfilter і черги пакетів (qdisc). Вхідний xdp_buff одразу надходить до кільця передачі (TX) інтерфейсу призначення.
+--------------------------------------------------------------------------+
| ПОРІВНЯННЯ ТРАЄКТОРІЙ: СТАНДАРТНИЙ IP-СТЕК ТА XDP DEVMAP |
+--------------------------------------------------------------------------+
| Етап обробки | Стандартний стек IP ядра | Переспрямування devmap|
+------------------------+--------------------------+-----------------------+
| Точка перехоплення | Опитування NAPI драйвера | Нативний драйвер XDP |
| Структура пам'яті | Важкий sk_buff (~256 B) | Легкий xdp_buff |
| Рішення про передачу | Пошук FIB Trie/Hash | O(1) індекс карти BPF |
| Фільтрація і Conntrack | Перевірка у Netfilter | Повністю виключено |
| Механізм надсилання | dev_queue_xmit (qdisc) | Прямий ndo_xdp_xmit |
| Пропускна здатність | ~2-4 Mpps на ядро | ~25-35 Mpps на ядро |
+--------------------------------------------------------------------------+
Програмна реалізація devmap мовою C (eBPF)
Нижче наведено приклад робочої програми eBPF для передачі транзитного тунельного трафіку між двома мережевими картами 100GbE:
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <bpf/bpf_helpers.h>
/* Створення карти devmap для збереження індексів портів */
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;
/* Перевірка та розбір заголовка Ethernet */
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end)
return XDP_PASS;
/* Аналіз пакетів 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;
/* Скерування транзитного трафіку на вихідний порт 2 */
__u32 target_ifindex = 2;
/* Виконання переспрямування на рівні драйвера без копіювання */
return bpf_redirect_map(&tx_port_map, target_ifindex, 0);
}
char _license[] SEC("license") = "GPL";
Розподіл криптографічного навантаження за допомогою cpumap
Для звичайного транзитного пересилання таблиця devmap демонструє максимальну швидкість. Однак у роботі захищених протоколів VPN (таких як WireGuard і RiceGuard) потрібні значні обчислювальні ресурси CPU для дешифрування алгоритмів ChaCha20-Poly1305 або AES-GCM.
Головна проблема виникає, коли великий обсяг зашифрованих пакетів потрапляє в одну чергу прийому мережевої карти. Якщо процесорне ядро, прив'язане до цієї черги, одночасно бере на себе апаратні переривання і важкі математичні операції дешифрування, його завантаження сягає 100 %, тоді як решта ядер сервера залишаються вільними.
Карта cpumap (BPF_MAP_TYPE_CPUMAP) ефективно усуває цю проблему:
- Попереднє сортування в драйвері: Програма XDP працює на ядрі, що приймає трафік, зі швидкістю фізичного каналу та зчитує метадані пакетів.
- Детерміноване гешування сесій: Код обчислює геш потоку за чотирма параметрами (IP джерела/призначення, порти) і призначає цільове ядро CPU.
- Переспрямування у чергу процесора: Виклик
bpf_redirect_map(&cpu_map, target_cpu, 0)передає сирий кадр у кільцеву чергу призначеного ядра. - Асинхронне виділення пам'яті: Цільове ядро дістає пакет, створює структуру
sk_buffі паралельно розшифровує дані всередині власного контексту softirq.
Вхідний потік 100GbE (Єдина черга RX)
│
v
Ядро 0 (Аналізатор XDP)
[ Розрахунок гешу потоку за 4 параметрами ]
│
┌─────┴─────────────────────────┐
│ bpf_redirect_map(&cpu_map) │
▼ ▼
Ядро 1 (Обробник SoftIRQ) Ядро 2 (Обробник SoftIRQ)
Виділення пам'яті sk_buff Виділення пам'яті sk_buff
Дешифрування RiceGuard Дешифрування RiceGuard
Цей підхід повністю ізолює обслуговування черг мережевого адаптера від криптографічних задач, запобігаючи блокуванню черг обробки на багатоядерних серверах.
Практичне налаштування та запуск у середовищі Linux
Розгортання переспрямування трафіку на основі XDP виконується за допомогою стандартних інструментів екосистеми BPF:
Крок 1: Компіляція програми eBPF
Виконайте компіляцію вихідного коду C за допомогою Clang для цільової архітектури BPF:
clang -O2 -g -target bpf -c xdp_forward.c -o xdp_forward.o
Крок 2: Завантаження програми XDP на мережевий інтерфейс
Підключіть скомпільований об'єктний файл у нативному режимі драйвера:
# Вимкнення універсального режиму та запуск у нативному драйвері
ip link set dev eth0 xdpgeneric off
ip link set dev eth0 xdpdrv object xdp_forward.o section xdp
Крок 3: Заповнення таблиці devmap
Запишіть індекс вихідного порту (наприклад, eth1) у прикріплену карту BPF:
# Визначення системного індексу для eth1
IFINDEX_ETH1=$(cat /sys/class/net/eth1/ifindex)
# Оновлення значень у карті devmap за допомогою bpftool
bpftool map update pinned /sys/fs/bpf/tx_port_map \
key 2 0 0 0 \
value $IFINDEX_ETH1 0 0 0
Крок 4: Моніторинг показників продуктивності
Перевіряйте лічильники переданих та оброблених пакетів:
# Перегляд статистики інтерфейсу та стану XDP
ip -s link show dev eth0
# Перегляд журналів виконання програми BPF
bpftool prog tracelog
Інтеграція технологій у мережу RiceGuard та VPNRice
У глобальній інфраструктурі ретрансляторів VPNRice спільне застосування XDP_REDIRECT, devmap та cpumap забезпечує високі показники надійності:
- Транзитна передача на швидкості фізичного інтерфейсу: Проміжні вузли мережі пересилають шифрований трафік тунелів WireGuard та RiceGuard безпосередньо через
devmap. Відсутність створення важких об'єктівsk_buffдозволяє одному серверу стабільно передавати понад 30 Mpps на кожному порту 100GbE. - Балансування з урахуванням структури NUMA: На великих концентраторах з десятками тисяч клієнтських сесій
cpumapрозподіляє трафік виключно між ядрами того вузла NUMA, до якого фізично підключено мережевий адаптер, що мінімізує затримки звернення до оперативної пам'яті. - Захист від аномальних сплесків трафіку: Некоректні та неавторизовані пакети відсікаються ще всередині драйвера адаптера, не навантажуючи пам'ять ядра та забезпечуючи стабільну роботу шлюзів.
Інженерні рекомендації для виробничих систем
Під час експлуатації механізмів переспрямування XDP важливо дотримуватися таких технічних умов:
- Сумісність драйверів: Переконайтеся, що мережевий драйвер має нативну підтримку виклику
ndo_xdp_xmit(зокрема драйвери Mellanoxmlx5, Inteli40e/iceта Broadcombnxt_en). - Резервування пам'яті заголовка: Драйвер повинен підтримувати достатній запас пам'яті (
XDP_PACKET_HEADROOM) для модифікації заголовків кадру без повторного виділення буфера. - Узгодження розміру MTU: Значення Maximum Transmission Unit (MTU) на вхідному та вихідному інтерфейсах має бути однаковим. Якщо пакет після переспрямування перевищує допустимий розмір MTU вихідного адаптера, обладнання безслідно відкидає такі дані.
Використання XDP_REDIRECT, devmap та cpumap перетворює сервери Linux на високоефективні комунікаційні шлюзи, закладаючи надійну платформу для швидкісних сучасних систем VPN.



