Files
hpnn-proto/docs/STEP1_SUMMARY.md
T
ayurishchevandClaude Opus 5 fa389f119b Шаг 5: динамическое изучение MAC/ARP для бэкендов
MAC каждого члена пула больше не статическая константа в topology.env,
а резолвится демоном hcd через обычный ARP ядра — в реальном
окружении MAC бэкенда заранее не известен (сервер ещё не подключён,
NIC может замениться), топология не описывается статически, в отличие
от стенда.

hcif-порты (единственные адреса узла в ядре) уже были настоящими
L3-интерфейсами в тех же сегментах, что и бэкенды — единственное, что
мешало обычному ARP, это permanent-записи ip neigh в entrypoint.sh.
Убрав их и добавив hc/neigh.go (читает ip -json neigh show, точечно
заливает бандл в таблицу 21 на том же тикере, что и health-пробы),
получили резолвер без нового OpenFlow-контроллера.

Таблица 21 стала единственным источником MAC для обоих путей —
маршрутизируемого и коммутируемого (шаг 3): таблица 12 больше не
дублирует MAC инлайново, ct(commit) ведёт сразу в таблицу 21.

Исправлен попутно найденный баг: после apply.sh (replace-flows)
таблица 21 не восстанавливалась, поскольку syncNeighbors сравнивал
MAC с памятью демона, а не с датапасом. Добавлен force-режим по
аналогии с Agent.apply(), плюс регрессионная проверка в verify.sh.

Проверено на живом стенде: MAC всех четырёх членов резолвлен и
совпадает с реальными интерфейсами; смена MAC "железа" обнаружена и
применена без вмешательства за счёт штатного старения ARP ядра.
Регрессия: 94 из 94 проверок.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 12:33:48 +03:00

105 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Шаг 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 отсутствует~~ —
снято на шаге 5: `hcd` резолвит MAC членов пула через обычный ARP ядра, см.
[STEP5_SUMMARY.md](STEP5_SUMMARY.md).
- **Только 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.