92 lines
7.2 KiB
Markdown
92 lines
7.2 KiB
Markdown
# E3 План реализации мультиинтерфейса (execution roadmap)
|
||
|
||
Дата: 2026-03-15
|
||
Статус: in-progress
|
||
Владелец: Engineering
|
||
|
||
## 1) Цель
|
||
- Реализовать мультиинтерфейсную архитектуру для transport-клиентов (`singbox`, далее `dnstt`, `phoenix`) без конфликтов маршрутизации.
|
||
- Сохранить инвариант: вся логика маршрутизации живёт в Go-ядре, GUI/Web/Mobile остаются тонкими клиентами API.
|
||
- Добавить безопасный path миграции без поломки текущего single-interface контура.
|
||
|
||
## 2) Инварианты реализации
|
||
- Никаких прямых мутаций `ip rule`/`ip route`/`nft` из UI.
|
||
- Один destination/intent может иметь только одного owner (до явного override).
|
||
- Сначала foundation/state/contract, потом orchestration data-plane.
|
||
- Каждый этап обратим (rollback), каждый этап проверяется `go test ./...`.
|
||
|
||
## 3) Фазы
|
||
|
||
### M1. Foundation интерфейсов (без изменения data-plane)
|
||
- Добавить логический `iface_id` в `TransportClient` (default: `shared`).
|
||
- Добавить state-файл интерфейсов (`transport-interfaces.json`) и нормализацию.
|
||
- Добавить read-only endpoint `GET /api/v1/transport/interfaces`.
|
||
- Обновить трекер и тесты миграции state.
|
||
- Критерий: поведение runtime не меняется, старые профили продолжают работать.
|
||
|
||
### M2. Interface Orchestrator core (E3.3)
|
||
- Ввести оркестратор `create/bind/start/stop/cleanup` по `iface_id`.
|
||
- Разделить "логический интерфейс" (`iface_id`) и "runtime iface" (`tunX/dev`) с явным mapping.
|
||
- Добавить lock-стратегию на уровне `iface_id`, чтобы исключить race между клиентами.
|
||
- Критерий: один API-path для оркестрации всех движков, без дублирования per-client логики.
|
||
|
||
### M3. Policy compiler per-interface
|
||
- Компилировать intents в наборы правил per `iface_id`: table/mark/pref/nft sets.
|
||
- Гарантировать непересекаемые allocator-пулы для разных интерфейсов.
|
||
- Подготовить атомарный apply-plan для группы интерфейсов.
|
||
- Критерий: отдельные интерфейсы не перетирают таблицы/правила друг друга.
|
||
|
||
### M4. Anti-mixing и ownership guardrails (E3.4/E3.5)
|
||
- Strict ownership registry (`domain/cidr/app`) с явным conflict reason.
|
||
- Destination stickiness (`conntrack mark` + owner lock).
|
||
- Predictable override-flow с подтверждением.
|
||
- Критерий: один destination не может "гулять" между двумя интерфейсами без явного switch.
|
||
|
||
### M5. Transaction pipeline (E3.6)
|
||
- Расширить apply до `validate -> plan -> confirm -> apply -> health-check -> commit`.
|
||
- На любой ошибке health-check выполнять auto-rollback на previous snapshot.
|
||
- Добавить idempotency/optimistic lock для multi-interface apply.
|
||
- Критерий: частично применённой политики не остаётся.
|
||
|
||
### M6. Unified observability API (E6.6)
|
||
- Добавить runtime endpoint для карточек/дашбордов:
|
||
- `active_iface`,
|
||
- `egress` (ip/country),
|
||
- `latency`,
|
||
- `last_error`,
|
||
- counters per engine/policy.
|
||
- Вынести метрики в единый DTO для GUI/Web/Mobile.
|
||
- Критерий: UI не склеивает статус из нескольких endpoint-ов вручную.
|
||
|
||
### M7. UI/Web адаптация после backend-ready
|
||
- Desktop: переключение iface/client через новый orchestration API.
|
||
- Web/Mobile: reuse того же backend-контракта без новой бизнес-логики.
|
||
- Добавить feature-flag/compat-mode для плавной миграции.
|
||
- Критерий: backend-контракт единый для всех фронтов.
|
||
- Текущий дизайн desktop-first зафиксирован: `docs/phase-e/E4_2_MULTI_INTERFACE_GUI_DESIGN.md`.
|
||
|
||
## 4) Что делаем прямо сейчас
|
||
- M1 завершён:
|
||
- `iface_id` + `transport-interfaces` state + `GET /transport/interfaces` + тесты.
|
||
- M2 завершён:
|
||
- добавлен per-`iface_id` lock manager для mutating lifecycle/provision (`start/stop/restart/provision`);
|
||
- добавлен mapping-layer `iface_id -> runtime_iface/netns/routing_table` (dedicated iface defaults + interface hints + apply на create/patch/lifecycle/netns-toggle/provision);
|
||
- закрыт owner-scope compile этап: `nft_set` генерируется в scope `iface+client+selector` (без shared-set mixing на одном `iface_id`).
|
||
- M3 завершён (foundation):
|
||
- добавлен compile-plan `iface_id -> table/mark/pref/nft sets` с persisted state (`transport-policies.plan.json`) и возвратом в `validate/apply/rollback/get-policy`;
|
||
- добавлен atomic apply executor foundation (`transport-policies.runtime.json` + runtime snapshot/restore) и врезан в `apply/rollback` до commit policy revision;
|
||
- подключён kernel stage в executor: per-interface CIDR nft sets apply/cleanup + optional `ip rule` stage под feature-flag;
|
||
- ownership foundation (M4-start): добавлен persisted registry `transport-ownership.json` + `GET /api/v1/transport/owners`;
|
||
- apply guardrails усилены: `force_override` допускается только для `owner_switch`, hard blocks не bypass-ятся override-флагом;
|
||
- anti-mixing foundation (M4-start): owner switch теперь блокируется runtime owner-lock (если previous owner в статусе `up|starting|degraded`);
|
||
- ownership observability: `GET /api/v1/transport/owners` аннотирует записи `owner_status/lock_active`, возвращает агрегат `lock_count` для UI/Web;
|
||
- conntrack stickiness foundation:
|
||
- kernel-stage (feature-flag `SVPN_TRANSPORT_POLICY_CONNTRACK_STICKY=1`) собирает destination-lock state из `conntrack -L -f ipv4` по `mark -> owner`;
|
||
- persisted state: `transport-owner-locks.json`;
|
||
- read-only endpoint: `GET /api/v1/transport/owner-locks`;
|
||
- validate/apply добавляют `destination_lock` block для `cidr` owner-switch, если destination ещё sticky-locked на предыдущего owner.
|
||
- owner-lock recovery:
|
||
- endpoint `POST /api/v1/transport/owner-locks/clear` (point clear by `client_id` and/or `destination_ip(s)`);
|
||
- двухшаговый confirm flow (`confirm_token`) для предотвращения случайного lock-loss.
|
||
- следующий шаг: hardening kernel stage (расширение selector coverage, guardrails/observability) + M4 stickiness (`conntrack owner lock`).
|