ARP flux — одна из тех сетевых проблем в Linux, которые долго выглядят как «странная плавающая сеть». Сегодня пинги проходят, завтра часть клиентов не может достучаться до одного из IP, а послезавтра трафик внезапно выходит через другой адрес. Особенно часто это проявляется на серверах с несколькими IPv4-адресами, несколькими интерфейсами, дополнительными алиасами, VRRP, контейнерными сетями или нестандартной маршрутизацией.
На Debian и Ubuntu проблема обычно связана не с «поломкой ARP», а с тем, как ядро Linux по умолчанию обрабатывает ARP-ответы и выбор исходного адреса. Если не ограничить поведение хоста, он может ответить на ARP-запрос для адреса, назначенного на одном интерфейсе, через другой интерфейс. Для соседних устройств в L2-сети это выглядит как путаница: один и тот же IP ассоциируется то с одним MAC, то с другим.
В результате получаем трудноуловимые симптомы: нестабильный доступ к сервисам, асимметричную маршрутизацию, периодические таймауты, непонятные записи в ARP-кэше соседних хостов и жалобы на «сетевые глюки», которые не подтверждаются банальным ping.
В этой статье разберём, что такое arp flux, как он проявляется в Debian/Ubuntu, какие параметры ядра реально влияют на поведение, и как правильно сочетать arp_ignore, arp_announce, rp_filter и policy routing. Покажу практичный путь диагностики и рабочую схему настройки для сервера с несколькими IP. Если вы обкатываете такую схему в отдельной среде, удобнее делать это на изолированном VDS, где можно спокойно проверять маршрутизацию и sysctl-параметры.
Что такое ARP flux простыми словами
ARP нужен для сопоставления IPv4-адреса и MAC-адреса внутри одного L2-сегмента. Когда соседняя машина хочет отправить пакет на ваш IP, она сначала спрашивает: «кто владеет этим IP?» Хост, у которого этот адрес есть, отвечает своим MAC.
Проблема в том, что Linux традиционно смотрит на IP-адрес как на ресурс всего хоста, а не строго конкретного интерфейса. То есть если адрес назначен на сервере, ядро в определённых условиях может ответить на ARP-запрос через интерфейс, на котором этот адрес формально не висит. Это и есть основа ARP flux.
Иными словами: сеть ожидает модель «IP привязан к конкретному порту», а Linux по умолчанию часто ведёт себя по модели «IP принадлежит всему серверу».
Если у вас один интерфейс и один адрес, вы этого почти никогда не заметите. Но как только появляются несколько адресов, несколько интерфейсов в одной подсети, secondary IP, bond, bridge, VRRP или ручные маршруты, поведение становится заметным и иногда разрушительным.
Типичные симптомы на Debian/Ubuntu
Самый частый сценарий: на сервере два интерфейса в одной или близкой сети, либо несколько IP на одном сервере с нестандартным роутингом. Соседние машины начинают получать ARP-ответы с неожиданного MAC-адреса. После этого часть трафика идёт не туда, возвратный путь отличается от входящего, а приложения видят обрывы соединений.
С практической стороны это может выглядеть так:
- один из дополнительных IP пингуется нестабильно;
- подключение к сервису на конкретном IP то работает, то нет;
- на соседнем хосте запись в ARP-кэше для одного IP меняется между двумя MAC;
- ответы уходят с другого исходного адреса;
tcpdumpпоказывает ARP-ответы не с того интерфейса;- после включения фильтрации reverse path часть трафика начинает отбрасываться.
Особенно неприятно, что проблема может быть не постоянной. ARP-кэш у соседей живёт ограниченное время, маршруты могут выбираться по метрикам, а некоторые запросы проходят успешно. Поэтому «сеть иногда ломается» — классическое описание ARP flux.
В таких случаях сначала полезно зафиксировать текущее поведение сети, а уже потом менять sysctl и таблицы маршрутизации. Это сильно снижает риск сломать рабочий, но просто неочевидный сценарий.
Когда проблема возникает чаще всего
В реальной эксплуатации я бы в первую очередь проверял ARP flux в следующих сценариях:
- несколько интерфейсов в одной IPv4-подсети;
- несколько IP на одном интерфейсе и сервисы, которые должны отвечать строго с конкретного адреса;
- VRRP, keepalived, floating IP;
- сетевые namespace, bridge, виртуализация, контейнеры;
- асимметричный трафик из-за нескольких шлюзов или policy routing;
- фильтрация пакетов с включённым строгим
rp_filter.
Важно понимать: несколько IP на одном Linux-хосте — это нормально. Но если вы хотите предсказуемое поведение, нужно явно описать системе, как отвечать на ARP и как выбирать маршрут обратно.

С чего начать диагностику
До изменения sysctl-параметров сначала соберите факты. Иначе легко «починить» не ту проблему или сломать рабочий сценарий с асимметричной маршрутизацией.
Проверяем адреса и интерфейсы
ip addr show
ip -br addr
Посмотрите, где именно назначены адреса, какие интерфейсы активны, нет ли адресов в одной подсети на разных NIC и нет ли неожиданных secondary IP.
Смотрим маршруты
ip route show
ip route show table main
ip rule show
Если на хосте уже используется policy routing, важно понять, какие правила выбираются первыми и как ядро определяет выходной интерфейс для ответа.
Проверяем, как ядро выберет маршрут для конкретного источника
ip route get 192.0.2.10
ip route get 192.0.2.10 from 198.51.100.20
Команда ip route get очень полезна при сетевой диагностике. Она показывает, какой маршрут реально будет использован, какой интерфейс выбран и какой исходный адрес будет подставлен.
Смотрим ARP-трафик
tcpdump -ni any arp
tcpdump -ni eth0 arp
tcpdump -ni eth1 arp
Если видите, что запрос пришёл на один интерфейс, а ответ ушёл с другого, или ответ уходит с MAC другого интерфейса, вы почти наверняка упёрлись в ARP flux.
Проверяем текущие sysctl-параметры
sysctl net.ipv4.conf.all.arp_ignore
sysctl net.ipv4.conf.all.arp_announce
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.default.arp_ignore
sysctl net.ipv4.conf.default.arp_announce
sysctl net.ipv4.conf.default.rp_filter
Дополнительно имеет смысл посмотреть значения по каждому интерфейсу, потому что они могут отличаться:
sysctl net.ipv4.conf.eth0.arp_ignore
sysctl net.ipv4.conf.eth0.arp_announce
sysctl net.ipv4.conf.eth0.rp_filter
sysctl net.ipv4.conf.eth1.arp_ignore
sysctl net.ipv4.conf.eth1.arp_announce
sysctl net.ipv4.conf.eth1.rp_filter
Что делают arp_ignore и arp_announce
Это два ключевых параметра против ARP flux.
Параметр arp_ignore
arp_ignore определяет, насколько охотно система отвечает на ARP-запросы для локальных адресов.
На практике чаще всего используют значение 1. Оно говорит: отвечай на ARP-запрос только если целевой IP назначен на интерфейс, через который этот запрос пришёл. Это уже резко снижает вероятность ARP flux.
Более строгие режимы существуют, но без необходимости их лучше не включать: можно случайно нарушить доступность в специфических сетях.
Параметр arp_announce
arp_announce контролирует, какой локальный адрес ядро использует в ARP-запросах и gratuitous ARP. Для multi-IP-хостов безопаснее обычно ставить 2, чтобы система старалась объявлять наиболее подходящий адрес для данного интерфейса и подсети.
Если кратко, удачная базовая комбинация для большинства случаев — arp_ignore=1 и arp_announce=2.
Эти параметры не заменяют нормальную маршрутизацию, а лишь делают ARP-поведение хоста более предсказуемым.
Практичная базовая настройка sysctl
Для Debian/Ubuntu удобно вынести настройки в отдельный файл, например /etc/sysctl.d/60-arp-flux.conf.
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.default.arp_announce = 2
Применить изменения можно так:
sysctl --system
Если интерфейсы уже существуют, проверьте, что значения действительно применились и на уровне конкретных интерфейсов. Иногда на живой системе полезно задать их явно:
sysctl -w net.ipv4.conf.eth0.arp_ignore=1
sysctl -w net.ipv4.conf.eth0.arp_announce=2
sysctl -w net.ipv4.conf.eth1.arp_ignore=1
sysctl -w net.ipv4.conf.eth1.arp_announce=2
После этого повторите tcpdump и проверьте таблицу ARP на соседних хостах.
Где здесь роль rp_filter
rp_filter — это reverse path filtering. Он проверяет, соответствует ли обратный маршрут для входящего пакета ожидаемому интерфейсу. Это полезный механизм защиты от спуфинга, но он же часто ломает легитимный асимметричный трафик.
Именно поэтому при нескольких IP, нескольких интерфейсах и policy routing нужно быть очень осторожным. Если включить строгий режим, хост начнёт отбрасывать пакеты, для которых обратный путь, по мнению ядра, должен идти не через тот интерфейс, по которому пакет пришёл.
Чаще всего встречаются такие варианты:
0— отключено;1— строгая проверка;2— более мягкая проверка.
Для серверов с несколькими маршрутами и осознанной асимметрией обычно разумнее использовать 2 или точечно настраивать параметры по интерфейсам. Если бездумно поставить 1 глобально, можно получить загадочные потери входящего трафика.
Пример осторожной настройки:
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
Но это не универсальная догма. Если у вас простой сервер с одним ожидаемым путём, строгий режим может быть уместен. Если же у вас multi-homed Linux, сначала проектируйте маршрутизацию, потом включайте фильтрацию. Если тема близка, ещё рекомендую материал про управление исходящими адресами через SNAT в nftables: он хорошо дополняет policy routing в multi-IP-сценариях.
Почему одного sysctl часто недостаточно
Очень распространённая ошибка: администратор выставляет arp_ignore и arp_announce, ARP-таблицы действительно стабилизируются, но сервис всё равно отвечает не тем IP или пакеты теряются. Причина в том, что ARP и IP-маршрутизация — разные уровни.
ARP определяет, как вас находят в локальном сегменте. А вот обратный путь пакетов определяет таблица маршрутизации. Если у сервера несколько IP и для каждого адреса ожидается свой выходной путь, нужно настраивать policy routing.
Когда нужен policy routing
Policy routing нужен, когда маршрут должен зависеть не только от адреса назначения, но и от источника, интерфейса или других признаков. Классический кейс: на сервере два IP из разных подсетей или два uplink, и ответы должны уходить через свой шлюз для каждого адреса.
Без этого возможна ситуация, когда пакет пришёл на IP одного интерфейса, а ответ уходит через основной маршрут другого интерфейса. С точки зрения клиента это выглядит как поломанная сеть, а при включённом rp_filter — ещё и как сброс части пакетов самим ядром.
Пример логики policy routing
Допустим, у нас есть:
eth0с адресом192.0.2.10/24и шлюзом192.0.2.1;eth1с адресом198.51.100.10/24и шлюзом198.51.100.1.
Тогда для корректного поведения нужно сделать отдельные таблицы маршрутизации и правила по исходному адресу.
echo '100 rt_eth0' >> /etc/iproute2/rt_tables
echo '101 rt_eth1' >> /etc/iproute2/rt_tables
ip route add 192.0.2.0/24 dev eth0 scope link table rt_eth0
ip route add default via 192.0.2.1 dev eth0 table rt_eth0
ip route add 198.51.100.0/24 dev eth1 scope link table rt_eth1
ip route add default via 198.51.100.1 dev eth1 table rt_eth1
ip rule add from 192.0.2.10/32 table rt_eth0
ip rule add from 198.51.100.10/32 table rt_eth1
После этого ответы для каждого адреса будут выбираться из своей таблицы. Именно такая схема часто завершает лечение ARP flux и связанных с ним побочных эффектов.
Перед внедрением в продакшене проверьте правила на тестовом узле или в отдельной среде. Для таких экспериментов удобнее использовать отдельный VDS, где не страшно временно менять сетевую логику и отлаживать возвратный маршрут.
Как это увязать с netplan и systemd-networkd
На современных Ubuntu часто используется netplan, а на Debian и Ubuntu серверных установках нередко встречается systemd-networkd или ifupdown. Главное правило тут простое: постоянная конфигурация должна описывать не только адреса, но и правила и таблицы маршрутизации, если они нужны.
Если вы временно добавили маршруты командами ip route и ip rule, а потом перезагрузили сервер, проблема может вернуться сама. Поэтому после отладки обязательно перенесите конфигурацию в штатный механизм вашей системы.
В рамках статьи не буду привязываться к одному сетевому стеку, потому что синтаксис зависит от вашей версии Debian/Ubuntu и текущего менеджера сети. Но принцип неизменен: отдельные таблицы, маршруты в этих таблицах и правила from для конкретных IP.

Пошаговый план исправления без лишнего риска
- Соберите текущее состояние:
ip addr,ip route,ip rule, значения sysctl. - Запустите
tcpdumpна проблемных интерфейсах и подтвердите ARP flux фактами. - Включите базовые настройки
arp_ignore=1иarp_announce=2. - Проверьте, исчезла ли путаница в ARP-ответах.
- Если трафик всё ещё идёт асимметрично, спроектируйте
policy routing. - Только после этого настраивайте
rp_filterв подходящий режим. - Закрепите конфигурацию в постоянных файлах системы.
- После изменений очистите ARP-кэш на соседях или дождитесь его обновления.
Последний пункт важен. Иногда вы уже всё исправили, но клиентская машина продолжает использовать старую ARP-запись и создаёт иллюзию, что ничего не поменялось.
Частые ошибки при борьбе с ARP flux
Первая ошибка — менять только один параметр наугад. Например, включить arp_ignore и не проверить маршрутизацию. Вторая — включить строгий rp_filter на multi-homed сервере и потом долго искать, почему часть соединений теряется только в одном направлении.
Третья ошибка — не смотреть трафик. Без tcpdump и без проверки ip route get очень легко принять последствия policy routing за проблему ARP и наоборот.
Четвёртая ошибка — забыть о порядке применения настроек. Значения all, default и параметры конкретного интерфейса взаимодействуют не всегда так, как ожидает администратор. После применения проверяйте итоговое состояние именно на нужных интерфейсах.
Минимальный рабочий шаблон для большинства случаев
Если нужен короткий и практичный стартовый вариант для Debian/Ubuntu сервера с несколькими IP, я бы рекомендовал такой подход:
- поставить
net.ipv4.conf.all.arp_ignore = 1; - поставить
net.ipv4.conf.all.arp_announce = 2; - дублировать эти значения в
default; - проверить, не мешает ли
rp_filter; - при разных uplink или ожидаемом раздельном обратном пути — добавить
policy routing.
Это не серебряная пуля, но для большинства сценариев с несколькими IP в Linux даёт предсказуемое поведение и снимает самую неприятную часть проблемы.
Как проверить, что всё действительно исправилось
После настройки убедитесь не только в отсутствии жалоб, но и в сетевой консистентности:
- ARP-запрос к IP на
eth0получает ответ только отeth0; - ARP-запрос к IP на
eth1получает ответ только отeth1; ip route getдля каждого источника показывает ожидаемый интерфейс;- при реальном подключении сервис отвечает с правильного IP;
- на соседних устройствах ARP-кэш больше не скачет между MAC-адресами.
Если хотя бы один из этих пунктов не выполняется, проблема, скорее всего, не закрыта полностью. Чаще всего остаётся недонастроенный маршрут, правило ip rule или конфликтующая конфигурация менеджера сети.
Итог
ARP flux в Debian и Ubuntu — это не экзотика и не баг сломанного сервера, а следствие стандартного поведения Linux в среде, где у хоста несколько IP и сеть ожидает более жёсткой привязки адреса к интерфейсу. Поэтому лечится проблема тоже системно: сначала корректируем ARP-поведение через arp_ignore и arp_announce, затем проверяем влияние rp_filter, а при необходимости строим нормальный policy routing.
Если подходить к задаче именно в таком порядке, можно довольно быстро превратить магические сетевые отказы в понятную и воспроизводимую схему. А это уже половина успеха в любой сетевой диагностике. Если вы регулярно поднимаете такие конфигурации для проектов и сервисов, имеет смысл сразу выбирать инфраструктуру, где удобно управлять сетями, адресами и маршрутами — от виртуального хостинга для простых задач до отдельных VDS для сложных multi-IP-сценариев.


