2026-08-16 21:43:02 +03:00
|
|
|
#!/bin/bash
|
|
|
|
|
# Подъём Open vSwitch внутри контейнера и сборка моста br-lb.
|
|
|
|
|
#
|
|
|
|
|
# Контейнер работает как чистый OpenFlow-роутер: IP-адреса на интерфейсах не
|
|
|
|
|
# настраиваются, сетевой стек ядра в форвардинге не участвует. Вся L3-логика
|
|
|
|
|
# (ARP, маршрутизация, DNAT) живёт в таблицах OpenFlow — см. pipeline.sh.
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
LB_DIR=/opt/lb
|
|
|
|
|
# shellcheck disable=SC1091
|
|
|
|
|
source "$LB_DIR/topology.env"
|
|
|
|
|
|
|
|
|
|
log() { echo "[lb-router] $*"; }
|
|
|
|
|
die() { echo "[lb-router] ОШИБКА: $*" >&2; exit 1; }
|
|
|
|
|
|
|
|
|
|
# --- 1. Kernel datapath ------------------------------------------------------
|
|
|
|
|
log "загрузка модуля openvswitch"
|
|
|
|
|
modprobe openvswitch 2>/dev/null || true
|
|
|
|
|
grep -q '^openvswitch ' /proc/modules || die \
|
|
|
|
|
"модуль openvswitch не загружен. Выполните на хосте: modprobe openvswitch (см. scripts/host-prereq.sh)"
|
|
|
|
|
|
|
|
|
|
# --- 2. Запуск ovsdb-server и ovs-vswitchd -----------------------------------
|
|
|
|
|
mkdir -p /var/run/openvswitch /var/log/openvswitch /etc/openvswitch
|
|
|
|
|
rm -f /var/run/openvswitch/*.pid
|
|
|
|
|
|
|
|
|
|
if [ ! -f /etc/openvswitch/conf.db ]; then
|
|
|
|
|
log "инициализация OVSDB"
|
|
|
|
|
ovsdb-tool create /etc/openvswitch/conf.db /usr/share/openvswitch/vswitch.ovsschema
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
log "запуск ovsdb-server"
|
|
|
|
|
ovsdb-server /etc/openvswitch/conf.db \
|
|
|
|
|
--remote=punix:/var/run/openvswitch/db.sock \
|
|
|
|
|
--remote=db:Open_vSwitch,Open_vSwitch,manager_options \
|
|
|
|
|
--pidfile --detach --log-file
|
|
|
|
|
ovs-vsctl --no-wait init
|
|
|
|
|
|
|
|
|
|
log "запуск ovs-vswitchd"
|
|
|
|
|
ovs-vswitchd --pidfile --detach --log-file
|
|
|
|
|
|
|
|
|
|
# --- 3. Мост -----------------------------------------------------------------
|
|
|
|
|
log "создание моста $BR"
|
|
|
|
|
ovs-vsctl --may-exist add-br "$BR" \
|
|
|
|
|
-- set bridge "$BR" fail_mode=secure \
|
|
|
|
|
-- set bridge "$BR" protocols=OpenFlow13,OpenFlow15 \
|
|
|
|
|
-- set bridge "$BR" other-config:disable-in-band=true
|
|
|
|
|
ip link set dev "$BR" up
|
|
|
|
|
|
|
|
|
|
# --- 4. Перенос интерфейсов Docker в мост ------------------------------------
|
|
|
|
|
# Интерфейсы опознаются по MAC (имена eth0/eth1/eth2 Docker раздаёт в
|
|
|
|
|
# непредсказуемом порядке), переименовываются в осмысленные и лишаются IP:
|
|
|
|
|
# адрес нужен только Docker IPAM, чтобы зарезервировать его за контейнером.
|
|
|
|
|
find_dev_by_mac() {
|
|
|
|
|
local mac="$1" d
|
|
|
|
|
for d in /sys/class/net/*; do
|
|
|
|
|
[ -f "$d/address" ] || continue
|
|
|
|
|
[ "$(cat "$d/address")" = "$mac" ] && { basename "$d"; return 0; }
|
|
|
|
|
done
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attach_port() {
|
|
|
|
|
local mac="$1" name="$2" ofport="$3" dev
|
|
|
|
|
dev=$(find_dev_by_mac "$mac") || die "интерфейс с MAC $mac не найден"
|
|
|
|
|
if [ "$dev" != "$name" ]; then
|
|
|
|
|
ip link set dev "$dev" down
|
|
|
|
|
ip addr flush dev "$dev"
|
|
|
|
|
ip link set dev "$dev" name "$name"
|
|
|
|
|
else
|
|
|
|
|
ip addr flush dev "$name"
|
|
|
|
|
fi
|
|
|
|
|
ip link set dev "$name" up
|
|
|
|
|
ovs-vsctl --may-exist add-port "$BR" "$name" \
|
|
|
|
|
-- set Interface "$name" ofport_request="$ofport"
|
|
|
|
|
log "порт $name (MAC $mac) -> $BR, ofport $ofport"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attach_port "$PUB_MAC" "$PUB_IFNAME" "$PUB_OFPORT"
|
|
|
|
|
attach_port "$P2_MAC" "$P2_IFNAME" "$P2_OFPORT"
|
|
|
|
|
attach_port "$P3_MAC" "$P3_IFNAME" "$P3_OFPORT"
|
|
|
|
|
|
|
|
|
|
# --- 4a. Порты-источники health-проб -----------------------------------------
|
|
|
|
|
# Единственные адреса, которые узел держит в ядре: с них уходят пробы (§7.1
|
|
|
|
|
# дизайна v1 — источник проб должен быть уникальным адресом узла, не VIP).
|
2026-08-19 12:33:48 +03:00
|
|
|
#
|
|
|
|
|
# MAC членов пула здесь больше НЕ прописывается статически (шаг 5): hcif-порты
|
|
|
|
|
# — настоящие L3-интерфейсы ядра в том же сегменте, что и бэкенды, и ядро само
|
|
|
|
|
# резолвит их MAC обычным ARP. Первая проба после старта чуть медленнее (кадр
|
|
|
|
|
# ARP-запроса уходит через br-lb и возвращается ответом реального бэкенда), но
|
|
|
|
|
# дальше запись живёт в neigh-таблице ядра обычным старением ARP — именно её
|
|
|
|
|
# читает hcd (hc/neigh.go) и заливает в таблицу 21 OpenFlow.
|
2026-08-16 21:43:02 +03:00
|
|
|
hc_port() {
|
|
|
|
|
local name="$1" ofport="$2" mac="$3" ip="$4" net="$5"
|
|
|
|
|
ovs-vsctl --may-exist add-port "$BR" "$name" \
|
|
|
|
|
-- set Interface "$name" type=internal ofport_request="$ofport" \
|
|
|
|
|
-- set Interface "$name" mac="\"$mac\""
|
|
|
|
|
ip link set dev "$name" address "$mac"
|
|
|
|
|
ip addr replace "$ip/${net##*/}" dev "$name"
|
|
|
|
|
ip link set dev "$name" up
|
2026-08-19 12:33:48 +03:00
|
|
|
log "порт $name ($ip) — источник health-проб"
|
2026-08-16 21:43:02 +03:00
|
|
|
}
|
|
|
|
|
|
2026-08-19 12:33:48 +03:00
|
|
|
hc_port "$HC2_IFNAME" "$HC2_OFPORT" "$HC2_MAC" "$HC2_IP" "$P2_NET"
|
|
|
|
|
hc_port "$HC3_IFNAME" "$HC3_OFPORT" "$HC3_MAC" "$HC3_IP" "$P3_NET"
|
2026-08-16 21:43:02 +03:00
|
|
|
|
|
|
|
|
# Ждём, пока vswitchd реально привяжет порты к датапасу.
|
|
|
|
|
for name in "$PUB_IFNAME" "$P2_IFNAME" "$P3_IFNAME"; do
|
|
|
|
|
for _ in $(seq 30); do
|
|
|
|
|
ofport=$(ovs-vsctl --if-exists get Interface "$name" ofport || echo -1)
|
|
|
|
|
[ "$ofport" -gt 0 ] 2>/dev/null && break
|
|
|
|
|
sleep 0.5
|
|
|
|
|
done
|
|
|
|
|
[ "${ofport:-0}" -gt 0 ] 2>/dev/null || die "порт $name не привязался к датапасу: $(ovs-vsctl get Interface "$name" error 2>/dev/null || true)"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# --- 5. Пайплайн -------------------------------------------------------------
|
|
|
|
|
# Таблица слотов здесь пуста (fail-close) — её наполнит hcd после первых
|
|
|
|
|
# успешных проб, поэтому apply.sh на этом этапе демона ещё не дёргает.
|
|
|
|
|
"$LB_DIR/apply.sh" --no-reapply
|
|
|
|
|
|
|
|
|
|
log "готово. Порты: $(ovs-vsctl list-ports "$BR" | tr '\n' ' ')"
|
|
|
|
|
|
|
|
|
|
# --- 6. Health-check ---------------------------------------------------------
|
|
|
|
|
# Демон становится основным процессом контейнера; ovsdb-server и ovs-vswitchd
|
|
|
|
|
# работают демонами рядом. Логи проб и переходов видны в docker logs.
|
|
|
|
|
CONF=$("$LB_DIR/hc-config.sh")
|
|
|
|
|
log "конфигурация health-check: $CONF"
|
|
|
|
|
|
|
|
|
|
tail -F --pid=$$ /var/log/openvswitch/ovs-vswitchd.log 2>/dev/null &
|
|
|
|
|
|
|
|
|
|
exec hcd -config "$CONF"
|