Техническая глубина
Настройка сетевого стека Linux против DDoS: очереди NIC, RSS/RPS и XDP
Обновлено: август 2026 г. · Очереди NIC, распределение пакетов, привязка IRQ и XDP · Время чтения ~21 мин

Когда атака измеряется не полосой, а частотой пакетов, одно ядро CPU уходит в 100% softirq, а остальные простаивают, и sysctl тут бессилен. Лечит слой драйвера и прерываний: кольцевые буферы NIC, RSS/RPS/RFS для распределения пакетов по ядрам, привязка IRQ и XDP для отбрасывания в драйвере до стека. Это дополнение к укреплению sysctl со стороны частоты пакетов.
Это руководство — дополнение по частоте пакетов к руководству по укреплению сервера Linux. То руководство защищает состояние соединений с помощью sysctl: очереди SYN, conntrack, дескрипторы. Это же защищает путь обработки пакетов. NIC, его очереди, прерывания и путь приёма — то есть всё, что включается, когда атака измеряется числом пакетов в секунду, а не состоянием.
Симптом, который приводит вас сюда, очень конкретен. Одно ядро CPU закреплено на уровне около
100% в softirq, пока остальные простаивают, а полоса далеко ниже предела канала. Флуд из мелких
пакетов способен насытить обработку пакетов на одном ядре задолго до того, как заполнит канал, и ни
один sysctl из другого руководства этого не касается. Каждая настройка ниже идёт со своей командой
ethtool или sysfs и со счётчиком, который показывает её работу.
| Устройство | Симптом | Слой | Команда |
|---|---|---|---|
| Одно ядро на 100% softirq, остальные простаивают | Распределение RSS / RPS, привязка IRQ | ethtool -L; /sys .../rps_cpus; /proc/irq | |
| Растёт столбец softnet 'dropped' | Кольцевой буфер NIC; netdev backlog/budget | ethtool -G; sysctl net.core.netdev_* | |
| Растёт столбец softnet 'squeezed' | Бюджет softirq; объединение прерываний | netdev_budget; ethtool -C | |
| Высокий pps мусора доходит до стека | Отбрасывание XDP в драйвере, до conntrack | ip link set ... xdp; небольшая программа XDP | |
| Теряется локальность потока между ядрами | RFS (receive flow steering) | rps_flow_cnt; rps_sock_flow_entries |
Каждая строка относится к слою драйвера и прерываний, ниже укрепления sysctl из руководства по серверу Linux. Симптом, который приводит вас сюда, — это CPU в softirq при полосе далеко ниже предела. Ничто из этого не помогает, когда заполнен сам канал.
0. Сначала базовые показатели: посмотрите, где пакеты и где CPU
Самое важное чтение — время softirq по ядрам и статистика softnet:
# softirq по ядрам — одно ядро горячее, пока остальные простаивают?
mpstat -P ALL 1 3 # смотрите столбец %soft по каждому CPU
# или
watch -n1 "grep . /proc/softirqs | head"
# softnet_stat: столбец1 обработано, столбец2 СБРОШЕНО, столбец3 время/бюджет SQUEEZED (по CPU, hex)
cat /proc/net/softnet_stat
# Какие IRQ срабатывают и на каком CPU
cat /proc/interrupts | grep -Ei 'eth|ens|enp|mlx|i40e|ixgbe'
# Сбросы и ошибки на уровне NIC
ethtool -S eth0 | grep -Ei 'drop|miss|error|fifo|rx_no_buffer'
Одно горячее ядро %soft при простаивающих остальных — это подпись частоты пакетов. Второй столбец
softnet_stat (сбросы) и третий (squeezed) говорят, в чём ограничение — в backlog или в бюджете.
Это базовые показатели, относительно которых оценивается каждое изменение ниже.
1. Кольцевые буферы NIC: первое место, где теряются пакеты
Кольцевой буфер приёма — это место, куда NIC складывает пакеты для приёма ядром. Под флудом пакетами недостаточный по размеру буфер сбрасывает пакеты ещё до того, как любое распределение успевает помочь:
# Текущие и максимальные размеры кольца
ethtool -g eth0
# Поднимите RX (и TX) к максимуму, который поддерживает NIC
ethtool -G eth0 rx 4096 tx 4096
# Убедитесь, что счётчик сбросов перестал расти после изменения
ethtool -S eth0 | grep -Ei 'rx_no_buffer|rx_missed|fifo'
Большее кольцо стоит немного памяти и задержки; на сервере, принимающем флуд пакетами, эта сделка
почти всегда оправданна. Если rx_no_buffer_count продолжает расти при максимальном размере кольца,
ограничение сместилось в CPU, а это тема следующих разделов.
2. RSS: распределите обработку приёма по ядрам в аппаратуре
Receive Side Scaling хеширует входящие потоки в несколько очередей приёма NIC, каждая со своим прерыванием на своём ядре. Это самый эффективный способ не дать одному ядру стать узким местом:
# Сколько combined/приёмных каналов у NIC и сколько включено?
ethtool -l eth0
# Включите столько combined-очередей, сколько ядер можете выделить на их обслуживание
ethtool -L eth0 combined 8
# Показать таблицу перенаправления RSS (в какую очередь идёт каждая корзина хеша)
ethtool -x eth0
# После включения /proc/interrupts должен показать IRQ NIC распределёнными по ядрам,
# а mpstat — %soft распределённым, а не одним горячим ядром
mpstat -P ALL 1 3
RSS — первый выбор, потому что распределение происходит в аппаратуре и без затрат CPU. Его предел — число очередей, которое даёт NIC. Там, где их слишком мало, что типично для виртуализированных NIC, пробел закрывает программный RPS.
3. RPS и RFS: программное распределение там, где аппаратуры не хватает
Receive Packet Steering распределяет пакеты по ядрам в ядре системы; Receive Flow Steering добавляет локальность потока, чтобы поток попадал на ядро, где работает его приложение:
# RPS: задать маску CPU (hex-битовая маска ядер) для очереди приёма
echo ff > /sys/class/net/eth0/queues/rx-0/rps_cpus
# RFS: сначала размер глобальной таблицы потоков, затем на очередь
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt
# Проверьте, что распределение сместилось: ни одно ядро не должно нести всю нагрузку softirq
grep NET_RX /proc/softirqs
Включайте RPS для каждой очереди приёма с маской, исключающей ядра, зарезервированные под приложение.
RFS поверх отправляет пакеты одного потока на одно ядро, что помогает локальности кэша. Задавайте
rps_sock_flow_entries и rps_flow_cnt на очередь вместе.
4. Привязка IRQ: закрепите очереди, подумайте об отключении irqbalance
Когда очереди RSS на месте, закрепление прерывания каждой очереди за выделенным ядром делает
распределение предсказуемым, вместо того чтобы позволить irqbalance двигать его под нагрузкой:
# Найти номера IRQ NIC по очередям
grep -Ei 'eth0|ens|enp' /proc/interrupts | awk '{print $1}' | tr -d ':'
# Закрепить IRQ за конкретным ядром (записать hex-маску ядра в smp_affinity)
echo 2 > /proc/irq/145/smp_affinity # ядро 1
echo 4 > /proc/irq/146/smp_affinity # ядро 2
# На выделенном хосте с высокой частотой остановить перетасовку irqbalance
systemctl stop irqbalance
systemctl disable irqbalance
Отключать ли irqbalance — решение по измерению, а не универсальное. На выделенном хосте под атакой
по частоте пакетов ручное закрепление предсказуемее; на сервере общего назначения irqbalance обычно
достаточен. Зарезервируйте ядра, несущие прерывания NIC, и держите приложение в стороне от них.
5. Бюджет softirq и объединение прерываний
Если третий столбец softnet_stat (squeezed) растёт, обработчик softirq упирается в бюджет и уступает,
не опустошив очередь. Поднимите бюджет и используйте объединение, чтобы срезать накладные расходы
прерываний на пакет:
# Поднять, сколько пакетов и как долго может обрабатывать один проход softirq
sysctl -w net.core.netdev_budget=60000
sysctl -w net.core.netdev_budget_usecs=8000
sysctl -w net.core.netdev_max_backlog=250000
# Объединение прерываний: группировать прерывания; adaptive повышает по мере роста частоты
ethtool -C eth0 adaptive-rx on rx-usecs 64
# Столбец squeezed (3-й в строке) должен перестать расти
awk '{print strtonum("0x"$3)}' /proc/net/softnet_stat
Объединение под флудом меняет немного задержки на много эффективности. Прежде чем закрепить агрессивный
rx-usecs, измерьте чувствительный к задержке путь в обычной работе.
6. Разгрузки: что оставить, а что отключить под атакой
Разгрузки без состояния (контрольная сумма, GRO/GSO/TSO) обычно помогают и должны оставаться включёнными. Единственная, которую стоит проверить, — LRO, потому что она объединяет пакеты так, что может мешать маршрутизации и части инспекции:
# Показать состояние разгрузок
ethtool -k eth0 | grep -Ei 'gro|gso|tso|lro|rx-checksum'
# Generic Receive Offload обычно помогает; оставьте включённым
ethtool -K eth0 gro on
# LRO выключить, если хост маршрутизирует/мостит или нужна видимость по пакетам
ethtool -K eth0 lro off
7. XDP: отбрасывайте в драйвере, до стека
Для флуда по частоте пакетов, который слой распределения не может рассеять, XDP — единственный инструмент хоста, меняющий порядок величины. Он запускает небольшую программу в драйвере, до того как пакет попадает в сетевой стек. До conntrack, до nftables, до выделения памяти. И может отбрасывать миллионы пакетов в секунду за долю того CPU, что этот же сброс стоит позже:
# Прикрепить скомпилированную программу XDP (отбрасывает по своему критерию)
ip link set dev eth0 xdp obj xdp_drop.o sec xdp
# Убедиться, что прикреплена и в каком режиме (native лучше всего; generic — запасной)
ip link show eth0 | grep -o 'xdp[a-z]*'
# Открепить
ip link set dev eth0 xdp off
Нативный XDP требует поддержки драйвера; без неё программа работает в generic-режиме с меньшей пользой. XDP сложнее остальных разделов и не первый инструмент. Но когда атака — это число пакетов в секунду, а распределение исчерпано, отбрасывание в драйвере — это то, что выделенное устройство делает в аппаратуре, выполненное программно на краю хоста.
Сигналы для подключения к мониторингу
# 1. softirq по ядрам — подпись горячего ядра
mpstat -P ALL 1 1 | awk '/%soft|Average/{print}'
# 2. сбросы и squeezed в softnet
awk '{d+=strtonum("0x"$2); s+=strtonum("0x"$3)} END{print "dropped",d,"squeezed",s}' /proc/net/softnet_stat
# 3. сбросы на уровне NIC
ethtool -S eth0 | grep -Ei 'rx_no_buffer|rx_missed|drop'
# 4. общая частота прерываний
grep NET_RX /proc/softirqs
Одно горячее ядро с растущим счётчиком squeezed — подпись частоты пакетов; рост сбросов NIC при максимальном кольцевом буфере означает, что узкое место — CPU, а не кольцо, и следующий ход — распределение или XDP.
Честный предел этого слоя
Этот слой защищает от частоты пакетов — от числа пакетов в секунду, насыщающего CPU, что может ударить далеко ниже предела полосы. Два случая лежат вне его.
Первый — полоса. Если атака заполняет канал доступа, пакеты отбрасываются выше по потоку до того, как их увидит NIC, и ни очередь, ни распределение, ни XDP не срабатывают.
Второй — исчерпание состояния, а это тема другого руководства: таблицы соединений и очереди, а не обработка пакетов. Два руководства вместе покрывают хост. Это держит CPU способным обрабатывать пакеты, а руководство по укреплению сервера не даёт заполниться состоянию соединений. Выше канала ответ — на сетевом уровне, где тот же сброс, что это руководство делает в XDP, выполняется в аппаратуре в масштабе.
Порядок применения
- Подтвердите симптом (раздел 0): одно горячее ядро softirq, полоса далеко ниже предела.
- Поднимите кольцевые буферы NIC; убедитесь, что сбросы NIC прекратились.
- Включите RSS со столькими очередями, сколько ядер могут обслужить; проверьте распределение.
- Добавьте RPS/RFS там, где аппаратных очередей слишком мало.
- Закрепите привязку IRQ; решение об irqbalance примите по измерению.
- Поднимите бюджет softirq и включите адаптивное объединение, если squeezed сохраняется.
- Для флуда, который распределение не может рассеять, разверните программу отбрасывания XDP.
- Подключите четыре сигнала к мониторингу.
Шаги 3 и 4 решают большинство проблем частоты пакетов, распределяя нагрузку; XDP в шаге 7 — эскалация для того, что одно распределение поглотить не может.
Частые вопросы
- Как понять, что нужен этот слой, а не настройка sysctl?
- По симптому. Если одно ядро CPU закреплено на уровне около 100% во времени программных прерываний (softirq), а остальные простаивают, и суммарная полоса далеко ниже предела канала, вы упёрлись в частоту пакетов, и настраивать нужно этот слой. Если же заполняются таблицы соединений, очереди или дескрипторы, а CPU в порядке, это исчерпание состояния, и оно относится к укреплению sysctl из руководства по серверу Linux. Эти два слоя дополняют друг друга: sysctl защищает состояние соединений, этот слой — путь обработки пакетов.
- RSS, RPS и RFS — в чём разница?
- Они распределяют обработку пакетов по ядрам на разных уровнях. RSS (Receive Side Scaling) выполняется в аппаратуре NIC и хеширует потоки в несколько очередей приёма, каждая со своим прерыванием. Это самый эффективный вариант и первый выбор, когда NIC поддерживает достаточно очередей. RPS (Receive Packet Steering) — программный эквивалент, распределяющий в ядре, когда аппаратного RSS нет или очередей слишком мало. RFS (Receive Flow Steering) добавляет поверх RPS локальность потока, направляя поток на то ядро, где работает его приложение, что улучшает поведение кэша. Используйте RSS где можете, RPS где не можете, а RFS вместе с RPS на многоядерных хостах.
- Стоит ли XDP того ради DDoS, или это перебор?
- Для атак с высокой частотой пакетов это самая эффективная защита на уровне хоста, потому что она отбрасывает пакеты в драйвере до того, как они попадают в сетевой стек. До conntrack, до iptables/nftables, до какого-либо выделения памяти. Небольшая программа XDP, отбрасывающая по простому критерию (набор источников, проверка на битый пакет, порт), способна отсеивать миллионы пакетов в секунду за долю того CPU, что этот же сброс стоит в nftables. Её сложнее развернуть, и для полной пользы нужен драйвер с нативной поддержкой XDP, поэтому это не первый инструмент. Но для флуда по частоте пакетов, который слой распределения не может рассеять, именно XDP меняет порядок величины.
- Объединение прерываний помогает или вредит под атакой?
- Оно меняет задержку на эффективность, и под флудом пакетами обычно побеждает эффективность. Объединение группирует прерывания, чтобы CPU не прерывался на каждый пакет; адаптивное объединение (adaptive-rx) повышает группировку по мере роста частоты. Это снижает накладные расходы прерываний ровно тогда, когда проблема — частота пакетов. Ценой становится небольшая добавленная задержка, важная для чувствительных к задержке нагрузок в обычной работе. Поэтому честный подход — измерять оба состояния, а не наращивать объединение вслепую.
- Отключать ли irqbalance и привязывать вручную?
- Часто да, на сервере под атакой по частоте пакетов. irqbalance перемещает прерывания динамически; в общем случае это нормально, но может разрушить тщательную привязку очередей RSS к ядрам и перебрасывать поток между ядрами под нагрузкой. Для выделенного, высокопроизводительного или атакуемого хоста привязка прерывания каждой очереди приёма NIC к конкретному ядру, и удержание этих ядер в стороне от приложения, предсказуемее. На сервере общего назначения оставить irqbalance включённым обычно правильно. Это решение принимается по измерению, а не как универсальное «включить/выключить».
- Останавливают ли эти настройки объёмную (по полосе) атаку?
- Нет. Если атака заполняет канал доступа, пакеты отбрасываются выше по потоку до того, как их увидит NIC, и ни очередь, ни распределение, ни XDP не срабатывают. Этот слой защищает от частоты пакетов — от числа пакетов в секунду, насыщающего CPU, что может произойти маленькими пакетами далеко ниже предела полосы. Полоса выше канала — это задача сетевого уровня, и на хосте она не решается.
Опубликовано: август 2026 г.
Руководство обновляется по мере выхода новых моделей и условий лицензирования. Как мы сравниваем производителей