Files
hpnn-proto/docs/STEP5_IMPLEMENTATION_PLAN.md
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

148 lines
10 KiB
Markdown
Raw Permalink 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.
# Шаг 5 — план внедрения: динамическое изучение MAC/ARP для бэкендов
**Дата:** 2026-08-18
**Предыдущий шаг:** [STEP3_SUMMARY.md](STEP3_SUMMARY.md) (реализован).
**Не путать с шагом 4** ([STEP4_PUBLIC_STATELESS_ASSESSMENT.md](STEP4_PUBLIC_STATELESS_ASSESSMENT.md))
— это только оценка перехода публичного пути на схему без conntrack, ещё не
реализована; данный шаг с ней не пересекается.
**Итоги:** [STEP5_SUMMARY.md](STEP5_SUMMARY.md)
## Задача
Сейчас MAC каждого члена пула — статическая константа (`BE1_MAC`…`BE4_MAC` в
`lb/topology.env`), продублированная в четырёх независимых местах: правило
`mod_dl_dst` в таблице 21 (routed-путь), инлайновый `mod_dl_dst` в таблице 12
(same-segment/коммутируемый путь шага 3), permanent-запись `ip neigh` в ядре
узла (`lb/entrypoint.sh`, для health-проб) и реальный MAC интерфейса ВМ
(`scripts/attach-segment.sh`). Все четыре обязаны совпадать вручную.
В реальном окружении MAC бэкенда заранее не известен: топология сети, в
отличие от стенда, не описывается статически. Уже задокументированный пробел
(`STEP1_SUMMARY.md`, известные ограничения: «MAC бэкендов прописаны статически.
ARP-резолвер next-hop отсутствует»), отдельно всплывший в оценке шага 4 (раздел
8, доставка до физического сервера в EVPN-фабрике).
Нужен компонент, изучающий MAC членов пула динамически, без предварительного
описания в конфигурации.
**Объём:** изучаются MAC только для адресов, уже известных из конфигурации
(member IP объявлен в `hc-config.sh`); обнаружение новых, необъявленных хостов
— вне рамок (отдельная задача control plane, уже отложена в `MULTITENANCY.md`).
Логика живёт в демоне `hcd` — расширение существующего единственного
control-plane процесса на ноде.
## Ключевая находка
Internal-порты `hcif-p2`/`hcif-p3` — единственные адреса узла, живущие в ядре
Linux, — уже настоящие L3-интерфейсы **в том же сегменте**, что и бэкенды.
Ядро уже способно резолвить их MAC обычным ARP; единственное препятствие —
статические `ip neigh ... nud permanent` записи в `lb/entrypoint.sh:99`,
которые ARP для этих адресов отключают навсегда. Подтверждено на живом стенде:
`ip -json neigh show` внутри `lb-router` сейчас отдаёт четыре записи с
`"state":["PERMANENT"]` — ровно то, что предстоит заменить на реальный ARP.
Дополнительно: `segment_ingress()`/`l3_learn()` в `lb/pipeline.sh` уже заливает
действием `learn` записи приоритета 90 в таблицу 21 для любого IP-трафика с
портов сегмента, включая ответы бэкендов на health-пробы — на живом стенде эти
записи присутствуют в `dump-flows table=21`, но перекрыты статическими
правилами приоритета 100. Задача не строит резолвер с нуля, а: (1) снимает
блокировку ARP ядра, (2) делает `hcd` явным и наблюдаемым источником MAC вместо
неявного поведения `learn`, (3) убирает дублирование MAC между таблицами 12 и
21.
## Разделение ответственности
| Кто | Адрес | Механизм |
|---|---|---|
| Клиенты | заранее неизвестен, произвольный | как сейчас — `learn` (таблица 21, приоритет 90), без изменений |
| Члены пула | известен из конфигурации, MAC — нет | новое: `hcd` резолвит через ядро (ARP на hcif-портах), заливает таблицу 21 приоритетом 100 |
## Изменения по файлам
### `lb/entrypoint.sh`
В `hc_port()` убрать `ip neigh replace ... nud permanent` для адресов членов
пула (строка 99, вызовы 106-109). MAC самого internal-порта (строка 93)
остаётся статичным — собственный адрес узла, не next-hop.
### `hc/neigh.go` (новый файл)
Работает на тикере health-проб (`cfg.interval`), без отдельной горутины:
- по `Source` члена и новому полю `iface` выполняет
`ip -json neigh show dev <iface> to <member_ip>`;
- MAC резолвлен при состоянии `REACHABLE`/`STALE`/`DELAY`/`PROBE`/`PERMANENT`;
- при изменении MAC — точечный бандл `ovs-ofctl bundle`: `flow delete
table=21,ip,nw_dst=<ip>` + `flow add table=21,priority=100,ip,nw_dst=<ip>
actions=mod_dl_dst:<mac>,output:<port>`;
- API: поле в `/status`, команда `lbctl neigh`.
### `lb/pipeline.sh`
- Убрать статические `table=21,priority=100,ip,nw_dst=$BE{1..4}_IP
actions=mod_dl_dst:$BE{n}_MAC,output:...` (строки 333-336). Записи для
`HC2_IP`/`HC3_IP` остаются статичными.
- Таблица 12, ветка same-segment (приоритет 200): убрать инлайновый
`mod_dl_dst:$mmac` (строка 284), `ct(commit,...)` направить в `table=21`
вместо `table=25`. Таблица 21 не декрементирует TTL — свойство «TTL не
уменьшается для соседей по сегменту» сохраняется, дублирование MAC между
таблицами уходит.
### `lb/topology.env`, `lb/hc-config.sh`
`BE1_MAC`…`BE4_MAC` перестают быть обязательными. Добавляется поле `iface` на
член пула.
### `lb/lbctl.sh`
Команда `neigh`: «член / адрес / MAC / состояние / возраст».
### `scripts/verify.sh`, `docs/MANUAL_TEST_PLAN.md`
- Таблица 21 заполняется динамически в течение нескольких секунд после старта.
- `lbctl neigh` показывает MAC, совпадающий с реальным MAC интерфейса ВМ.
- Смена MAC у `be1` обнаруживается `hcd` без разрыва доставки.
- Регрессия: все существующие проверки (оба листенера, транзит, health-check,
fail-close, дренаж, идемпотентность `apply.sh`) без изменений в поведении.
- `lbctl trace` same-segment пути — обновить ожидаемую цепочку (`12 → 21`
вместо `12 → 25`).
### Документация
`docs/PUBLIC_LB_DATAFLOW.md`, `docs/PRIVATE_LB_DATAFLOW.md` — таблица 21:
«статические MAC» → «резолвятся `hcd` через ядро». Снять пункт «MAC бэкендов
прописаны статически» из ограничений `STEP1_SUMMARY.md`. `README.md`.
## Порядок работ
1. `docs/STEP5_IMPLEMENTATION_PLAN.md` (этот документ).
2. ~~Спайк `ip -json neigh`~~ — выполнено, подтверждено на живом стенде.
3. `lb/entrypoint.sh` — снять статические `ip neigh permanent`; проверить ARP
вручную.
4. `hc/neigh.go` + правки `hc/main.go`.
5. `lb/pipeline.sh` — таблица 21 как единственный источник MAC.
6. `lb/hc-config.sh`, `lb/topology.env`.
7. `lb/lbctl.sh` — команда `neigh`.
8. Ручная проверка, затем `scripts/verify.sh` и `MANUAL_TEST_PLAN.md`.
9. `docs/STEP5_SUMMARY.md`, README, диаграммы потоков.
## Критерии приёмки
- `lbctl neigh` показывает реальный MAC каждого члена, совпадающий с
`ip link show eth0` внутри соответствующего контейнера;
- в `topology.env` нет обязательных `BE*_MAC`;
- смена MAC у бэкенда обнаруживается и трафик продолжает доставляться без
ручного вмешательства;
- все существующие проверки (`make verify`) проходят без изменений в
наблюдаемом поведении.
## Риски
- **Окно на холодном старте** таблицы 21 для члена, пока `hcd` не сделал
первый резолв — по порядку величины совпадает с существующим fail-close
таблицы слотов, новой категории риска не вводит.
- **Обнаружение новых, необъявленных хостов вне объёма** — осознанно отложено
к control plane (`MULTITENANCY.md`).
- **Изменение цепочки таблиц same-segment пути** — требует правки ожидаемых
трасс в документации.