diff --git a/02_configure_host.sh b/02_configure_host.sh index f6bcb1a97..c8aa4bdf1 100755 --- a/02_configure_host.sh +++ b/02_configure_host.sh @@ -512,3 +512,8 @@ if [ "${PERSISTENT_IMAGEREG}" == true ] ; then sudo systemctl start nfs-server sudo exportfs -a fi + +# Optionally run a top-of-rack BGP speaker on the baremetal network +if [[ -n "${ENABLE_BGP_TOR:-}" ]]; then + bgp/configure_bgp_tor.sh +fi diff --git a/bgp/cleanup_bgp_tor.sh b/bgp/cleanup_bgp_tor.sh new file mode 100755 index 000000000..2ffd907e6 --- /dev/null +++ b/bgp/cleanup_bgp_tor.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euxo pipefail + +bgp_dir="$(dirname "$(readlink -f "$0")")" +# shellcheck disable=SC1091 +source "${bgp_dir}/../common.sh" + +# Tears down the optional top-of-rack BGP speaker deployed by +# configure_bgp_tor.sh. Tolerant of a missing container / firewall rule so +# it can run unconditionally from host_cleanup.sh. + +BGP_TOR_NAME="bgp-tor" +BGP_TOR_DIR="${WORKING_DIR}/bgp-tor" + +sudo podman rm -f "${BGP_TOR_NAME}" || true + +sudo firewall-cmd --zone=libvirt --permanent --remove-port=179/tcp || true +sudo firewall-cmd --zone=libvirt --remove-port=179/tcp || true + +rm -rf "${BGP_TOR_DIR}" diff --git a/bgp/configure_bgp_tor.sh b/bgp/configure_bgp_tor.sh new file mode 100755 index 000000000..ae6be3cb0 --- /dev/null +++ b/bgp/configure_bgp_tor.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +set -euxo pipefail + +bgp_dir="$(dirname "$(readlink -f "$0")")" +# shellcheck disable=SC1091 +source "${bgp_dir}/../common.sh" +# shellcheck disable=SC1091 +source "${bgp_dir}/../network.sh" + +# Deploys an FRR container on the host network acting as a top-of-rack BGP +# speaker for the baremetal network. Cluster nodes (e.g. BGP-based VIP +# management, enhancement openshift/enhancements#1982) peer with it via +# dynamic neighbors; learned routes are installed into the host kernel by +# zebra, so the hypervisor reaches advertised VIPs over the BGP paths. + +BGP_TOR_NAME="bgp-tor" +BGP_TOR_DIR="${WORKING_DIR}/bgp-tor" + +mkdir -p "${BGP_TOR_DIR}" + +if [[ -n "${EXTERNAL_SUBNET_V4:-}" ]]; then + ROUTER_ID="$(nth_ip "${EXTERNAL_SUBNET_V4}" 1)" +else + # BGP router IDs are always in IPv4 dotted-quad format; use a fixed + # documentation-range ID for IPv6-only deployments. + ROUTER_ID="192.0.2.1" +fi + +# Accept dynamic BGP sessions from anywhere on the external subnet(s) and +# only activate the address families a peer could exist on. +LISTEN_RANGES="" +ADDRESS_FAMILIES="" +if [[ -n "${EXTERNAL_SUBNET_V4:-}" ]]; then + LISTEN_RANGES+=" bgp listen range ${EXTERNAL_SUBNET_V4} peer-group CLUSTER +" + ADDRESS_FAMILIES+=" ! + address-family ipv4 unicast + neighbor CLUSTER activate + exit-address-family +" +fi +if [[ -n "${EXTERNAL_SUBNET_V6:-}" ]]; then + LISTEN_RANGES+=" bgp listen range ${EXTERNAL_SUBNET_V6} peer-group CLUSTER +" + ADDRESS_FAMILIES+=" ! + address-family ipv6 unicast + neighbor CLUSTER activate + exit-address-family +" +fi + +# "no bgp ebgp-requires-policy" relaxes RFC 8212; without it FRR 8+ refuses +# to exchange routes with eBGP peers unless explicit policies are configured. +cat > "${BGP_TOR_DIR}/frr.conf" < "${BGP_TOR_DIR}/daemons" <