Высокопроизводительные VPN-шлюзы и граничные узлы безопасности одновременно обрабатывают два различных класса сетевого трафика: трафик локальной терминации (зашифрованные туннели WireGuard или IPsec, направляемые в локальные сокеты хоста) и транзитный трафик пересылки (декапсулированные пользовательские пакеты, направляемые через сетевые интерфейсы в глобальную сеть WAN). В сетевом стеке ядра Linux организация пути между входящей классификацией пакетов и просмотром таблицы маршрутизации напрямую определяет масштабируемость системы.

Механизм IP Early Demux (ip_early_demux) был внедрен в ядро Linux с целью исключения повторных обращений к дереву маршрутизации FIB (Forwarding Information Base) для уже установленных сетевых соединений. Однако на серверах, которые одновременно выполняют роль криптографических терминаторов туннелей и высоконагруженных маршрутизаторов пересылки, настройка Early Demux требует четкого понимания заложенных архитектурных компромиссов.


Дилемма маршрутизации: Просмотр FIB Trie против Кэширования сокетов

Чтобы понять назначение IP Early Demux, проанализируем стандартный маршрут входящего пакета IPv4 после выхода из драйвера сетевого адаптера (NIC):

  1. Прием пакета: Пакет поступает на сетевой уровень стека через функцию ip_rcv() и передается в ip_rcv_finish_core().
  2. Стандартный поиск маршрута: По умолчанию ядро сразу вызывает ip_route_input_noref() для опроса дерева FIB trie. Этот алгоритм анализирует IP-адрес назначения, IP-адрес источника, метки политик маршрутизации (fwmark) и входящий интерфейс, определяя, предназначен ли пакет локальной системе (RTN_LOCAL) или подлежит дальнейшей пересылке (RTN_UNICAST).
  3. Демультиплексирование в локальный сокет: Если результат маршрутизации равен RTN_LOCAL, выполнение передается в ip_local_deliver(). На транспортном уровне (TCP или UDP) выполняется поиск по хэш-таблице сокетов (inet_lookup_established или хэш-таблице портов UDP) для нахождения целевой структуры struct sock.
[ Входящий пакет IPv4 ]
          │
          ▼
[ Стандартный путь: ip_rcv_finish_core() ]
          │
          ▼
[ Поиск в дереве FIB Trie: ip_route_input_noref() ] ──► (Расход процессорных циклов)
          │
          ├─► Если локальный (RTN_LOCAL) ──► ip_local_deliver() ──► Хэш-таблица сокетов
          └─► Если пересылаемый (RTN_UNICAST) ──► ip_forward()

На шлюзе, обрабатывающем 5 миллионов пакетов в секунду по тысячам параллельных туннелей VPN, регулярное сканирование дерева FIB trie для каждого отдельного пакета создает значительную нагрузку на шину памяти и приводит к вымыванию кэша процессора уровней L2 и L3.


Архитектурный механизм: Прямой переход Early Demux без опроса FIB

IP Early Demux меняет очередность операций для активных сетевых потоков. До обращения к подсистеме маршрутизации FIB ядро предпринимает попытку упреждающего поиска сокета непосредственно из функции ip_rcv_finish_core().

[ Входящий пакет IPv4 ]
          │
          ▼
[ Early Demux: ip_rcv_finish_core() ]
          │
          ▼
[ Упреждающий поиск сокета: tcp_v4_early_demux() / udp_v4_early_demux() ]
          │
          ├─► Совпадение найдено (sk->sk_rx_dst валиден):
          │         │
          │         ├─► Прямое назначение маршрута из кэша (skb_dst_set_noref)
          │         └─► Переход сразу в ip_local_deliver() [Без опроса FIB trie]
          │
          └─► Нет локального совпадения:
                    │
                    └─► Возврат к стандартному поиску через ip_route_input_noref()

В исходном коде ядра (net/ipv4/ip_input.c) Early Demux вызывает специализированные обработчики протоколов:

/* Концептуальная схема работы в net/ipv4/ip_input.c */
static int ip_rcv_finish_core(struct net *net, struct sock *sk,
                             struct sk_buff *skb, struct net_device *dev,
                             const struct sk_buff *hint)
{
    const struct iphdr *iph = ip_hdr(skb);

    if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb)) {
        const struct net_protocol *ipprot;
        int protocol = iph->protocol;

        ipprot = rcu_dereference(inet_protos[protocol]);
        if (ipprot && ipprot->early_demux)
            ipprot->early_demux(skb);
    }

    /* Если запись маршрута установлена early_demux, поиск в FIB опускается */
    if (!skb_dst(skb)) {
        int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
                                      iph->tos, dev);
        if (unlikely(err))
            goto drop;
    }
    return NET_RX_SUCCESS;
}

Механизм кэширования маршрута (sk_rx_dst)

При установке TCP-соединения или при работе сокетов UDP в подключенном режиме (через системный вызов connect()) ядро сохраняет параметры входящего маршрута в поле sk->sk_rx_dst.

Во время выполнения tcp_v4_early_demux() ядро считывает кортеж адресов и портов из заголовков IP и TCP, находит установленный сокет и проверяет актуальность записи sk->sk_rx_dst. Если кэш действителен, ссылка привязывается к skb->_skb_refdst с помощью skb_dst_set_noref(skb, dst). Пакет немедленно отправляется на локальную обработку, полностью исключая задержки на уровне таблицы маршрутизации.


Эксплуатационные особенности: Терминация туннелей против Транзитной пересылки

Хотя Early Demux обеспечивает ощутимый прирост производительности для локального трафика, на гибридных шлюзах VPN возникают сопутствующие эксплуатационные факторы:

  • Непродуктивные обращения при транзите: Когда шлюз пересылает декапсулированный клиентский трафик во внешние интерфейсы, эти пакеты не предназначены локальным сокетам хоста. Если Early Demux активен, ядро выполняет холостой поиск в хэш-таблице сокетов для каждого транзитного пакета, что приводит к промаху и последующему возврату к дереву FIB.
  • Риск задержки обновления при асимметричной маршрутизации: При динамическом изменении многопутевой маршрутизации (ECMP) кэшированная запись sk_rx_dst может кратковременно направлять данные по прежним параметрам до момента проверки валидности сокетом.
+-------------------------------------------------------------------------+
|                  Сценарии развертывания на VPN-шлюзах                   |
+-------------------------------------------------------------------------+
| Сценарий А: Узел терминации туннелей (Серверы RiceGuard / WireGuard)    |
| -> Пакеты направлены в локальные сокеты (инкапсуляция UDP)              |
| -> Оптимизация: Включить ip_early_demux и udp_early_demux               |
|                                                                         |
| Сценарий Б: Выделенный маршрутизатор транзитной пересылки               |
| -> Пакеты курсируют между WAN и внутренними сетями                      |
| -> Оптимизация: Отключить ip_early_demux для устранения холостых хэшей  |
+-------------------------------------------------------------------------+

Настройка параметров Early Demux в операционной системе Linux

В ядре Linux предусмотрены системные параметры sysctl для глобального и протокольного управления Early Demux.

1. Проверка текущих системных значений

Оцените текущую конфигурацию на сервере:

# Просмотр активных параметров Early Demux
sysctl net.ipv4.ip_early_demux
sysctl net.ipv4.tcp_early_demux
sysctl net.ipv4.udp_early_demux

2. Настройка узлов терминации зашифрованных туннелей

На шлюзах, основная нагрузка которых связана с приемом и дешифрованием VPN-трафика (например, узлы RiceGuard, принимающие миллионы кадров UDP), включите упреждающее демультиплексирование для обоих протоколов:

# Включение общего механизма Early Demux
sysctl -w net.ipv4.ip_early_demux = 1

# Включение для TCP (панели управления и веб-интерфейсы)
sysctl -w net.ipv4.tcp_early_demux = 1

# Включение для UDP (подключенные сокеты туннелей)
sysctl -w net.ipv4.udp_early_demux = 1

Для сохранения параметров после перезагрузки добавьте их в /etc/sysctl.d/99-early-demux.conf:

cat << 'EOF' > /etc/sysctl.d/99-early-demux.conf
net.ipv4.ip_early_demux = 1
net.ipv4.tcp_early_demux = 1
net.ipv4.udp_early_demux = 1
EOF
sysctl --system

3. Настройка узлов чистой транзитной пересылки и NAT

Если сервер функционирует исключительно как маршрутизатор пересылки декапсулированного пользовательского трафика без терминации сокетов, отключение Early Demux экономит ресурсы процессора:

# Отключение на транзитных маршрутизаторах
sysctl -w net.ipv4.ip_early_demux = 0

4. Контроль эффективности кэша с помощью nstat

Контролируйте успешность срабатывания упреждающего поиска и статистику сетевого стека утилитой nstat:

# Просмотр статистики совпадений Early Demux и объема маршрутизации
nstat -az | grep -E "IpEarlyDemux|IpInReceives|IpForwDatagrams"

Сравнительный анализ: Включение и Отключение Early Demux

Результаты работы механизма Early Demux зависят от структуры входящих сетевых потоков:

Параметр оценки Early Demux включен (Локальные сокеты) Early Demux выключен (Базовый путь) Early Demux на транзитном узле
Нагрузка на FIB Trie Исключается для установленных сессий Выполняется для каждого пакета Запрос в FIB плюс холостой поиск
Нагрузка на кэш L2/L3 Локализована в хэш-таблице сокетов Распределена по дереву FIB trie Выше из-за двойного обращения
Интенсивность PPS Устойчивые 7.8 Mpps на ядро Стабильные 5.9 Mpps на ядро Незначительное снижение (~4%)
Задержка пересылки Стандартная (с возвратом в FIB) Минимальная детерминированная Дополнительные 3-5% на малых пакетах
Риск устаревания кэша Минимален (проверка валидности) Полностью отсутствует Отсутствует (нет совпадений)

Архитектурное разделение в инфраструктуре RiceGuard

В глобальной платформе VPNRice узлы RiceGuard реализуют разделение входящей терминации и последующей пересылки:

  1. Входные внешние интерфейсы: Сетевые интерфейсы, принимающие входящий зашифрованный трафик клиентов по UDP, работают с параметрами net.ipv4.ip_early_demux = 1 и net.ipv4.udp_early_demux = 1. Кадры WireGuard мгновенно сопоставляются с открытыми сокетами и поступают в конвейер криптографической обработки RiceGuard минуя задержки таблицы маршрутизации.
  2. Выходные транзитные интерфейсы: Сетевые пространства имен (namespaces), отвечающие за дальнейшую пересылку декапсулированного трафика клиентов, используют net.ipv4.ip_early_demux = 0. Это позволяет механизму маршрутизации обрабатывать запросы в дереве FIB trie напрямую без холостых проверок сокетов.
  3. Изоляция управляющего контура и DNS: Административные интерфейсы TCP и защищенные серверы разрешения DNS работают в выделенных пространствах с tcp_early_demux = 1, что обеспечивает мгновенную обработку запросов и предотвращение утечек DNS.