Вузькі місця маршрутизації трафіку в зашифрованих шлюзах VPN

Під час експлуатації потужних концентраторів VPN, шлюзів операторського класу та магістральних вузлів транзиту шифрованого трафіку системні адміністратори нерідко стикаються з апаратною межею продуктивності процесора. Навіть якщо сервер оснащено десятками сучасних процесорних ядер і швидкісними мережевими картами PCIe 4.0, пропускна здатність у пакетах за секунду (PPS) часто обмежується обробкою програмних переривань на одному ядрі задовго до вичерпання фізичної смуги каналу.

У класичному мережевому стеку Linux кожен транзитний пакет послідовно проходить через довгий ланцюг обробників підсистеми Netfilter:

[ Фізичний кабель ] 
          |
          v
[ Кільцевий буфер RX драйвера / NAPI Poll ]
          |
          v
[ Етап PREROUTING (conntrack, mangle, raw, dnat) ]
          |
          v
[ Прийняття рішення про маршрутизацію (fib_lookup) ]
          |
          v
[ Етап FORWARD (фільтрація пакетів, обмеження швидкості) ]
          |
          v
[ Етап POSTROUTING (snat, masquerade, mangle) ]
          |
          v
[ Розпізнавання сусідів (ARP/NDP) / Черга Egress Qdisc ]
          |
          v
[ Кільцевий буфер TX драйвера ] ---> [ Фізичний кабель ]

Кожен крок вимагає оновлення атомарних лічильників, блокування хеш-таблиць відстеження з'єднань (nf_conntrack_lock), виділення пам'яті під метадані пакетів (sk_buff) і повторних звернень до таблиці маршрутизації FIB. Коли шлюз підтримує тисячі одночасних тунелів (WireGuard, RiceGuard або IPsec), це навантаження стрімко зростає:

  1. Повторні перевірки для сталих з'єднань: Пакети, що належать до вже встановлених тривалих сесій TCP або UDP, змушені заново проходити повний перелік правил міжмережевого екрана та автомата conntrack.
  2. Конкуренція за лінії кеш-пам'яті: Хеш-таблиця відстеження сесій розподілена між усіма ядрами CPU. Інтенсивний потік пакетів викликає вибивання ліній кешу L3 (cache line bouncing).
  3. Подвійна затримка інкапсуляції: Пересилання розшифрованих пакетів у зовнішній інтернет або маршрутизація зовнішніх UDP-датаграм тунелю змушує пакети проходити ланцюг Netfilter повторно.

Для подолання цих обмежень без відмови від перевірки стану з'єднань у ядро Linux було інтегровано підсистему Netfilter Flowtable (створену Пабло Нейрою Аюсо та включену до складу ядра починаючи з версії 4.16).

Архітектура Ingress Fastpath підсистеми Netfilter Flowtable

Netfilter Flowtable є вбудованим у ядро механізмом кешування швидкісних шляхів для двоспрямованих потоків даних. Замість спрямування кожного пакета крізь повний ланцюг Netfilter, Flowtable фіксує сесію після завершення початкового погодження (ct state established) і створює прямий швидкісний маршрут безпосередньо на етапі вхідного приймання (ingress hook) драйвера мережевої карти.

                       [ Вхідний пакет на адаптері ]
                                      |
                                      v
                       +-----------------------------+
                       |    Flowtable Ingress Hook   |
                       +-----------------------------+
                                     / \
                     Потік знайдено?/   \   Новий потік?
                                   /     \
                                 ТАК      НІ
                                 /         \
                                v           v
         +-------------------------+     +-------------------------------+
         | Швидкісний шлях Fastpath|     | Класичний ланцюг Netfilter:   |
         | - Оновлення лічильників |     | - PREROUTING                  |
         | - Застосування NAT      |     | - Оцінка станів conntrack     |
         | - Зменшення TTL / MAC   |     | - Пошук маршруту fib_lookup   |
         | - Прямий трансфер у TX  |     | - FORWARD та POSTROUTING      |
         +-------------------------+     +-------------------------------+
                      |                                  |
                      |                          З'єднання встановлено?
                      |                                  |
                      |                                  v
                      |                       [ Запис у Flowtable ]
                      \                                  /
                       \                                /
                        v                              v
                      +----------------------------------+
                      |    dev_queue_xmit (Вихідний NIC) |
                      +----------------------------------+

Принцип роботи всередині ядра Linux

Головні функції підсистеми реалізовано у файлі net/netfilter/nf_flow_table_core.c. Коли пакет надходить на інтерфейс, призначений у Flowtable:

  1. Перехоплення на рівні Ingress: Функція nf_flow_offload_ip_hook() обробляє вхідний кадр на етапі NF_INET_INGRESS, до запуску ip_rcv() та ланцюга PREROUTING.
  2. Безблокувальний пошук кортежу (5-tuple): Захищена механізмом RCU (Read-Copy-Update) хеш-таблиця миттєво звіряє 5 ключових параметрів: IP відправника, IP одержувача, порт відправника, порт одержувача та протокол четвертого рівня.
  3. Миттєве виконання транзиту:
    • Зменшення TTL: Знижується значення Time-To-Live і перераховується контрольна сума IP-заголовка.
    • Трансляція NAT на місці: Якщо для з'єднання налаштовано SNAT або DNAT, Flowtable замінює адреси та порти безпосередньо в заголовку пакета.
    • Формування Ethernet-заголовка: MAC-адреса наступного вузла (збережена на етапі первинного погодження) підставляється в заголовок кадру без звернення до таблиці ARP.
    • Пряме передавання у драйвер: Пакет минає підсистему маршрутизації (ip_forward) і передається одразу в чергу вихідного інтерфейсу за допомогою dev_queue_xmit().

Коли в потоці з'являється прапорець завершення TCP FIN або RST, чи завершується період очікування, запис видаляється з Flowtable. Наступні службові пакети повертаються до стандартного стека Netfilter, зберігаючи точність фіксації завершення з'єднань.

Порівняння програмного Fastpath та апаратного розвантаження SmartNIC

Підсистема Flowtable пропонує два рівні прискорення залежно від обладнання сервера:

Критерій Стандартна маршрутизація Програмний Fastpath Flowtable Апаратне розвантаження SmartNIC
Місце перехоплення Декілька ланцюгів (Pre/Fwd/Post) NF_INET_INGRESS (Ядро) Апаратний ASIC / TCAM адаптера
Обробка conntrack Кожен пакет Лише перший пакет під час з'єднання Лише перший пакет під час з'єднання
Навантаження на CPU Високе (Всі ядра перевантажені) Низьке (Минає стек IP) 0% CPU для активних сесій
Затримка транзиту 15 – 35 мкс 4 – 8 мкс < 1.5 мкс
Продуктивність PPS 1.5 – 3.2 Mpps на ядро 6.5 – 12.0 Mpps на ядро Фізична швидкість лінії (100 Гбіт/с+)
Вимоги до плати Будь-яка мережева карта Будь-яка мережева карта Підтримка TC offload (Mellanox, Intel E810)

Апаратне прискорення через SmartNIC (Hardware Offload)

Якщо шлюз обладнано серверними мережевими картами з підтримкою апаратного розвантаження (такими як NVIDIA Mellanox ConnectX-5, ConnectX-6 Dx чи Intel E810), ядро Linux може завантажувати записи Flowtable безпосередньо в пам'ять TCAM мережевого адаптера.

Після активації параметра flags { offload; } у правилах nftables ядро транслює правила потоків і параметри NAT у команди контролера через інтерфейс switchdev. У цьому режимі транзитні пакети маршрутизуються і транслюються в оптичний порт силами самого адаптера без генерації переривань процесора сервера.

Ефективність Flowtable в архітектурі VPN-шлюзів

У шлюзах із високим навантаженням потік даних поділяється на дві частини:

  1. Зовнішній інкапсульований потік UDP: Пакети, що надходять з інтернету та прямують до криптографічного модуля шлюзу (wg0, riceguard0, tun0).
  2. Внутрішній розшифрований потік: Дані після розшифрування, які передаються між внутрішніми підмережами або спрямовуються через NAT назовні.

Застосування Flowtable до внутрішньої маршрутизації забезпечує значні переваги:

1. Звільнення ресурсів процесора для RiceGuard

У шлюзах із підтримкою RiceGuard, які обслуговують тисячі активних користувачів, зняття до 60% команд фільтрації на кожен пакет вивільняє ресурси ядер процесора для операцій шифрування ChaCha20-Poly1305. Це гарантує стабільну роботу шлюзу без втрати пакетів навіть за раптових стрибків трафіку.

2. Ліквідація джитера для голосового зв'язку та ігор

Потоки чутливого трафіку (VoIP SIP/RTP та ігровий трафік) використовують фіксовані параметри портів UDP. Завдяки Flowtable 99.8% таких пакетів передаються через швидкісний шлях. Час проходження через операційну систему зменшується з 25 до менш ніж 5 мікросекунд, що усуває проблеми порушення черговості пакетів між ядрами.

3. Поєднання з механізмами черг (QoS)

Після виходу зі швидкісного шляху через dev_queue_xmit() пакет надходить до дисципліни qdisc вихідного порту. Адміністратори можуть поєднувати Flowtable з FQ-CoDel або CAKE, забезпечуючи захист від bufferbloat за максимальної пропускної здатності каналу.

Налаштування nftables Flowtable на практиці

Робочий приклад конфігураційного файлу nftables для шлюзу VPN, що з'єднує зовнішній інтерфейс (eth0) та внутрішню мережу або тунель (eth1 / wg0):

#!/usr/sbin/nft -f

# Очищення старих правил
flush ruleset

table inet vpn_router {
    # 1. Створення таблиці Flowtable з прив'язкою до портів
    flowtable ft_fastpath {
        hook ingress priority filter
        devices = { eth0, eth1 }
        # Для активації апаратного розвантаження на сумісних картах розкоментуйте:
        # flags { offload; }
    }

    # 2. Ланцюг маршрутизації (Forward chain)
    chain forward {
        type filter hook forward priority filter; policy drop;

        # Спрямування встановлених сесій TCP та UDP у швидкісний шлях
        meta l4proto { tcp, udp } flow add @ft_fastpath

        # Дозвіл сталого та пов'язаного трафіку звичайним шляхом
        ct state established,related accept

        # Скидання некоректних пакетів
        ct state invalid drop

        # Дозвіл нових з'єднань із внутрішньої мережі назовні
        iifname "eth1" oifname "eth0" accept
    }

    # 3. Трансляція адрес (SNAT / Masquerade)
    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;

        # Маскування вихідного трафіку на порту WAN
        oifname "eth0" masquerade
    }
}

Перевірка та моніторинг функціонування

Після застосування конфігурації перевірте стан потоків у Flowtable:

# Перегляд активних сесій у таблиці Flowtable та лічильників
nft list flowtable inet vpn_router ft_fastpath

# Перевірка системної статистики налагодження через sysfs
cat /sys/kernel/debug/netfilter/nf_flowtable/*

# Порівняння лічильників conntrack між звичайним та швидким шляхами
cat /proc/net/stat/nf_conntrack

У звіті команди nft list flowtable відображається кількість переданих байтів та пакетів за кожною сесією. Якщо ввімкнено апаратне розвантаження, біля потоків з'являється статус [OFFLOAD], що підтверджує перенесення обробки безпосередньо на контролер мережевої плати.

Практичні поради для впровадження

  1. Фрагментація пакетів (Fragmentation): Flowtable не виконує збирання фрагментованих пакетів IP. Фрагменти без повного заголовка четвертого рівня автоматично перенаправляються до класичного стека conntrack. Обов'язково налаштовуйте TCP MSS clamping або механізм Path MTU Discovery на портах тунелів.
  2. Оновлення ключів шифрування (Re-keying): Тунелі на зразок WireGuard періодично виконують зміну сесійних ключів. Ці керуючі пакети передаються звичайним шляхом і не впливають на безперервність потоків у Flowtable.
  3. Підтримка віртуальних адаптерів: Flowtable можна безперешкодно прив'язувати до субінтерфейсів VLAN (eth0.100) та об'єднаних каналів Bonding (bond0), що робить технологію універсальною для сучасних хмарних дата-центрів.

Перехід від поштучної обробки кожного пакета до одноразової реєстрації з'єднання дозволяє шлюзам VPN на базі Linux демонструвати максимальну швидкість обробки даних із мінімальними затримками.