Написал легковесный демон для OpenWrt, который переключает default route по качеству канала (latency, loss, jitter). Влезает в 8 МБ flash, где mwan3 со всеми зависимостями уже не помещается.
Проблема:
Есть роутер Xiaomi Mi Router 4C (8 МБ flash, 64 МБ RAM) на OpenWrt r24550-f909059b74. Нужно автоматически переключаться с проводного интернета на Wi-Fi точку доступа с телефона при падении основного канала.
Файловая система:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/root 6912 6912 0 100% /rom
tmpfs 28584 336 28248 1% /tmp
/dev/mtdblock9 5760 5628 132 98% /overlay
overlayfs:/overlay 5760 5628 132 98% /
Свободно ~130 КБ. mwan3 со всеми зависимостями (iptables, conntrack, LuCI) сюда уже не влезает.
Существующие решения
mwan3 — стандартный инструмент для multi-WAN в OpenWrt. Умеет балансировку, policy-based routing, трекинг через ICMP/DNS/ARP. Но:
- требует установки iptables, kmod-ipt-conntrack-extra, luci-app-mwan3 и пр. — цепочка зависимостей разрастается до 1–2 МБ.
- держит persistent-демон, трекеры, нагружает conntrack — на 64 МБ RAM под нагрузкой это ощутимо.
- конфигурация сложная (интерфейсы, члены, политики) для задачи «переключить маршрут при деградации».
Другие варианты типа ifplugd не умеют оценивать качество канала — только up/down.
Мое решение: легковесная служба wanmon на скриптах
Написал свой демон на POSIX shell. Три независимых стадии:
-
Измерение
(wm-state.sh)— ICMP-пинги до заданного хоста через каждый интерфейс, сбор RTT, loss, jitter. -
Решение (wm-select.sh) — вычисляет score для каждого интерфейса:
score = (latency + jitter) + (loss² / loss_divisor) + bias
Выбирает интерфейс с минимальным score. Применяет сглаживание (smooth window) и гистерезис, чтобы избежать флаппинга.
- Применение
(wm-apply.sh)— обновляет таблицу маршрутизации: основной default route через выбранный интерфейс, резервный — через первый из оставшихся с увеличенной метрикой.
Демон (wm-daemon.sh) — служба, которая непрерывно проверяет состояние сетевых интерфейсов, запуская вышеупомянутые скрипты в цикле с заданным интервалом. При необходимости она переключает соединение на более предпочтительное.
Философия: связность — не бинарное состояние. Канал может быть «up», но непригоден для работы. wanmon трактует качество как непрерывную cost-функцию, а не флаг достижимости.
Сравнение с mwan3
| Параметр | mwan3 | wanmon |
|---|---|---|
| Занимаемое место | ≥1–2 МБ (с зависимостями) | <100 КБ |
| Использование RAM | Умеренное (демон + conntrack + трекеры) | Минимальное (fork-exec цикл) |
| Конфигурация | Сложная (политики, члены, трекеры) | Один JSON-файл |
| Основное назначение | Балансировка + failover | Только failover |
| Критерий выбора | Доступность (up/down) | Latency + loss + jitter |
| Web-интерфейс | Полноценный LuCI | Одна HTML-страница или вкладка в LuCI |
| Policy-based routing | Есть | Нет |
| Per-connection tracking | Есть | Нет |
| Модифицируемость | Сложно (C/shell) | Просто (shell) |
Честно: wanmon не замена mwan3 во всех сценариях. Это сознательный трейд-офф: отказ от гибкости в пользу минимализма и работы в ограниченном окружении.
Как работает на практике
Поднял на роутере два интерфейса:
- wan — проводной
- wwan — Wi-Fi точка доступа с телефона
В ifaces.json выставил bias для проводного интерфейса ниже (предпочтительнее). При падении качества проводного канала (потеря пакетов, рост задержки) score растёт, после пересечения порога гистерезиса маршрут переключается на wwan. При восстановлении — переключается обратно.
Веб-интерфейс по адресу http://<router_ip>/wanmon.html (или через раздел «Службы» → «WAN Monitor» в LuCI) показывает статус, текущий маршрут, scores и телеметрию, позволяет переключить вручную.
Ссылки
- Репозиторий: https://github.com/ng256/wanmonitor
Вывод
Для маломощных роутеров (8 МБ flash, 64 МБ RAM) wanmon — рабочая альтернатива mwan3, когда нужен только failover по качеству канала. Простая архитектура, минимальный вес, прозрачная логика. Если у вас более мощное железо и нужна балансировка/политики — берите mwan3. wanmon для узких мест.








