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>
8.0 KiB
Шаг 1 — итоги: прототип окружения hpnn_v2
Дата: 2026-08-16 Статус: выполнено, стенд поднят и проверен (30 из 30 проверок) План: 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 |
Отличия от плана
-
Публичная сеть объявлена с подсетью
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. -
Обратный путь занял таблицы 15 и 16 вместо 30 и 31.
goto_tableв OpenFlow разрешает переход только вперёд, поэтому таблицы обратного пути обязаны стоять до общей маршрутизации (20). -
DNAT вынесен из бакетов группы в отдельную таблицу 11. Бакет только кладёт номер члена пула в
reg2и делаетresubmit. Так вся логика трансляции лежит в одном месте и не зависит от того, какие действия допустимы внутри бакета. -
Обучение MAC клиентов сужено до трафика, адресованного стенду (VIP, адрес узла, приватные сегменты). В первой редакции
learnсрабатывал на любой IP-пакет с macvlan-порта и заносил в таблицу 21 весь широковещательный шум сегмента — DHCP, mDNS, SSDP всех соседей по LAN. -
Проверка профиля 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.- Только TCP и только IPv4. UDP- и L3-листенеров нет.
Задел на шаг 2
- Заменить
ct(nat)на stateless DNAT/un-DNAT с таблицей слотов иmultipath(symmetric_l4)— это спайк S0 из §12 дизайна v1 и предпосылка для Active/Active. - Проверить детерминизм выбора бэкенда: один и тот же 5-tuple должен давать
один и тот же слот на разных узлах и между перезапусками
(
ofproto/traceпо корпусу синтетических кортежей). - Подсистема health-check: пробы с уникального адреса узла, вывод члена из пула, перерасчёт таблицы слотов.
- Control plane: модель
Load_Balancer → Listener → Pool → Memberв OVSDB вместоtopology.env, агент-рендерер пайплайна. - ICMP-транслятор в userspace (packet-in) — для PMTUD и корректных ICMP-ошибок от имени VIP.