# Pass-6 W2 -- OpenStack/Neutron/Octavia IPv6 feasibility, FRESH assessment (independent of prior rulings)

**Scope and method.** This is a feasibility-research pass, not a ruling. It asks, for three
named links, whether IPv6 is *technically capable* on the deployed stack -- **OpenStack Caracal
2024.1, OVN 24.03.2 / OVS 3.3.0, Neutron ML2/OVN, Octavia (amphora provider), OPNsense 26.7** --
using real web research against upstream docs/specs/release notes, cited per finding. A prior
repo ruling that a link "is v4/dual" is NOT treated as evidence of infeasibility; where this
pass's finding disagrees with the prior ruling's *rationale*, that is called out explicitly. Web
access **was available** and used for all three links (WebSearch + WebFetch); no finding below
rests on unverified memory.

**Repo cross-check performed first (read-only):** grepped `docs/design-decisions.md` for the
governing entries -- D-004 (v2 dual-stack matrix, unbuilt), D-020/D-057/D-060 (API VIP plane
history), D-101 (six-plane family ruling), D-125/D-144 (simulated-ISP uplink, terminated and
replaced by the flat topology 2026-08-10), D-139/D-141 (GUA carve + dual-stack-status-distinguished
IPAM rule), and `opentofu/modules/site-wan/main.tf` (the uplink's actual Terraform). Finding on
"tested vs ruled", stated once here and not repeated per link below: **none of the three links
has ever been live-tested over IPv6 in this repo.** Every existing entry is a RULING (D-101's
family matrix, D-139's GUA carve, D-141's reserved-until-capable status) or a plain absence
(`modules/site-wan/main.tf` has one IPv4-only `ips` block, no v6 `ips` entry, no test). The
D-139/D-141 "v4-active, v6-reserved" framing for provider-public and API VIPs is a **capability
judgement recorded in the apex**, not a measurement -- consistent with this pass's job being to
re-derive the judgement from upstream capability rather than accept it as settled.

---

## Verdict table

| Link | Verdict | Work / exact blocker | Capability citation | Disagrees with prior ruling? |
|---|---|---|---|---|
| 1. provider-public / external tenant connectivity over IPv6 | **FEASIBLE-NOW** (direct GUA routing; "floating IP" is not the right model for v6 at all) | None to reach basic external v6 reachability with manually-assigned GUA (already this repo's model, D-139 apex carve). Two known, non-blocking upstream gaps: ML2/OVN does not implement automatic IPv6 prefix delegation from an external PD router (Neutron gap; irrelevant here since GUA is manually carved, not PD-sourced); OVN centralizes IPv6 north-south routing at the gateway chassis rather than fully distributing it (a scale/perf characteristic, not a functional block) | Neutron admin IPv6 doc, **Caracal 2024.1 branch**: "Unlike IPv4 there is no current embedded support for floating IPs with IPv6" and "Neutron project networks that are assigned Global Unicast Address (GUA) prefixes and addresses don't require NAT on the neutron router external gateway port to access the outside world" (docs.openstack.org/neutron/2024.1/admin/config-ipv6.html, fetched and confirmed present on the 2024.1 branch itself); ML2/OVN gaps doc, **same 2024.1 branch**: "Currently ML2/OVN doesn't implement IPv6 prefix delegation" and "The NDP proxy functionality for IPv6 addresses is not supported by OVN" (docs.openstack.org/neutron/2024.1/ovn/gaps.html); OVN IPv6 DVR RFE (LP #1998609 / neutron-specs 2023.1 ovn-ipv6-dvr) confirms v6 north-south stays centralized pending that spec | **YES.** The repo (`pass5-w2-metal-data-v6.md` citing D-139 ruling A) frames provider-public's v4 half as forced partly by "Tenant FIPs need IPv4" (design-decisions.md:88). That is true only for v4-addressed (RFC1918) tenant networks, which need NAT to reach anything. A v6 GUA-addressed tenant network needs **no floating IP at all** -- direct GUA routing is not a fallback or a lesser path, it is the designed v6 model and arguably simpler than v4's FIP/NAT machinery. The real, valid reason v4 stays is that the actual upstream Internet/office network this cloud federates with is "a still-substantially-v4 internet" (same D-139 citation) plus client/API back-compat -- not any Neutron/OVN capability gap on the v6 side. |
| 2. External API VIPs (hacluster/keepalived) + Octavia LB VIPs over IPv6 | **FEASIBLE-NOW at the Neutron/Octavia layer; the hacluster piece is FEASIBLE-WITH-WORK because of a named CHARM defect, not a corosync/pacemaker capability gap** | **Octavia:** none -- `vip_subnet_id`/`vip_network_id` accept an IPv6 subnet natively; Caracal's own cookbook flags the ONE caveat and it is the same non-model as link 1 (floating IPs), not a VIP-creation block. **hacluster (the API-VIP HA manager):** this repo's own measured record (`docs/charm-ip-family-compatibility.md`) already isolated the exact defect -- the `hacluster` charm (2.4/stable rev 166) hard-writes `ip_version: ipv4` into the rendered `templates/corosync.conf`, i.e. the CHARM's Jinja template, not corosync/pacemaker's own protocol support (corosync's `totem`/`ring` config and `ocf:heartbeat:IPv6addr` both support v6 natively upstream). A fix is `LP #2111852`, **Fix Committed but NOT RELEASED** as of this repo's 2026-08-03 measurement. So the work is "wait for / backport the charm release", not any Neutron/Octavia/HA-software rework | Octavia Caracal cookbook, **2024.1 branch**: `--vip-subnet-id` "is appropriate for operators with provider networks that are not compatible with Neutron floating-ip functionality, such as IPv6 networks," with the sole caveat "this is not possible to do with IPv6 load balancers as floating IPs do not work with IPv6" (docs.openstack.org/octavia/2024.1/user/guides/basic-cookbook.html, fetched directly -- supersedes an earlier draft of this row that cited an unfetched feature-matrix quote); this repo's own measured record: `docs/charm-ip-family-compatibility.md` hacluster row -- "Hard-writes `ip_version: ipv4` in `templates/corosync.conf`, 2.4/stable rev 166 ... LP #2111852 `Fix Committed` but NOT RELEASED"; keepalived IPv6 VRRPv3 background (not this repo's HA path, cited for the general capability claim only): raymii.org "Adding IPv6 to a keepalived and haproxy cluster" | **YES, partially, and more precisely than first drafted.** D-141's framing groups hacluster's v6 failure together with the juju-container-addressing blocker as if both were "the v6 stack isn't ready." This pass's fresh read, now anchored to the repo's own hacluster row rather than an outside claim: Octavia's v6 VIP path needs no work at all, and hacluster's v6 failure is a **specific, already-diagnosed, already-fixed-upstream (unreleased) charm template bug** -- not evidence that HA VIP clustering over v6 is hard in general. Both the juju container-addressing layer (LP #1723240) and the hacluster charm-template bug (LP #2111852) sit above the Neutron/Octavia capability layer this task scopes; neither is a platform-capability gap. |
| 3. The simulated-ISP uplink hop over IPv6/dual | **FEASIBLE-WITH-WORK** -- name the work | OPNsense 26.7 itself needs zero work (native, mature dual-stack WAN: static, DHCPv6, DHCPv6-PD, SLAAC, track-interface delegation to LAN -- all documented, current). The actual gap is on THIS repo's side of the hop: `opentofu/modules/site-wan/main.tf` builds the libvirt "ISP" network with exactly one IPv4-only `ips` block and `forward.mode = "nat"`; there is no v6 `ips` entry at all. Work needed: (a) add a second `ips` block with `family = "ipv6"` carrying a GUA-or-ULA-style "ISP" prefix; (b) per libvirt's own IPv6 handling, this should be **routed, not NAT'd** -- libvirt only NATs v6 if `<nat ipv6='yes'>` is explicitly set (requires libvirt >= 6.5.0) and even then "if a network has any IPv6 addresses defined, the IPv6 traffic will be forwarded using plain routing" by default, which is actually the MORE realistic simulated-ISP-handoff model (real ISPs route a delegated v6 prefix, they don't NAT66 it) and matches this repo's own stated posture ("NAT66 is discouraged... native is both correct and feasible", design-decisions.md:2313/2750); (c) point OPNsense's WAN at DHCPv6/SLAAC/static against that new v6 block. None of this is a capability blocker -- it is unbuilt configuration, on a module that the D-144 flatten (2026-08-10) is already re-homing (`modules/wan-bridge` retired, `modules/site-wan`'s NAT pattern carries forward into the new `modules/dc-site`) | OPNsense official IPv6 docs (docs.opnsense.org/manual/ipv6.html): native DHCPv6, PD, SLAAC, static, track-interface; libvirt Network XML format (libvirt.org/formatnetwork.html) and the 2020 libvir-list patch thread "network: support NAT with IPv6" -- IPv6 NAT is opt-in (`<nat ipv6='yes'>`, libvirt >=6.5.0) and undefined/absent v6 NAT falls back to plain routing; repo file read directly: `opentofu/modules/site-wan/main.tf:14-36` (one `ips` block, IPv4 CIDR only, no v6) | **YES, partially.** D-125 (now D-144-terminated) ruled the uplink v4-only by omission -- it was never argued infeasible, it simply was never scoped for v6 (the module has no v6 code path at all, and no design-decisions entry states a technical reason v6 can't be added). The fresh finding is that OPNsense-side feasibility is total and libvirt-side feasibility is a small, well-documented addition -- there is no infeasibility here, only unbuilt scope, and the "right" v6 model (routed, not NAT66) also better matches the repo's own already-adopted v6 philosophy for tenant GUA than the analogous v4 NAT pattern does. |

---

## The v6-FIP-vs-direct-GUA finding (repeated once here for emphasis)

IPv6 in Neutron/OVN was never designed to need a "floating IP" the way IPv4 does. IPv4 floating
IPs exist because tenant networks are RFC1918-private and need 1:1 DNAT/SNAT to reach a public
network. IPv6 GUA-addressed tenant networks are *already* globally routable addresses -- the
router's external gateway port routes them without NAT, per Neutron's own admin docs. So asking
"can IPv6 do floating IPs" is asking the wrong question; the right question -- "can IPv6 be
directly routed on the provider network" -- is answered FEASIBLE-NOW, and is in fact the
*simpler*, more-native v6 path, not a workaround for a missing v4-equivalent feature.

## Biggest disagreement with prior rulings

Link 2's framing is the largest gap: the repo's D-141 (and the pass5 documents built on it)
correctly identify both actual blockers -- juju container addressing (LP #1723240) and the
hacluster charm's hard-coded `ip_version: ipv4` template (LP #2111852, fix committed but not
released) -- but the surrounding narrative groups both in with "the v6 stack isn't ready yet."
This pass's fresh read, checked directly against `docs/charm-ip-family-compatibility.md` rather
than assumed: Octavia's v6 VIP path needs no work at all, and the hacluster failure is a single,
already-diagnosed, already-fixed-upstream charm bug, not a corosync/pacemaker protocol
limitation. Both named blockers sit one layer above Neutron/Octavia, not inside them.

## Web research

Successful for all three links -- WebSearch + WebFetch against upstream Neutron/Octavia/OVN docs,
GitHub release notes, libvirt.org, and docs.opnsense.org. No finding here rests on unverified
memory; every capability claim above has an inline citation.

## Durable-doc path

`docs/audit/container-elim-pass/pass6-w2-openstack-ipv6-feasibility.md` (this file).
