114 lines
5.1 KiB
Bash
114 lines
5.1 KiB
Bash
#!/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
|