Create the Neutron external provider network that sources floating IPs and tenant router gateways (the FIP/ext_net leg of Option B), on top of the MAAS address carve done pre-deploy in phase-00. Also the IPAM reference for where addresses live.
Decisions: D-003 (provider shared-L2: public API VIPs + FIP/ext_net, Option B; FIP pool 10.12.5.0-10.12.7.254), the IPv4 provider/internal carve (front-loaded VIP /26), KI-P3-001 (VIP/primary collision -> the reserved-range fix). Troubleshooting: appendix-A -- KI-P3-001.
NOTE on what the "carve" is split across:
vip: values come from that reserved block -- phase-01.Provider 10.12.4.0/22 (role Provider; shared-L2, Option B):
neutron allocation_pool. Every bundle public `vip:` is from here.
Metal 10.12.8.0/22 (role Metal; charm control plane + internal VIPs):
KI-P3-001 invariant: on every space carrying juju VIPs (provider AND metal), the VIP block is MAAS-reserved and DISTINCT from the primary range and any neutron allocation_pool, so a MAAS auto-static primary can never land on a configured VIP. (Root cause of the original collision: provider had NO VIP reservation, so MAAS auto-assigned container primaries .225/.226/.227 onto the .224-.236 VIP block.)
ENV(physnet) physnet1ENV(ext-net) provider-ext ENV(ext-subnet) provider-ext-fipENV(ext-cidr) 10.12.4.0/22 (full provider /22 so .1 gateway is in-subnet + FIP ARP spans the L2)ENV(fip-pool) 10.12.5.0 - 10.12.7.254 (D-003 Option-A; ~765 FIPs; full pool, not a slice)# RUN: jumphost -- vopenstack-jesse as jessea123, admin-openrc sourced; openstack + maas admin.# RUN: jumphost --external but NOT --share (usable as router gateway + FIP source, but tenants cannot attach instance ports to the provider segment -- Option B isolation). --no-dhcp (MAAS owns DHCP on this segment; FIPs are NAT'd). The subnet is the FULL provider /22 with the FIP pool as the allocation_pool; the VIP block and primaries are MAAS-reserved so neutron never allocates them.
Read-only pre-check first (verify the FIP pool is MAAS-reserved so neutron can own it):
# RUN: jumphost (MAAS profile is 'admin'; never run 'maas list' -- it prints the API key, DOCFIX-016) maas admin ipranges read | jq -r '.[] | select(.type=="reserved") | "\(.start_ip)-\(.end_ip) subnet=\(.subnet.id) [\(.comment)]"' # expect a reserved 10.12.5.0-10.12.7.254 on subnet id 1 (provider); + the front-loaded VIP /26 reservations.
Create (idempotent ( set -e ); dynamic gateway; tags applied via set, not an inline --tag flag):
source ~/admin-openrc
( set -e
PHYSNET=physnet1; EXT_NET=provider-ext; EXT_SUBNET=provider-ext-fip
EXT_CIDR=10.12.4.0/22; FIP_START=10.12.5.0; FIP_END=10.12.7.254
GW=$(maas admin subnet read 1 | jq -r '.gateway_ip') # dynamic; never hardcode .1
[ "$GW" = "10.12.4.1" ] || { echo "GATE FAIL: MAAS provider gateway='$GW' (expected 10.12.4.1)"; exit 1; }
echo "[OK] gateway $GW"
if openstack network show "$EXT_NET" -f value -c id >/dev/null 2>&1; then
echo "[SKIP] network $EXT_NET exists"
else
openstack network create --external --provider-network-type flat \
--provider-physical-network "$PHYSNET" "$EXT_NET" -f value -c id
openstack network set --tag role=provider "$EXT_NET"
echo "[OK] network $EXT_NET created + tagged"
fi
if openstack subnet show "$EXT_SUBNET" -f value -c id >/dev/null 2>&1; then
echo "[SKIP] subnet $EXT_SUBNET exists"
else
openstack subnet create --network "$EXT_NET" --subnet-range "$EXT_CIDR" \
--gateway "$GW" --no-dhcp --allocation-pool start="$FIP_START",end="$FIP_END" \
"$EXT_SUBNET" -f value -c id
openstack subnet set --tag role=provider --tag "netbox-iprange=${FIP_START}-${FIP_END}" "$EXT_SUBNET"
echo "[OK] subnet $EXT_SUBNET created + tagged"
fi
echo "=== CONFIRM ==="
openstack network show "$EXT_NET" -f json | jq -c '{name, external: ."router:external", type: ."provider:network_type", physnet: ."provider:physical_network", shared, tags}'
openstack subnet show "$EXT_SUBNET" -f json | jq -c '{name, cidr, gateway_ip, enable_dhcp, allocation_pools, tags}'
)
GATE: provider-ext external=true, type=flat, physnet=physnet1, shared=false; provider-ext-fip cidr=10.12.4.0/22, gateway 10.12.4.1, enable_dhcp=false, allocation_pools=[10.12.5.0-10.12.7.254].
provider-ext (external, flat/physnet1, not shared) + provider-ext-fip (full /22, FIP allocation pool, no-dhcp) present and tagged role=provider.phase-05 -- octavia enablement.