Конфігурація Extroot
Вступ
Цей посібник описує, як налаштувати OpenWrt для використання зовнішнього носія (USB, SATA, SD-картки або іншого) для розширення кореневої файлової системи, щоб мати змогу встановлювати всі необхідні пакети.
У більшості підтримуваних пристроїв OpenWrt розділяє внутрішню пам’ять на розділи rootfs та rootfs_data або ubifs, які об'єднуються в єдину придатну для запису файлову систему типу overlay.
| Розділ | Точка монтування | Стиснення | Запис |
|---|---|---|---|
rootfs | /rom | Так | Ні |
rootfs_dataubifs | /overlay/rom/overlay | Ні | Так |
overlay | / | Незмінені файли | Так |
Таким чином, OpenWrt може працювати навіть на пристроях із дуже обмеженим обсягом внутрішньої пам’яті (від 4 МіБ), залишаючи можливість зберігати налаштування та встановлювати деякі пакети.
Extroot працює шляхом монтування нової розділу overlay з зовнішнього носія поверх внутрішнього під час завантаження. Це дозволяє легко повернутись до внутрішньої overlay у разі відключення зовнішнього накопичувача — пристрій завантажиться з власної overlay та працюватиме так само, як до налаштування extroot.
Відомо, що OpenWrt ігнорує конфігурацію fstab на пристроях, у яких відсутній розділ overlay у ``/proc/mtd``. Обхідним шляхом є використання ``/`` як точки монтування.
Інструкції
Наступні інструкції передбачають, що ви вже маєте доступ до shell на вашому пристрої OpenWrt. Більшість команд можна виконати через веб-інтерфейс, але це не рекомендується.
Доступ до shell зазвичай отримують через SSH або послідовний порт.
1. Підготовка
Пристрої з флеш-пам’яттю 8 МіБ або більше зазвичай мають достатньо місця для встановлення необхідних пакетів. В іншому разі створіть кастомний образ.
Видаліть усі пакети, встановлені для вторинного функціоналу — вони просто займають місце. Якщо ви не пам’ятаєте, що саме встановлювали — спробуйте видалити 'ntfs', це може звільнити простір.
Залиште лише ті пакети, які потрібні для доступу до Інтернету та extroot.
У деяких випадках достатньо буде використати офіційний OEM-образ (наприклад, OpenWRT GL.inet для GL.inet Mango).
Extroot може бути будь-яким пристроєм, який може монтувати утиліта ``block``. Підтримувані файлові системи: ext2/3/4, f2fs, btrfs, ntfs або ubifs (зверніть увагу, що FAT16/32 не підтримуються).
Найчастіше це USB-накопичувач, але також це може бути SD-картка, SATA-диск, мережевий пристрій тощо.
Якщо ви використовуєте USB-пристрій, налаштуйте його згідно з інструкцією зі встановлення за допомогою USB.
Нижче передбачено, що extroot створюється на USB-накопичувачі з файловою системою EXT4.
Установка необхідних пакетів вимагає значного обсягу вільного місця. Якщо система переповниться — доведеться прошивати все заново.
Встановіть необхідні пакети:
opkg update
opkg install block-mount kmod-fs-ext4 e2fsprogs parted kmod-usb-storage
Якщо ви використовуєте SSD в USB-кейсі, можливо, також потрібно встановити `kmod-usb-storage-uas`.
Перевірте назву USB-диска:
ls -l /sys/block
2. Розмітка та форматування
Розмітьте диск та створіть файлову систему:
DISK="/dev/sda" parted -s ${DISK} -- mklabel gpt mkpart extroot 2048s -2048s DEVICE="${DISK}1" mkfs.ext4 -L extroot ${DEVICE}
Увага: ці команди зітруть усі дані на диску.
3. Налаштування extroot
Налаштуйте монтування extroot:
eval $(block info ${DEVICE} | grep -o -e 'UUID="\S*"') eval $(block info | grep -o -e 'MOUNT="\S*/overlay"') uci -q delete fstab.extroot uci set fstab.extroot="mount" uci set fstab.extroot.uuid="${UUID}" uci set fstab.extroot.target="${MOUNT}" uci commit fstab
4. Налаштування rootfs_data / ubifs
Додайте запис для монтування оригінальної внутрішньої overlay:
ORIG="$(block info | sed -n -e '/MOUNT="\S*\/overlay"/s/:\s.*$//p')" uci -q delete fstab.rwm uci set fstab.rwm="mount" uci set fstab.rwm.device="${ORIG}" uci set fstab.rwm.target="/rwm" uci commit fstab
Це дозволить вам мати доступ до внутрішньої overlay (rootfs_data / ubifs) за шляхом `/rwm`.
5. Передача даних
Скопіюйте поточну overlay на extroot:
mount ${DEVICE} /mnt tar -C ${MOUNT} -cvf - . | tar -C /mnt -xf -
6. Застосування змін
Перезавантажте пристрій:
reboot
Тестування
Інструкції через веб-інтерфейс
- LuCI → System → Mount Points має показати, що USB-розділ змонтовано як
overlay. - LuCI → System → Software має показати вільний простір у розділі overlay.
Інструкції через командний рядок
Розділ USB повинен бути змонтований у /overlay. Вільне місце на / повинно відповідати /overlay.
# grep -e /overlay /etc/mtab /dev/sda1 /overlay ext4 rw,relatime,data=ordered overlayfs:/overlay / overlay rw,noatime,lowerdir=/,upperdir=/overlay/upper,workdir=/overlay/work # df /overlay / Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda1 7759872 477328 7221104 6% /overlay overlayfs:/overlay 7759872 477328 7221104 6% /
Вирішення проблем
- Проаналізуйте етап
preinitу журналі завантаження:
block info; uci show fstab; logread | sed -n -e "/- preinit -/,/- init -/p"
- Якщо після оновлення ви бачите повідомлення «block: extroot: UUID mismatch», видаліть файли
.extroot-uuidз диску:
mount /dev/sda1 /mnt rm -f /mnt/.extroot-uuid /mnt/etc/.extroot-uuid umount /mnt
- Не використовуйте файлову систему vfat (FAT/FAT32) — вона не підтримується. Якщо ваш USB-накопичувач відформатований у FAT, переформатуйте його в ext4 (встановіть пакет `e2fsprogs`, а потім запустіть `mkfs.ext4 /dev/sda1`).
- Якщо extroot не монтується під час завантаження, але його можна змонтувати вручну, спробуйте збільшити затримку параметра ``delay_root``. Наприклад, до 15 секунд:
uci set fstab.@global[0].delay_root="15" uci commit fstab
- ⚠️ Можливо застаріло: додайте опцію
force_spaceу ``/etc/opkg.conf``, щоб дозволити встановлення пакетів, які більші за вільне місце у ``/rom``:
echo option force_space >> /etc/opkg.conf
- Ще один варіант — змінити файл ``/etc/rc.local``, як описано у тікеті #14946. Це допомогло, наприклад, на Chaos Calmer r44266 (Comtrend AR-5387un):
export PREINIT=1 mount_root
- Якщо ви використовуєте не USB-пристрій для extroot, а наприклад MMC-картку, переконайтеся, що необхідні модулі ядра додані у файл ``/etc/modules-boot.d``. Наприклад, для sdhci на пристроях mt7688/mt7628 додайте до ``/etc/modules-boot.d/mmc`` такі рядки:
mmc_core mmc_block sdhci mtk_sd
Додатково
Збереження списків opkg
Зберігайте списки `opkg` у директорії /usr/lib/opkg/lists на extroot-носії, замість оперативної памʼяті.
Це дозволить зберегти списки після перезавантаження і зменшить використання RAM.
Інструкції через веб-інтерфейс
- Перейдіть до LuCI → System → Software → Configuration і змініть значення з
/var/opkg-listsна/usr/lib/opkg/lists. - Потім перейдіть до LuCI → System → Software → Actions → Update lists, щоб вперше згенерувати список пакетів на extroot.
Інструкції через командний рядок
sed -i -e "/^lists_dir\s/s:/var/opkg-lists$:/usr/lib/opkg/lists:" /etc/opkg.conf opkg update
Swap (підкачка)
Якщо ваш пристрій має мало оперативної памʼяті (наприклад 32MB) і не вдається зчитати списки, увімкніть підкачку:
# Створення swap-файлу DIR="$(uci -q get fstab.extroot.target)" dd if=/dev/zero of=${DIR}/swap bs=1M count=100 mkswap ${DIR}/swap # Увімкнення swap-файлу uci -q delete fstab.swap uci set fstab.swap="swap" uci set fstab.swap.device="${DIR}/swap" uci commit fstab service fstab boot # Перевірка статусу cat /proc/swaps
USB-модем (донгл)
Рекомендується включити утиліту usb-modeswitch у прошивку.
Однак існує важливе застереження: якщо /overlay монтується з картки пам’яті, що вставлена в кардрідер USB-донгла — то конфігурація pivot overlay, яка інакше працює, зламається на пізніших етапах завантаження системи.
Це відбувається тому, що usb-modeswitch (вимикаючи CDROM і вмикаючи модем) тимчасово впливає на кардрідер, порушуючи файлову систему.
Щоб уникнути цієї проблеми, використовуйте донгл, який можна попередньо сконфігурувати так, щоб модем або мережевий адаптер (та кардрідер) активувалися автоматично при подачі живлення — без використання usb-modeswitch на маршрутизаторі.
Попереднє налаштування донгла
1. Вставте донгл у настільний ПК. 2. Відкрийте термінал і надішліть AT-команди.
Перевірте початкову конфігурацію донгла:
at^setport? ^SETPORT:A1,A2;1,3,2,A1,A2 OK
Пояснення кодів доступних функцій:
at^setport=? ^SETPORT:A1: CDROM ^SETPORT:A2: SD ^SETPORT:A: BLUETOOTH ^SETPORT:B: FINGER PRINT ^SETPORT:D: MMS ^SETPORT:E: PC VOICE ^SETPORT:1: MODEM ^SETPORT:2: PCUI ^SETPORT:3: DIAG ^SETPORT:4: PCSC ^SETPORT:5: GPS ^SETPORT:6: GPS CONTROL ^SETPORT:16: NCM OK
У прикладі вище:
- Перша конфігурація (до символу
;) містить CDROM (A1) і кардрідер (A2). - Друга (після
;) — модем (1), діагностику (3), інтерфейс керування (2) та знову CDROM (A1) і кардрідер (A2).
Саме між цими двома конфігураціями usb-modeswitch перемикає пристрій.
Мета налаштування
Вимкнути CDROM (A1), увімкнути модем (1) або мережевий адаптер (16), та залишити активним кардрідер (A2).
ВАЖЛИВО: Ніколи не вимикайте PCUI (2) — ви втратите доступ до модему!
Застосування команди ''disable all''
Деякі модеми підтримують спеціальну команду 'disable all' (код FF), яка очищає наявні конфігурації.
Нижче наведено приклад для повного вимкнення та задання бажаних інтерфейсів:
at^setport="ff;1,2,3,a2" OK at^reset OK at^setport? ^SETPORT:;1,2,3,A2 OK
У результаті:
- CDROM вимкнено;
- активні: модем (1), PCUI (2), діагностика (3), кардрідер (A2);
- лише одна конфігурація — немає нічого ліворуч від символу
;.
Підтримка попереднього налаштування
Модем Huawei E3131s-2 з прошивкою v21.158.47.00.1094 підтримує попереднє конфігурування.
LUKS (Шифрування extroot)
Ви можете захотіти розмістити файлову систему extroot у зашифрованому контейнері LUKS. Починаючи з OpenWrt 22.03.2, це не підтримується належним чином. OpenWrt не має офіційного способу для розшифрування LUKS-розділів до того, як відбудеться перевірка extroot під час стандартного процесу завантаження. Отже, під час цієї перевірки зашифрований extroot буде невидимий, і процес завантаження продовжиться, як ніби extroot не налаштований.
Нижче описано два методи, які дозволяють запустити систему на зашифрованому extroot. Перший метод є кращим, оскільки має менше побічних ефектів і є більш елегантним рішенням.
Перш ніж продовжити, необхідно створити LUKS-контейнер, в якому буде розміщено файлову систему extroot.
Скористайтеся документацією шифрування диска, щоб налаштувати LUKS-контейнер на вашому пристрої.
Вам потрібно мати достатньо вільного місця у розділі rootfs_data для встановлення пакету cryptsetup та його залежностей.
Коли LUKS-контейнер буде готовий, дотримуйтесь інструкцій зі створення файлової системи extroot на розблокованому пристрої, включаючи копіювання файлів з /overlay до новоствореного extroot.
PREINIT
У фазі PREINIT процесу завантаження виконується команда mount_root, яка спочатку перевіряє наявність конфігурації extroot на ROM-пристрої, а потім на пристрої ''rootfs_data'' (див. Схема флеш-пам'яті OpenWrt для деталей).
У стандартній прошивці OpenWrt конфігурація extroot у ROM відсутня.
Для перевірки файлової системи rootfs_data mount_root монтує її у тимчасовий каталог (/tmp/overlay), потім перевіряє файл /tmp/overlay/etc/config/fstab — той самий, що був налаштований раніше, — на наявність extroot.
Якщо конфігурація знайдена, послідовно шукаються виконувані файли /tmp/overlay/upper/sbin/block, /tmp/overlay/sbin/block та /sbin/block. Знайдений файл виконується з аргументом extroot — це відбувається тут.
Тому для роботи extroot потрібно встановити пакет block-mount.
Оскільки mount_root під час PREINIT запускається з ROM, але намагається виконати block з overlay-файлової системи, цим можна скористатися, щоб вставити власні команди у фазу PREINIT до перевірки extroot.
Це реалізується створенням скрипта, який замінює оригінальний бінарник block. Цей скрипт:
- розшифровує LUKS-пристрій;
- робить доступною файлову систему extroot;
- викликає справжній
block.
Скрипт використовує decrypt.sh з посібника зі шифрування дисків.
Спершу виконайте install-decrypt.sh.
Щоб встановити скрипт:
- перемістіть
/sbin/blockу/sbin/block.bin; - збережіть новий
block-скрипт у/sbin/blockі зробіть його виконуваним.
Скрипт перевіряє наявність файлу /.use_crypt_extroot у змонтованому overlayfs (або /upper/.use_crypt_extroot у /overlay) — якщо файл відсутній, extroot не буде налаштований.
Це дозволяє легко відключити зашифрований extroot у разі потреби, наприклад, у failsafe-режимі.
Коли:
blockскрипт встановлено;decrypt.shприсутній;- налаштований
/etc/crypttab; - extroot змонтовано;
- файл
/.use_crypt_extrootіснує —
можна перезавантажити пристрій для входу в зашифрований extroot.
- block
#!/bin/sh # Залежності: # * пакети: # * block-mount # * cryptsetup # * перемістіть /sbin/block → /sbin/block.bin # * встановіть decrypt.sh у /sbin/decrypt.sh з правами на виконання # Цей скрипт повинен бути у /upper/sbin/block (UBIFS overlay) # або у /sbin/block, якщо overlay вже активний. export DEBUG= SDIR=${0%/*} BLOCK="${SDIR}/block.bin" LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-.} LD_LIBRARY_PATH="${SDIR}/../usr/lib:${LD_LIBRARY_PATH}" PATH=$PATH:${SDIR}:${SDIR}/../usr/sbin:${SDIR}/../usr/bin block() { ( exec -a ${0} ${BLOCK} "$@" ) } if [ "$PREINIT" != "1" ]; then exec block "$@" fi get_jiffies() { head -n3 /proc/timer_list | tail -n1 | cut -d' ' -f 3 } if [ -z "$BLOCK_LOG" ] && [ -n "$DEBUG" ]; then TIME=$(get_jiffies) export BLOCK_LOG="/tmp/block.$(printf '%016d' ${TIME:-9999999999}).log" exec 2>"$BLOCK_LOG" set -x fi if [ ! -x "$BLOCK" ]; then echo "Error: ${BLOCK} is not an executable" >&2 return 1 fi if [ "$1" = "extroot" ] && [ -e ${SDIR}/../.use_crypt_extroot ]; then for SYSDEVPATH in /sys/class/block/sd*; do [ ! -f "$SYSDEVPATH"/dev ] && continue [ -e "/dev/${SYSDEVPATH##*/}" ] && continue MAJMIN=$(cat "$SYSDEVPATH"/dev | tr ':' ' ') mknod /dev/${SYSDEVPATH##*/} b $MAJMIN done KVER=$(uname -r) insmod ${SDIR}/../lib/modules/${KVER}/af_alg.ko insmod ${SDIR}/../lib/modules/${KVER}/algif_rng.ko insmod ${SDIR}/../lib/modules/${KVER}/algif_hash.ko insmod ${SDIR}/../lib/modules/${KVER}/algif_skcipher.ko find /dev -type b | grep -E "/(sd|mmcblk).*" | while read DEVPATH; do cryptsetup --disable-locks isLuks $DEVPATH || continue export ACTION=add DEVNAME="${DEVPATH##*/}" ALTROOT="${SDIR}/.." "$SDIR"/decrypt.sh || "$SDIR"/decrypt.sh done fi block "$@"
/etc/rc.local
Існує ще один спосіб обійти існуючі обмеження. Однак його слід використовувати лише тоді, коли попередній метод не працює, оскільки цей підхід менш стабільний і може мати побічні ефекти.
Суть у тому, що extroot буде налаштований, як описано у інструкціях вище, але не буде змонтований під час стандартного завантаження, оскільки зашифрована extroot-файлова система не буде доступна. Це очікувано.
Зміни у файлі /etc/rc.local дозволять розблокувати LUKS розділ наприкінці процесу завантаження, коли ми маємо більше контролю над системою. Після цього буде повторно викликано mount_root, і extroot буде виявлено та змонтовано.
Ваш файл конфігурації fstab має містити секцію монтування з таргетом /overlay.
Краще використовувати параметр uuid замість device, щоб не синхронізувати вручну /etc/rc.local з /etc/config/fstab.
Нижче наведено приклад скрипта для вставлення в /etc/rc.local.
Цей скрипт не підтримує розблокування LUKS за паролем (stdin працює неправильно у цьому контексті).
Необхідно використовувати файл-ключ, наприклад: /root/extroot.key. Оцініть загрози, щоб визначити безпечність такого підходу.
# Виконується лише якщо існує /.use_crypt_extroot у rootfs_data. mkdir -p /mnt/tmp if [ -e /.use_crypt_extroot ]; then cryptsetup open -d /root/extroot.key /dev/sda1 cextroot umount /overlay mount --bind /tmp /mnt/tmp sleep 5 PREINIT=1 mount_root umount -l /tmp mount --bind /rom/mnt/tmp /tmp block mount service rpcd reload fi
Цей метод фактично повторює частину процесу завантаження, тому він трохи повільніший. На моєму пристрої веб-інтерфейс доступний на 20–30 секунд пізніше. SSH-з'єднання не затримується.
Оновлення системи
Цей розділ стосується лише snapshot-збірок OpenWrt, не релізів. У релізах kernel-пакети й пов'язані з ними отримують лише патчі безпеки.
НЕ використовуйте команду opkg upgrade для оновлень — це призведе до неконсистентного стану системи або soft-brick'у:
- ABI бібліотеки uClibc нестабільний, змінюється між версіями — двійкові файли можуть бути несумісними.
- UUID для розділів
/romабо/rwmможе змінитися після оновлення, що призведе до помилок монтування extroot. - Якщо оновити kernel-пакети, а потім перепрошити й перезавантажити пристрій, і щось піде не так — може виникнути невідповідність між ядром і модулями.
- Якщо оновити всі пакети, крім ядра, — пакети на зразок
iptablesможуть зламатися.
Також, якщо UUID ROM-партіції зміниться, можливо доведеться знову виконати кроки 3 та 4 з інструкцій.
Рекомендовано: після оновлення системи перевстановлювати всі пакети, особливо kernel-модулі.
Кастомна прошивка
Цей метод корисний для пристроїв з 4 МіБ флеш-пам'яті або менше. У типовому образі OpenWrt немає інструментів для extroot, оскільки система збірки створює лише мінімальні образи.
Єдиний варіант — зібрати прошивку самостійно за допомогою Image Builder.
Image Builder працює лише в 64-бітних Linux-системах. Якщо у вас немає такої — скористайтесь VirtualBox і встановіть Ubuntu 64-bit.
На сторінці завантаження прошивки для вашого пристрою знайдіть файл, що починається з “OpenWrt-imagebuilder”. Завантажте та розпакуйте його у папку в Linux-системі.
Відкрийте термінал у цій папці й виконайте:
make info
Це виведе список доступних профілів для збірки.
Приклад:
tl-wr1043nd-v1:
TP-LINK TL-WR1043N/ND v1
Packages: kmod-usb-core kmod-usb2 kmod-ledtrig-usbdev
Перший рядок — це назва профілю. Другий — опис пристрою. Третій — список пакетів за замовчуванням.
У моєму випадку назва профілю — tl-wr1043nd-v1. Для створення прошивки введіть:
make image PROFILE=tl-wr1043nd-v1 PACKAGES="block-mount kmod-fs-ext4 kmod-usb-storage kmod-usb-ohci kmod-usb-uhci"
Це створить прошивку з підтримкою ext4.
⚠️ Пакет e2fsprogs занадто великий для 4 МіБ flash, тому форматування USB-диска потрібно виконати заздалегідь на іншій системі.
Після збірки прошивки:
- Відкрийте папку bin, потім target, потім специфічну для пристрою, і знайдіть папку generic.
- Там будуть прошивки для встановлення (
factoryабоsysupgrade).
Щоб відформатувати USB у ext4, скористайтесь LiveCD або GParted Live.
Автоматичне налаштування
Ви можете скористатися frontend-інструментом openwrt-auto-extroot для ImageBuilder, щоб зібрати кастомну прошивку, яка автоматично відформатує та налаштує extroot на будь-якому підключеному, але ще не налаштованому пристрої зберігання.
Автоматичне оновлення
Налаштуйте Hotplug extras та Opkg extras.
Пакети, необхідні для роботи Extroot, мають бути збережені у профілі Opkg init і автоматично відновлені після оновлення за допомогою скрипта для повторного налаштування Extroot.
cat << "EOF" > /etc/uci-defaults/90-extroot-restore if uci -q get fstab.extroot > /dev/null \ && [ ! -e /etc/extroot-restore ] \ && [ -e /etc/opkg-restore-init ] \ && lock -n /var/lock/extroot-restore then UUID="$(uci -q get fstab.extroot.uuid)" DIR="$(uci -q get fstab.extroot.target)" DEV="$(block info | sed -n -e "/${UUID}/s/:.*$//p")" if touch /etc/extroot-restore \ && grep -q -e "\s${DIR}\s" /etc/mtab \ && mount "${DEV}" /mnt then BAK="$(mktemp -d -p /mnt -t bak.XXXXXX)" mv -f /mnt/etc /mnt/upper "${BAK}" cp -f -a "${DIR}"/. /mnt umount "${DEV}" fi lock -u /var/lock/extroot-restore reboot fi exit 1 EOF cat << "EOF" >> /etc/sysupgrade.conf /etc/uci-defaults EOF