MVP Single Node with Manual Config in Docker
This commit is contained in:
commit
8212699f23
27 files changed
+3818
No files matched your search
@@ -0,0 +1,103 @@
|
||||
# Шаг 1 — итоги: прототип окружения hpnn_v2
|
||||
|
||||
**Дата:** 2026-08-16
|
||||
**Статус:** выполнено, стенд поднят и проверен (30 из 30 проверок)
|
||||
**План:** [STEP1_IMPLEMENTATION_PLAN.md](STEP1_IMPLEMENTATION_PLAN.md)
|
||||
|
||||
## Что сделано
|
||||
|
||||
Собрано контейнерное окружение из трёх сетей и трёх контейнеров, на котором
|
||||
работают обе подсистемы — маршрутизация и балансировка нагрузки. Всё
|
||||
форвардинг-решение принимается в OpenFlow: сетевой стек ядра контейнера
|
||||
транзитный трафик не обрабатывает.
|
||||
|
||||
- **Контейнер 1 (`hpnn-lb`)** — Open vSwitch с kernel datapath в собственном
|
||||
netns, мост `br-lb` с тремя портами. Пайплайн из 42 правил и группы
|
||||
балансировки рендерится скриптом из `topology.env` и заливается атомарным
|
||||
бандлом.
|
||||
- **Контейнеры 2 и 3 (`hpnn-be1`, `hpnn-be2`)** — идентичный web-сервис на Go,
|
||||
каждый в своём приватном сегменте; отдаёт имя хоста, дату, время и адрес
|
||||
клиента.
|
||||
- **Сети** — публичный сегмент через macvlan поверх `enp3s0` (настоящий L2
|
||||
клиентской сети) и два приватных bridge-сегмента.
|
||||
- **Инструментарий** — `make up/down/flows/verify`, `lbctl` для осмотра
|
||||
датапаса, `scripts/host-prereq.sh` для подготовки хоста.
|
||||
|
||||
## Результаты проверок
|
||||
|
||||
| Проверка | Результат |
|
||||
|---|---|
|
||||
| Kernel datapath OVS в netns контейнера | `system@ovs-system`, поддержка recirculation, ct_state_nat, ct_zone |
|
||||
| macvlan-интерфейс как порт OVS | работает, `pub0` — ofport 1 |
|
||||
| `selection_method=hash, fields(ip_src,tcp_src)` | принят OVS 3.1 |
|
||||
| Балансировка 20 запросов с клиента | be1/be2 ≈ 10/10, счётчики обоих бакетов растут |
|
||||
| Сохранение IP клиента | бэкенд видит `192.168.5.13` — DNAT без SNAT подтверждён |
|
||||
| ARP- и ICMP-респондеры OVS | `ping` до узла и до VIP проходит |
|
||||
| Маршрутизация между приватными сегментами | `be1 → be2` через таблицы 20/21 |
|
||||
| Профиль A (§3.2 дизайна v1) | egress бэкенда наружу работает и на порту `p2` не появляется |
|
||||
| `ofproto/trace` пути клиент → VIP | DNAT, `dec_ttl`, перепись MAC, выход в порт 2 |
|
||||
|
||||
## Отличия от плана
|
||||
|
||||
1. **Публичная сеть объявлена с подсетью `192.168.55.0/24`, а не
|
||||
`192.168.5.0/24`.** Docker отказывается регистрировать пул, пересекающийся
|
||||
с уже существующей macvlan-сетью соседнего стенда `router-functest`
|
||||
(`Pool overlaps with other one on this address space`). Объявленная подсеть
|
||||
нужна только Docker IPAM: адреса узла и VIP живут исключительно в правилах
|
||||
OpenFlow, а macvlan включён в `enp3s0` и работает на реальном L2.
|
||||
|
||||
2. **Обратный путь занял таблицы 15 и 16 вместо 30 и 31.** `goto_table` в
|
||||
OpenFlow разрешает переход только вперёд, поэтому таблицы обратного пути
|
||||
обязаны стоять до общей маршрутизации (20).
|
||||
|
||||
3. **DNAT вынесен из бакетов группы в отдельную таблицу 11.** Бакет только
|
||||
кладёт номер члена пула в `reg2` и делает `resubmit`. Так вся логика
|
||||
трансляции лежит в одном месте и не зависит от того, какие действия
|
||||
допустимы внутри бакета.
|
||||
|
||||
4. **Обучение MAC клиентов сужено** до трафика, адресованного стенду (VIP,
|
||||
адрес узла, приватные сегменты). В первой редакции `learn` срабатывал на
|
||||
любой IP-пакет с macvlan-порта и заносил в таблицу 21 весь
|
||||
широковещательный шум сегмента — DHCP, mDNS, SSDP всех соседей по LAN.
|
||||
|
||||
5. **Проверка профиля A добавлена в `verify.sh`** — в плане она была только
|
||||
ручной.
|
||||
|
||||
## Известные ограничения
|
||||
|
||||
Осознанные упрощения шага 1, каждое — задача следующих шагов:
|
||||
|
||||
- **Датапас stateful.** Обратную трансляцию выполняет `ct(nat)`, а не
|
||||
stateless un-DNAT из §2 дизайна v1. Следствие: прямой и обратный трафик
|
||||
сессии обязаны проходить через один узел, то есть Active/Active ECMP в такой
|
||||
схеме работать не будет.
|
||||
- **ICMP-ошибки не генерируются.** У чисто-OpenFlow узла нет стека, который бы
|
||||
формировал `TTL exceeded` и `fragmentation needed`; PMTUD через стенд не
|
||||
работает, `traceroute` не показывает узел.
|
||||
- **Фрагменты IP не обрабатываются** — правила матчат L4-заголовок, которого
|
||||
во втором и последующих фрагментах нет.
|
||||
- **Один узел LB.** Ни BGP, ни BFD, ни ECMP-набора: FRR в стенде нет, место
|
||||
под него (internal-порты с IP) на шаге 1 не занято, поскольку маршрутизация
|
||||
выполняется целиком в OpenFlow.
|
||||
- **Нет health-check.** Бэкенды считаются живыми всегда; отказ бэкенда не
|
||||
выводит его из группы. У приложения есть `/healthz` как задел.
|
||||
- **Пул и листенер статические** — заданы в `topology.env`, control plane и
|
||||
OVSDB-схемы из §6 дизайна v1 нет.
|
||||
- **MAC бэкендов прописаны статически.** ARP-резолвер next-hop отсутствует;
|
||||
MAC зафиксированы в `docker-compose.yml`.
|
||||
- **Только TCP и только IPv4.** UDP- и L3-листенеров нет.
|
||||
|
||||
## Задел на шаг 2
|
||||
|
||||
1. Заменить `ct(nat)` на stateless DNAT/un-DNAT с таблицей слотов и
|
||||
`multipath(symmetric_l4)` — это спайк S0 из §12 дизайна v1 и предпосылка
|
||||
для Active/Active.
|
||||
2. Проверить детерминизм выбора бэкенда: один и тот же 5-tuple должен давать
|
||||
один и тот же слот на разных узлах и между перезапусками
|
||||
(`ofproto/trace` по корпусу синтетических кортежей).
|
||||
3. Подсистема health-check: пробы с уникального адреса узла, вывод члена из
|
||||
пула, перерасчёт таблицы слотов.
|
||||
4. Control plane: модель `Load_Balancer → Listener → Pool → Member` в OVSDB
|
||||
вместо `topology.env`, агент-рендерер пайплайна.
|
||||
5. ICMP-транслятор в userspace (packet-in) — для PMTUD и корректных
|
||||
ICMP-ошибок от имени VIP.
|
||||
Reference in new issue
Block a user