Маршрутизатор Banana Pi R64 — Debian, Wireguard, РКН
Banana Pi 64 — это одноплатный компьютер по типу Raspberry Pi, но с несколькими портами Ethernet, что дает возможность сделать из него маршрутизатор на базе дистрибутива Linuх общего назначения.
Да, уже есть Openwrt, но у него свои заморочки свой GUI и CLI; есть Mikrotik, но у него опять же свой GUI/CLI, да и Wireguard из коробки не работает… В общем хочется маршрутизатор с гибкими настройками, при этом оставшись в рамках стандартного линукса, с которым работаешь каждый день.
В статье под названиями BPI, R64, одноплатник я буду подразумевать одно и тоже — собственно сам одноплатник Banana Pi R64.
Выбор образа. Загрузка по eMMC
Самый первый навык, который нужно приобрести при работе с SBC вообще, и с R64 в частности, это научиться грузить в него операционку и иметь возможность взаимодействовать с ним, ведь у R64 нет порта для монитора (HDMI, например). Когда все отвалилось — перестал работать Wifi, сеть Ethernet, Bluetooth, USB и прочее есть UART, через интерфейс которого всегда можно посмотреть, что пошло не так, а также запустить пару команд из консоли, по необходимости.
Алгоритм подключения к R64 по USB-UART:
бежим в магазин радиодеталей за кабелем USB-UART (PL2303, Serial-to-USB)
подключаем один USB-конец к компьютеру, а другой, UART,- к R64, тремя проводами из четырех, как на картинке ниже
в консоли компьютера запускаем sudo minicom
После этого в большинстве случаев появится консоль одноплатника = успех.
Подробнее можно посмотреть здесь.
Далее, проще всего загрузить операционную систему с SD-карты: скачиваем по ссылке образ и заливаем его:
вставляем карту в SD-слот R64, включаем, наблюдаем по подключенной консоли загрузку сначала uboot, затем стандартную загрузку линукса.
Альтернативный вариант загрузки — с помощью уже вшитой в R64 карты размером 8Gb, называемой eMMC. По инструкции в вики переписываем образ на устройство
/dev/mmcblk0 в BPI, перегружаемся, вытаскиваем SD-карту, включаем BPI снова… и не работает. Как туда-сюда Boot select ни дергай.
Дело в том, что как минимум для BPI необходимо поставить специальный флаг, чтобы иметь возможность грузиться с внутренней флешки:
Производитель R64 (Китай) выложил этот бинарь здесь. Что он делает неизвестно (исходников нет), но без него тоже не заработает.
В общем-то после этого образы начинают грузиться и с eMMC. Если же захотеть разобраться и создавать образы с нуля, то для обоих случаев (SD/eMMC) нужно записывать еще несколько файлов (preloader для SD-карты, ATF, u-boot), только чтоб добраться до загрузки ядра. Тема эта до сих пор развивается, но для нас главное, что работает и ладно.
Сейчас я загрузку по eMMC, честно говоря, не использую, SD карты достаточно, но я довольно много времени потратил на то, чтоб оно заработало, поэтому пусть будет в статье.
Выбор операционки. Armbian
Первая прикладная задача — запустить VPN, естественно Wireguard. Сразу же обнаружилось, что со стороны ядра он не собран, и заголовков нет. Пересобрал ядро и, по привычке с x86, собрал модуль ядра с помощью DKMS. Однако скорость сборки на arm64 даже небольших утилит меня неприятно удивила. А дальше еще один модуль ядра потребовался, и т.д. В общем, выходит, что все, связанное с ядром, лучше собирать на теплом-ламповом ноутбуке x86, затем простым копированием переносить на R64, перегружаться и тестить.
Другое дело — юзейспейсная часть. В моем случае выбора Debian, все для архитектуры arm64 уже есть на packages.debian.org и ничего пересобирать не приходится.
Чтобы не плодить очередной велосипед, я портировалArmbian на BPI R64.
Вернее так: userspace-ная часть — Armbian, а ядро берется из репозитория Frank-а. Самый свежий образ можно скачать здесь.
Вся активность по разработке софтовой части R64 ведется на форуме. Вообще говоря, сам производитель стремится популяризировать роутер под Openwrt, но благодаря активности разработчика Frank-а из Германии все фичи быстро оказываются в ядре для Debian-а. Удивительно, но Frank активен в каждой ветке форума.
Организация рабочего пространства: провода
Отдельно хочу рассказать, как во время разработки/тестирования разместить SBC (не только BPI) на столе так, чтоб не вести Ethernet-кабель к нему от источника интернета через всю комнату/офис. Дело в том, что с одной стороны нужно обеспечить железке интернет, а с другой стороны в этой самой железке может все ломаться, и в первую очередь Wifi.
Сначала я решил приобрести дешевый USB-Wifi "свисток", воткнуть его в единственный порт на BPI и забыть о проводах. Для этого приобрел недорогой TP-LINK TL-WN725N USB 2.0, но очень скоро стало понятно, что не взлетит: для работы свистка нужен драйвер ядра, которого там, естественно, не было (позже я собрал нужный драйвер RTL8XXXU, но все равно это непрактично). И Ethernet-кабель портил вид комнаты некоторое время.
В итоге от кабеля мне удалось избавиться с помощь Tenda MW3 (Wifi mesh-система): просто расположил один кубик под столом и метровым Ethernet-кабелем подключил BPI к LAN-порту последнего. Успех.
Wireguard, РКН, Bird
Одна из хотелок, для чего я использую Banana PI — иметь свободный доступ на сайты, заблокированные РКН, в частности, чтоб работал Telegram и звонки в Slack-е. На эту тему уже были предложены статьи на Хабре: раз, два, три.
Развертывание именно такого решения я реализовал с помощью Ansible: ссылка.
Предполагается, что VPS работает под Ubuntu 18.04. Работоспособность проверил на двух хостерах в Европе: Amazon и Digital Ocean.
Итак, мы установили вышеуказанный Armbian на R64, он доступен по ssh под именем hm-bananapi-1 и имеет доступ в интернет. Развертываем последовательно ansible, скрипты автоматизации и запускаем установку собственно на R64:
# зависимости для Debian-based дистрибутивов
$ sudo apt install --no-install-recommends python3-pip python3-setuptools python3-wheel git
$ which pip3
/usr/bin/pip3
# ansible с pybook, скриптование на Python
$ pip3 install https://github.com/muravjov/ansible/archive/ansible-2.10.0.dev0-pybook2019.tar.gz
$ export PATH=~/.local/bin:$PATH
$ which ansible-playbook
/home/sa/.local/bin/ansible-playbook
$ git clone https://github.com/muravjov/ansible-bpi-r64.git
$ cd ansible-bpi-r64
$ git submodule update --init
# убеждаемся в доступности hm-bananapi-1
$ ssh hm-bananapi-1 which python3
/usr/bin/python3
# собственно установка
$ ansible-playbook ./router.py -l hm-bananapi-1
Далее нужно аналогичным образом задеплоить на VPS наш VPN:
ansible-playbook ./router.py -l current-vpn
Здесь аргумент всегда current-vpn, а собственно имя VPS настраивается в переменной (в данном случае это paris-vpn-aws-t2-micro-1):
with mapping:
append("name", "start bird")
with mapping("systemd"):
append("name", "bird")
append("state", "started")
append("enabled", "yes")
Запись команд Ansible кодом на Python позволяет повторно использовать код, да и вообще открыты все возможности языка общего назначения. Например, установка bird на R64 и VPS:
Итого: телеграмчик работает, linkedin и pornhub тоже, в общем user experience — ок. Но все может ломаться, и китайские железки тоже.
Обновления ядра тоже бывают интересными: например, я захотел обновить ядро 5.4 => 5.6, нуачо, там же Wireguard изкоробки, не надо патчить… Сказано-сделано: кропотливо переносил патчи с 5.4 на 5.6, ядро завелось, туннель до VPS пингуется, но bird не может соединиться с ошибкой "BGP Error"… "В ужасе откатился назад" (с) на 5.4; переезд на 5.6 отложил в TODO.
Поэтому в дополнение к инсталяции роутера и VPS добавил мониторинг (на x86 Ubuntu 18.04), который ставится на отдельный хост со следующими компонентами:
prometheus, alertmanager, blackbox_exporter — все в докере
алерты направляются в телеграм-канал с помощью бота metalmatze/alertmanager-bot — тоже в докере
tor для бота, чтобы бот мог алертить ситуации, когда интернет есть, но телеграм все равно не работает, и сам бот не может соединиться
В дополнении ко всему запланировал подключиться к двум провайдерам, чтобы интернет продолжил работать, даже если у одного провайдера проблемы с сетью, или забыли заплатить за интернет и т.д., и прочий человеческий фактор.
Наиболее продвинутый user experience на тему multi-wan описан здесь для системы Mwan3 под Openwrt. У данного решения богатый функционал, но настройка и эксплуатация вообще для multi-wan довольно хлопотна. Один только пример: если приходить на некоторые сайты сразу с двух IP-адресов, то им это может не понравится, они перестанут работать => "интернет не работает".
Учитывая данный опыт решил, что multihoming пока не в приоритете, только failover. Хотя, кажется, в последних версиях linux все должно работать одной командой вида:
ip route add default
nexthop via 192.168.1.1 weight 10
nexthop via 192.168.2.1 weight 5
Итак, чтобы не было единой точки отказа, берем 2 BPI, каждый подключаем к одному провайдеру, соединяем их между собой и связь друг c другом сделаем динамической маршрутизацией через bird/OSPF.
Далее, на каждом анонсируем одинаковый IP-адрес в случае, если сервис доступен (интернет, DNS). То есть проставлять маршрут по умолчанию будем не сами, а посредством bird. Решение подсмотрел здесь .
Данный функционал пока не реализовал, коварный коронавирус и тут подгадил (не все приехало c алиэкспресс; еще один интернет-магазин, Layta, обещал доставить за неделю, а уже больше месяца прошло; второй провайдер не успел кабель протянуть до карантина, успел только дырку в стене просверлить для кабеля).
Как заказать R64
Сама плата в официальном магазине SinoVoip.
Также лучше сразу заказать:
Есть нюанс — цена доставки с какого-то времени стала неадекватно высокой в официальном магазине. Менеджер Judy Huang убеждала меня, что ошибки нет, и можно выбрать ePacket за $5, но я видел, что для России есть только EMS за >33$. Неприятно, но не критично. Причем, если выбрать любую другую страну для доставки (перебрал все континенты), доставка будет за ~5$. Русофобы?.. Но потом я нашел, что для Франции цена доставки тоже ~30$, и успокоился.
В итоге Judy предложила сделать заказ, но не оплачивать (hint: положить на карту меньше, чтоб автоматом оплата не прошла); написать ей, и она снизит цену доставки до нормальной. Успех.
Issues
Не все пока работает идеально.
Производительность
Медленно выполняются команды Ansible=Python, даже холостые, по 20-30 секунд; на порядок дольше, чем на ноуте x86. Причем сначала выполняются достачно быстро, ~3 секунды, затем резко замедляются. Возможно это происходит из-за нагревающегося CPU (throttling). Код на Go тоже долго работает:
# запрос метрик для прометея из node_exporter на Go
$ time curl -s http://172.30.1.1:9100/metrics > /dev/null
real 0m6,118s
user 0m0,005s
sys 0m0,009s
# однако температура 51 градус, не так и много
sa@bananapir64:~$ cat /sys/devices/virtual/thermal/thermal_zone0/temp
51700
Wifi
Wifi работает, но на Armbian где-то через сутки перестает, пишет: