Introduces a higher-order topology that wraps two OPNSenseFirewall instances (primary + backup) and orchestrates score application across both. CARP VIPs get differentiated advskew values (primary=0, backup=configurable) while all other scores apply identically to both firewalls. Includes CarpVipScore, DhcpServer delegation, pair Score impls for all existing OPNsense scores, and opnsense_from_config() factory method. Also adds ROADMAP entries for generic firewall trait (10), delegation macro, integration tests, and named config instances (11). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2.8 KiB
Phase 10: Firewall Pair Topology & HA Firewall Automation
Goal
Provide first-class support for managing OPNsense (and future) HA firewall pairs through a higher-order topology, including CARP VIP orchestration, per-device config differentiation, and integration testing.
Current State
FirewallPairTopology is implemented as a concrete wrapper around two OPNSenseFirewall instances. It applies uniform scores to both firewalls and differentiates CARP VIP advskew (primary=0, backup=configurable). All existing OPNsense scores (Lagg, Vlan, Firewall Rules, DNAT, BINAT, Outbound NAT, DHCP) work with the pair topology. QC1 uses it for its NT firewall pair.
Tasks
10.1 Generic FirewallPair over a capability trait
Priority: MEDIUM Status: Not started
FirewallPairTopology is currently concrete over OPNSenseFirewall. This breaks extensibility — a pfSense or VyOS firewall pair would need a separate type. Introduce a FirewallAppliance capability trait that OPNSenseFirewall implements, and make FirewallPairTopology<T: FirewallAppliance> generic. The blanket-impl pattern from ADR-015 then gives automatic pair support for any appliance type.
Key challenge: the trait needs to expose enough for CarpVipScore to configure VIPs with per-device advskew, without leaking OPNsense-specific APIs.
10.2 Delegation macro for higher-order topologies
Priority: MEDIUM Status: Not started
The "delegate to both" pattern used by uniform pair scores is pure boilerplate. Every Score<FirewallPairTopology> impl for uniform scores follows the same structure: create the inner Score<OPNSenseFirewall> interpret, execute against primary, then backup.
Design a proc macro (e.g., #[derive(DelegatePair)] or delegate_score_to_pair!) that generates these impls automatically. This would also apply to DecentralizedTopology (delegate to all sites) and future higher-order topologies.
10.3 XMLRPC sync support
Priority: LOW Status: Not started
Add optional FirewallPairTopology::sync_from_primary() that triggers OPNsense XMLRPC config sync from primary to backup. Useful for settings that must be identical and don't need per-device differentiation. Not blocking — independent application to both firewalls achieves the same config state.
10.4 Integration test with CARP/LACP failover
Priority: LOW Status: Not started
Extend the existing OPNsense example deployment to create a firewall pair test fixture:
- Two OPNsense VMs in CARP configuration
- A third VM as a client verifying connectivity
- Automated failover testing: disconnect primary's virtual NIC, verify CARP failover to backup, reconnect, verify failback
- LACP failover: disconnect one LAGG member, verify traffic continues on remaining member
This builds on the KVM test harness from Phase 6.