Files
hpnn-proto/scripts/attach-segment.sh
T

115 lines
5.1 KiB
Bash
Executable File

#!/bin/bash
# Подключение ВМ приватных сегментов к мосту br-lb (шаг 3).
#
# В целевой среде порты виртуальных машин создаёт гипервизор, и каждая ВМ уже
# висит на vSwitch. В контейнерном стенде эту роль выполняет этот скрипт: для
# каждого участника сегмента он создаёт veth-пару, один конец кладёт в сетевое
# пространство имён контейнера, другой — в netns балансировщика и добавляет в
# br-lb с детерминированным ofport.
#
# Адрес, MAC и маршруты назначаются СНАРУЖИ, как это делают гипервизор и DHCP.
# Внутри ОС ВМ ничего не настраивается — это условие шага 3.
#
# Запускать на хосте с правами root, после docker compose up:
# sudo scripts/attach-segment.sh # подключить
# sudo scripts/attach-segment.sh --status # показать порты моста
# sudo scripts/attach-segment.sh --detach # снять порты
set -euo pipefail
cd "$(dirname "$0")/.."
# shellcheck disable=SC1091
source lb/topology.env
LB_CONTAINER=hpnn-lb
log() { echo "[attach] $*"; }
die() { echo "[attach] ОШИБКА: $*" >&2; exit 1; }
[ "$(id -u)" = 0 ] || die "нужны права root (sudo scripts/attach-segment.sh)"
pid_of() {
local pid
pid=$(docker inspect -f '{{.State.Pid}}' "$1" 2>/dev/null) || die "контейнер $1 не найден"
[ "$pid" != "0" ] || die "контейнер $1 не запущен"
echo "$pid"
}
# attach <контейнер> <имя порта> <ofport> <mac> <ip> <префикс> <шлюз|-> [сеть via LB]...
attach() {
local cname="$1" port="$2" ofport="$3" mac="$4" ip="$5" plen="$6" gw="$7"
shift 7
local pid pid_lb tmp
pid=$(pid_of "$cname")
pid_lb=$(pid_of "$LB_CONTAINER")
if nsenter -t "$pid" -n ip link show eth0 >/dev/null 2>&1; then
log "$cname уже подключён, пропуск"
return 0
fi
# Временное имя нужно потому, что оба конца veth рождаются в netns хоста и
# имя eth0 там почти наверняка занято.
tmp="tmp$$-${ofport}"
ip link add "$port" type veth peer name "$tmp"
ip link set "$port" netns "$pid_lb"
ip link set "$tmp" netns "$pid"
nsenter -t "$pid" -n ip link set "$tmp" name eth0
nsenter -t "$pid" -n ip link set eth0 address "$mac"
nsenter -t "$pid" -n ip addr replace "$ip/$plen" dev eth0
nsenter -t "$pid" -n ip link set eth0 up
# Профиль A: default остаётся на шлюзе Docker, через LB маршрутизируются
# только клиентские префиксы и соседний сегмент. Клиентам не выдаётся ничего.
[ "$gw" = "-" ] || nsenter -t "$pid" -n ip route replace default via "$gw"
while [ $# -ge 1 ]; do
nsenter -t "$pid" -n ip route replace "$1" via "$2"
shift 2
done
nsenter -t "$pid_lb" -n ip link set "$port" up
docker exec "$LB_CONTAINER" ovs-vsctl --may-exist add-port "$BR" "$port" \
-- set Interface "$port" ofport_request="$ofport" >/dev/null
log "$cname -> порт $port (ofport $ofport), $ip/$plen, MAC $mac"
}
detach() {
local port
for port in be1 be3 cli2 be2 be4 cli3; do
docker exec "$LB_CONTAINER" ovs-vsctl --if-exists del-port "$BR" "$port" >/dev/null 2>&1 || true
done
log "порты сегментов сняты с моста (интерфейсы исчезнут вместе с контейнерами)"
}
status() {
docker exec "$LB_CONTAINER" ovs-ofctl -O "$OF" show "$BR" | grep -E '^\s+[0-9]+\('
}
case "${1:-}" in
--status) status; exit 0 ;;
--detach) detach; exit 0 ;;
esac
p2len=${P2_NET##*/}
p3len=${P3_NET##*/}
# Бэкенды сегмента 2: default на docker-шлюз, клиентский префикс и соседний
# сегмент — через балансировщик.
attach hpnn-be1 be1 "$BE1_OFPORT" "$BE1_MAC" "$BE1_IP" "$p2len" "$P2_DOCKER_GW" \
192.168.5.0/24 "$LB_P2_IP" "$P3_NET" "$LB_P2_IP"
attach hpnn-be3 be3 "$BE3_OFPORT" "$BE3_MAC" "$BE3_IP" "$p2len" "$P2_DOCKER_GW" \
192.168.5.0/24 "$LB_P2_IP" "$P3_NET" "$LB_P2_IP"
attach hpnn-be2 be2 "$BE2_OFPORT" "$BE2_MAC" "$BE2_IP" "$p3len" "$P3_DOCKER_GW" \
192.168.5.0/24 "$LB_P3_IP" "$P2_NET" "$LB_P3_IP"
attach hpnn-be4 be4 "$BE4_OFPORT" "$BE4_MAC" "$BE4_IP" "$p3len" "$P3_DOCKER_GW" \
192.168.5.0/24 "$LB_P3_IP" "$P2_NET" "$LB_P3_IP"
# Клиенты: только адрес и маска. Ни маршрутов, ни дополнительных интерфейсов —
# ровно то, что требует условие шага 3.
attach hpnn-cli2 cli2 "$CLI2_OFPORT" "$CLI2_MAC" "$CLI2_IP" "$p2len" -
attach hpnn-cli3 cli3 "$CLI3_OFPORT" "$CLI3_MAC" "$CLI3_IP" "$p3len" -
log "готово"
status