This bug documents and fixes ipv6 for wan load balancing, and works correctly in my live cluster and in a test harness that I built with containerlab.
I authored part of the fix and a test harness. I instructed a coding assistant (in this case OpenAI Codex gpt-5.5 xhigh) to write a testing scenario and to complete the fix. Then I verified the fix.
Below is the LLM-authored summary of the issue and the testing URLs:
WAN load-balancing currently programs the IPv4 dataplane but does not program an equivalent IPv6 dataplane. In a dual-stack deployment, the same configured WAN load-balancing policy installs IPv4 nftables marks, IPv4 policy rules, and IPv4 per-interface default routes, but IPv6 traffic is not handled equivalently.
This should be treated as a bug in existing WAN load-balancing behavior, not as a new feature request. A dual-stack WAN setup should not silently have WLB/failover coverage for IPv4 only.
Version / Base
The proposed fix was rebased and tested against VyOS current:
- Repository: vyos/vyos-1x
- Branch: current
- Base commit: [1dd997d724449e941c6bf42be98529372d9f1530](https://github.com/vyos/vyos-1x/commit/1dd997d724449e941c6bf42be98529372d9f1530)
- Short commit: 1dd997d72
- Commit date: 2026-05-12T17:41:35+03:00
- Commit subject: frr: T8606: add watchfrr timeout option (#5165)
This base includes the merged T8481 fix:
- ab28ff732ca159438ef911cd91fd86ddd5000970 (https://github.com/vyos/vyos-1x/commit/ab28ff732ca159438ef911cd91fd86ddd5000970) wan: T8481: scope flush-connections to WLB connection marks
- PR: vyos/vyos-1x#5163 (https://github.com/vyos/vyos-1x/pull/5163)
Local tracking branch for the IPv6 fix:
- Branch: AppMana/forks-vyos-1x-fix-wlb:TXXXX-ipv6-wan-wlb (https://github.com/AppMana/forks-vyos-1x-fix-wlb/tree/TXXXX-ipv6-wan-wlb)
- Head commit: 734c6c6 (https://github.com/AppMana/forks-vyos-1x-fix-wlb/commit/734c6c6) wan: mark untracked IPv6 WLB packets
Observed Behavior
With WAN load-balancing configured on a dual-stack router:
- IPv4 gets table ip vyos_wanloadbalance.
- IPv4 gets fwmark policy routing rules.
- IPv4 gets per-interface WLB routing table default routes.
- IPv6 does not get an equivalent table ip6 vyos_wanloadbalance.
- IPv6 does not get equivalent ip -6 rule fwmark policy routing.
- IPv6 per-interface WLB routing tables are not populated/refreshed with IPv6 default routes.
- IPv6 failover/load-balancing behavior therefore diverges from IPv4 on the same WLB configuration.
In a dual-stack deployment, this means IPv4 can fail over through WLB while IPv6 does not have equivalent WLB dataplane state.
Expected Behavior
WAN load-balancing should program IPv6 dataplane state equivalent to the IPv4 dataplane when IPv6 routes and IPv6 traffic are present:
- Render an ip6 vyos_wanloadbalance nftables table.
- Render IPv6 WLB rules using ip6 saddr / ip6 daddr.
- Support IPv6 address groups and IPv6 network groups when rendering WLB rules.
- Install ip -6 rule fwmark lookups for each WLB routing table.
- Install/refresh IPv6 default routes in the per-interface WLB routing tables.
- Preserve existing IPv4 behavior.
If set load-balancing wan only-default-route from T8480 / PR #5119 is enabled, IPv6 should also install the equivalent suppress rule:
text ip -6 rule add fwmark <mark> table main suppress_prefixlength 0 priority <prio> ip -6 rule add fwmark <mark> table <wlb-table> priority <prio>
suppress_prefixlength 0 is correct for IPv6 as well as IPv4 because the IPv6 default route is ::/0. The rule checks the main table for specific routes and suppresses only the default route, so internal/connected/static/BGP routes are preferred before traffic falls through to WLB per-interface default tables.
Relationship To Existing Tasks
- T8481 (https://vyos.dev/T8481) / PR #5163 (https://github.com/vyos/vyos-1x/pull/5163) is merged and fixed flush-connections so only WLB-managed conntrack marks are deleted.
- T8480 (https://vyos.dev/T8480) / PR #5119 (https://github.com/vyos/vyos-1x/pull/5119) adds the opt-in only-default-route behavior for IPv4 WLB policy routing.
- This issue is the IPv6 parity bug for WLB. It should be stacked on T8480 if only-default-route is accepted, because IPv6 needs the same policy-routing behavior when that node is enabled.
The fix
This fix keeps IPv4 behavior intact and adds IPv6 parity:
- Add ip6 vyos_wanloadbalance rendering to data/templates/load-balancing/nftables-wlb.j2.
- Extend the WLB nft rule renderer to render either IPv4 or IPv6 address expressions and skip rules from the wrong address family.
- Render IPv6 firewall groups as @A6_... and @N6_....
- Add IPv6 default route discovery for each WLB interface.
- Install IPv6 default routes into the per-interface WLB routing tables.
- Restore missing IPv6 table defaults during WLB health polling, matching the existing IPv4 behavior.
- Install/delete ip -6 rule fwmark policy rules in the same lifecycle as IPv4.
- Mark IPv6 packets with ct state { new, untracked }, since forwarded IPv6 traffic can arrive as untracked in the relevant nft hook path and otherwise misses WLB marking.
Test Coverage
Smoketest coverage added/extended:
- Creates veth-backed WAN peers with IPv4 and IPv6 addresses.
- Adds IPv6 default routes for the simulated WAN interfaces.
- Verifies IPv4 WLB tables still contain expected default routes.
- Verifies IPv6 WLB tables contain expected default routes:
text ip -6 route show table 201 ip -6 route show table 202
- Verifies existing IPv4 policy rules.
- Verifies IPv6 policy rules:
text ip -6 rule show
- Verifies only-default-route installs IPv4 and IPv6 lookup main suppress_prefixlength 0 rules when enabled.
- Verifies those suppress rules are absent when only-default-route is not set.
VM-backed Containerlab test coverage, captured in AppMana/network-tests-vyos:
- Uses Containerlab with a VM-backed VyOS node and Linux LAN/WAN peer nodes.
- Builds a dual-stack topology:
- LAN: IPv4 198.51.100.0/24, IPv6 2001:db8:100::/64
- WAN1: IPv4 203.0.113.0/24, IPv6 2001:db8:201::/64
- WAN2: IPv4 192.0.2.0/24, IPv6 2001:db8:202::/64
- Configures WLB failover with WAN1 preferred and WAN2 backup.
- Verifies IPv4 and IPv6 active path through WAN1.
- Takes WAN1 down.
- Verifies WLB health state marks WAN1 down and WAN2 up.
- Verifies IPv4 and IPv6 fail over through WAN2.
- Verifies table ip vyos_wanloadbalance and table ip6 vyos_wanloadbalance both contain the expected active WAN jump.
- Verifies host default routes are unchanged before/after the lab so the test does not disturb workstation WAN networking.
Minimal Reproducer Shape
text set load-balancing wan hook /bin/true set load-balancing wan only-default-route set load-balancing wan interface-health <wan1> failure-count 2 set load-balancing wan interface-health <wan1> nexthop <wan1-ipv4-gw> set load-balancing wan interface-health <wan1> success-count 1 set load-balancing wan interface-health <wan2> failure-count 2 set load-balancing wan interface-health <wan2> nexthop <wan2-ipv4-gw> set load-balancing wan interface-health <wan2> success-count 1 set load-balancing wan rule 10 failover set load-balancing wan rule 10 inbound-interface <lan> set load-balancing wan rule 10 interface <wan1> weight 100 set load-balancing wan rule 10 interface <wan2> weight 1
The router also has IPv6 defaults learned or installed on both WAN interfaces. After commit, IPv4 WLB state exists, but without the fix the equivalent IPv6 WLB state is missing or incomplete.
Why This Is A Bug
The WLB configuration is interface/rule based and is not explicitly an IPv4-only mode in the user workflow. On dual-stack WANs, only programming IPv4 causes IPv6 traffic to behave differently from IPv4 under the same WLB policy. That breaks dual-stack failover expectations and makes IPv6 behavior incorrect for deployments that rely on WLB for WAN outage handling.
Containerlab Test Artifact URLs
The VM-backed Containerlab test report and evidence bundle were pushed to GitHub:
- Repository: AppMana/network-tests-vyos
- Commit: [077ea70ca91b5db2fdd6be1ff342238b7254ac54](https://github.com/AppMana/network-tests-vyos/commit/077ea70ca91b5db2fdd6be1ff342238b7254ac54)
- Scenario: scenarios/vyos-wlb-ipv6
- Topology: clab-vm.yml
- Diagram: diagrams/clab-vm.mermaid
- Test report: 2026-05-11 VM-backed dual-stack WLB failover report
- Captured logs: reports/logs/2026-05-11-vm-test-170935
- Durable release artifact: VyOS WLB IPv6 Containerlab Report 2026-05-11
- Release artifact archive: vyos-wlb-ipv6-containerlab-report-2026-05-11.tar.gz
- Release artifact checksum: vyos-wlb-ipv6-containerlab-report-2026-05-11.sha256
- GitHub Actions run: Upload Network Test Artifacts #25753677093
- GitHub Actions artifact: vyos-wlb-ipv6-containerlab-report