Files
hpnn-proto/lb/entrypoint.sh
T

137 lines
6.3 KiB
Bash
Executable File

#!/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).
# MAC бэкенда прописывается статически: ARP-резолвер узлу не нужен, MAC членов
# пула и так зафиксированы в docker-compose.yml.
hc_port() {
local name="$1" ofport="$2" mac="$3" ip="$4" net="$5"
shift 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
# Остальные аргументы — пары «адрес MAC» членов пула в этом сегменте.
local peers=""
while [ $# -ge 2 ]; do
ip neigh replace "$1" lladdr "$2" dev "$name" nud permanent
peers="$peers $1"
shift 2
done
log "порт $name ($ip) — источник health-проб для$peers"
}
hc_port "$HC2_IFNAME" "$HC2_OFPORT" "$HC2_MAC" "$HC2_IP" "$P2_NET" \
"$BE1_IP" "$BE1_MAC" "$BE3_IP" "$BE3_MAC"
hc_port "$HC3_IFNAME" "$HC3_OFPORT" "$HC3_MAC" "$HC3_IP" "$P3_NET" \
"$BE2_IP" "$BE2_MAC" "$BE4_IP" "$BE4_MAC"
# Ждём, пока 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"