10-vlan40.network.j2 set IPv6AcceptRA=false on enp1s0.40, leaving the interface with only a link-local address. edge-1 was therefore unreachable over IPv6 on the service VLAN — the VLAN it exists on in order to inherit the NTP VIP after the Talos migration.
The concern behind it was real: a second default route from the VLAN 40 lease would make return traffic asymmetric across the two VLANs. But that only required suppressing the default route and DNS, not addressing itself. Disabling RAs wholesale traded away the primary address family to protect the legacy one.
Mirrors what UseRoutes=false / UseDNS=false already do for DHCPv4. Both options verified present in systemd 261 against man systemd.network (UseGateway= added in v250), not assumed.
Verified on edge-1 after applying
enp1s0.40 now holds fd40::8eec:4bff:fe43:cebc/64 and 2003:d6:9717:a702:8eec:4bff:fe43:cebc/64 alongside 10.2.40.153/24
exactly one IPv6 default route, still via enp1s0 (VLAN 30)
exactly one IPv4 default route, still via 10.2.30.1 on enp1s0
no DNS servers on the VLAN 40 link
chronyd and keepalived both still active; VIP unaffected
Auto-revert timer armed before the change and disarmed after, as with #315.
Separate, larger issue found while verifying — NOT fixed here
All four NTP servers bind only 0.0.0.0:123. There is no IPv6 listener anywhere in the cluster.
This predates edge-1 and is not caused by this PR or #315 — the three PVE nodes have served the LAN this way for months. So IPv6 clients have never received NTP from this infrastructure, and the VIP design (10.2.40.4, DHCP option 42, the VRRP instance) is IPv4-only end to end. After the Talos migration, IPv6 clients would have no NTP source at all.
Cause not determined. Ruled out so far: no -4 flag in either unit (DAEMON_OPTS="-F 1" on Debian, no options on Arch), net.ipv6.conf.all.disable_ipv6=0 on both. The chrony documentation states allow is access-control only and does not restrict address family, and does not document a default that would explain this. Needs proper investigation rather than a guess.
Worth tracking as its own issue — it is the missing half of the NTP migration.
Fixes a regression I introduced in #315.
## What was wrong
`10-vlan40.network.j2` set `IPv6AcceptRA=false` on `enp1s0.40`, leaving the interface with only a link-local address. edge-1 was therefore unreachable over IPv6 on the service VLAN — the VLAN it exists on in order to inherit the NTP VIP after the Talos migration.
The concern behind it was real: a second default route from the VLAN 40 lease would make return traffic asymmetric across the two VLANs. But that only required suppressing the default route and DNS, not addressing itself. Disabling RAs wholesale traded away the primary address family to protect the legacy one.
## Fix
```
[Network]
IPv6AcceptRA=true
[IPv6AcceptRA]
UseGateway=false
UseDNS=false
```
Mirrors what `UseRoutes=false` / `UseDNS=false` already do for DHCPv4. Both options verified present in systemd 261 against `man systemd.network` (`UseGateway=` added in v250), not assumed.
## Verified on edge-1 after applying
- `enp1s0.40` now holds `fd40::8eec:4bff:fe43:cebc/64` and `2003:d6:9717:a702:8eec:4bff:fe43:cebc/64` alongside `10.2.40.153/24`
- exactly **one** IPv6 default route, still via `enp1s0` (VLAN 30)
- exactly **one** IPv4 default route, still via `10.2.30.1` on `enp1s0`
- no DNS servers on the VLAN 40 link
- `chronyd` and `keepalived` both still active; VIP unaffected
Auto-revert timer armed before the change and disarmed after, as with #315.
## Separate, larger issue found while verifying — NOT fixed here
**All four NTP servers bind only `0.0.0.0:123`. There is no IPv6 listener anywhere in the cluster.**
```
jupiter UNCONN 0 0 0.0.0.0:123 0.0.0.0:*
saturn UNCONN 0 0 0.0.0.0:123 0.0.0.0:*
neptune UNCONN 0 0 0.0.0.0:123 0.0.0.0:*
edge-1 UNCONN 0 0 0.0.0.0:123 0.0.0.0:*
```
This predates edge-1 and is not caused by this PR or #315 — the three PVE nodes have served the LAN this way for months. So IPv6 clients have never received NTP from this infrastructure, and the VIP design (`10.2.40.4`, DHCP option 42, the VRRP instance) is IPv4-only end to end. After the Talos migration, IPv6 clients would have no NTP source at all.
Cause **not determined**. Ruled out so far: no `-4` flag in either unit (`DAEMON_OPTS="-F 1"` on Debian, no options on Arch), `net.ipv6.conf.all.disable_ipv6=0` on both. The chrony documentation states `allow` is access-control only and does not restrict address family, and does not document a default that would explain this. Needs proper investigation rather than a guess.
Worth tracking as its own issue — it is the missing half of the NTP migration.
The previous config set IPv6AcceptRA=false on enp1s0.40, which left the
interface with only a link-local address and made edge-1 unreachable over IPv6
on the service VLAN. IPv6 is the primary address family on this network, so
suppressing it to guard against a routing problem in the legacy family was the
wrong trade.
The concern that motivated it was real -- a second default route from the VLAN
40 lease would make return traffic asymmetric across the two VLANs -- but it
only required suppressing the default route and DNS, not addressing itself.
RAs are now accepted with [IPv6AcceptRA] UseGateway=false and UseDNS=false,
mirroring what UseRoutes=false and UseDNS=false already do for DHCPv4. Both
options verified present in systemd 261 (UseGateway added in v250).
Verified after applying to edge-1:
- enp1s0.40 now holds fd40::/64 and 2003:d6:9717:a702::/64 alongside
10.2.40.153/24
- exactly one IPv6 default route, still via enp1s0 (VLAN 30)
- exactly one IPv4 default route, still via 10.2.30.1 on enp1s0
- no DNS servers on the VLAN 40 link
- chronyd and keepalived unaffected
Separately discovered and NOT addressed here: all four NTP servers bind only
0.0.0.0:123, so the service has no IPv6 listener at all -- this predates edge-1
and affects jupiter, saturn and neptune equally. No -4 flag is set and IPv6 is
not disabled in the kernel; the cause is not yet determined.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Second commit added: IPv6 allow rule — this is the actual reason the infrastructure has never served IPv6 clients.
chrony's allow directive is per address family and the default is that no clients are allowed access. The chrony.conf documentation lists allow 0/0 and allow ::/0 as separate examples for exactly this reason. Every allow rule in this repo was IPv4, so all four servers bound 0.0.0.0:123 and opened no IPv6 socket at all.
Adding an IPv6 rule brings up [::]:123. Verified with a real NTP transaction, not just a listening socket — chronyd -Q from jupiter against edge-1's ULA:
server fd40::8eec:4bff:fe43:cebc iburst
-> System clock wrong by -0.000023 seconds
ULA only, deliberately. The GUA prefix is ISP-delegated and rotates. A hardcoded 2003:...::/56 rule silently stops matching at the next delegation change, and since the default is deny, a stale rule fails closed and locks clients out. Keeping both the allow rule and any future service address on ULA makes them independent of the ISP entirely. Per RFC 6724 source selection a client reaching a ULA destination sources from its own ULA, so ULA-only suffices provided clients target a ULA address.
Scoped to edge_host only. jupiter, saturn and neptune still need the same rule before IPv6 clients can be pointed anywhere — left for a follow-up so this proves out on one host first.
This changes the shape of the anycast question in the parent discussion: with a working IPv6 listener, a ULA anycast address is now viable and is rotation-proof by construction. Still unverified: DAD suppression mechanics for a shared address in systemd-networkd, and whether the UDM can advertise an NTP server to IPv6 clients (DHCPv6 option 56 or an RA option) — without that, no client learns the address regardless of how it is held.
Second commit added: **IPv6 `allow` rule** — this is the actual reason the infrastructure has never served IPv6 clients.
chrony's `allow` directive is per address family and **the default is that no clients are allowed access**. The chrony.conf documentation lists `allow 0/0` and `allow ::/0` as separate examples for exactly this reason. Every allow rule in this repo was IPv4, so all four servers bound `0.0.0.0:123` and opened no IPv6 socket at all.
Adding an IPv6 rule brings up `[::]:123`. Verified with a real NTP transaction, not just a listening socket — `chronyd -Q` from jupiter against edge-1's ULA:
```
server fd40::8eec:4bff:fe43:cebc iburst
-> System clock wrong by -0.000023 seconds
```
**ULA only, deliberately.** The GUA prefix is ISP-delegated and rotates. A hardcoded `2003:...::/56` rule silently stops matching at the next delegation change, and since the default is deny, a stale rule **fails closed** and locks clients out. Keeping both the allow rule and any future service address on ULA makes them independent of the ISP entirely. Per RFC 6724 source selection a client reaching a ULA destination sources from its own ULA, so ULA-only suffices provided clients target a ULA address.
**Scoped to `edge_host` only.** jupiter, saturn and neptune still need the same rule before IPv6 clients can be pointed anywhere — left for a follow-up so this proves out on one host first.
This changes the shape of the anycast question in the parent discussion: with a working IPv6 listener, a ULA anycast address is now viable and is rotation-proof by construction. Still unverified: DAD suppression mechanics for a shared address in systemd-networkd, and whether the UDM can advertise an NTP server to IPv6 clients (DHCPv6 option 56 or an RA option) — without that, no client learns the address regardless of how it is held.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes a regression I introduced in #315.
What was wrong
10-vlan40.network.j2setIPv6AcceptRA=falseonenp1s0.40, leaving the interface with only a link-local address. edge-1 was therefore unreachable over IPv6 on the service VLAN — the VLAN it exists on in order to inherit the NTP VIP after the Talos migration.The concern behind it was real: a second default route from the VLAN 40 lease would make return traffic asymmetric across the two VLANs. But that only required suppressing the default route and DNS, not addressing itself. Disabling RAs wholesale traded away the primary address family to protect the legacy one.
Fix
Mirrors what
UseRoutes=false/UseDNS=falsealready do for DHCPv4. Both options verified present in systemd 261 againstman systemd.network(UseGateway=added in v250), not assumed.Verified on edge-1 after applying
enp1s0.40now holdsfd40::8eec:4bff:fe43:cebc/64and2003:d6:9717:a702:8eec:4bff:fe43:cebc/64alongside10.2.40.153/24enp1s0(VLAN 30)10.2.30.1onenp1s0chronydandkeepalivedboth still active; VIP unaffectedAuto-revert timer armed before the change and disarmed after, as with #315.
Separate, larger issue found while verifying — NOT fixed here
All four NTP servers bind only
0.0.0.0:123. There is no IPv6 listener anywhere in the cluster.This predates edge-1 and is not caused by this PR or #315 — the three PVE nodes have served the LAN this way for months. So IPv6 clients have never received NTP from this infrastructure, and the VIP design (
10.2.40.4, DHCP option 42, the VRRP instance) is IPv4-only end to end. After the Talos migration, IPv6 clients would have no NTP source at all.Cause not determined. Ruled out so far: no
-4flag in either unit (DAEMON_OPTS="-F 1"on Debian, no options on Arch),net.ipv6.conf.all.disable_ipv6=0on both. The chrony documentation statesallowis access-control only and does not restrict address family, and does not document a default that would explain this. Needs proper investigation rather than a guess.Worth tracking as its own issue — it is the missing half of the NTP migration.
The previous config set IPv6AcceptRA=false on enp1s0.40, which left the interface with only a link-local address and made edge-1 unreachable over IPv6 on the service VLAN. IPv6 is the primary address family on this network, so suppressing it to guard against a routing problem in the legacy family was the wrong trade. The concern that motivated it was real -- a second default route from the VLAN 40 lease would make return traffic asymmetric across the two VLANs -- but it only required suppressing the default route and DNS, not addressing itself. RAs are now accepted with [IPv6AcceptRA] UseGateway=false and UseDNS=false, mirroring what UseRoutes=false and UseDNS=false already do for DHCPv4. Both options verified present in systemd 261 (UseGateway added in v250). Verified after applying to edge-1: - enp1s0.40 now holds fd40::/64 and 2003:d6:9717:a702::/64 alongside 10.2.40.153/24 - exactly one IPv6 default route, still via enp1s0 (VLAN 30) - exactly one IPv4 default route, still via 10.2.30.1 on enp1s0 - no DNS servers on the VLAN 40 link - chronyd and keepalived unaffected Separately discovered and NOT addressed here: all four NTP servers bind only 0.0.0.0:123, so the service has no IPv6 listener at all -- this predates edge-1 and affects jupiter, saturn and neptune equally. No -4 flag is set and IPv6 is not disabled in the kernel; the cause is not yet determined. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Second commit added: IPv6
allowrule — this is the actual reason the infrastructure has never served IPv6 clients.chrony's
allowdirective is per address family and the default is that no clients are allowed access. The chrony.conf documentation listsallow 0/0andallow ::/0as separate examples for exactly this reason. Every allow rule in this repo was IPv4, so all four servers bound0.0.0.0:123and opened no IPv6 socket at all.Adding an IPv6 rule brings up
[::]:123. Verified with a real NTP transaction, not just a listening socket —chronyd -Qfrom jupiter against edge-1's ULA:ULA only, deliberately. The GUA prefix is ISP-delegated and rotates. A hardcoded
2003:...::/56rule silently stops matching at the next delegation change, and since the default is deny, a stale rule fails closed and locks clients out. Keeping both the allow rule and any future service address on ULA makes them independent of the ISP entirely. Per RFC 6724 source selection a client reaching a ULA destination sources from its own ULA, so ULA-only suffices provided clients target a ULA address.Scoped to
edge_hostonly. jupiter, saturn and neptune still need the same rule before IPv6 clients can be pointed anywhere — left for a follow-up so this proves out on one host first.This changes the shape of the anycast question in the parent discussion: with a working IPv6 listener, a ULA anycast address is now viable and is rotation-proof by construction. Still unverified: DAD suppression mechanics for a shared address in systemd-networkd, and whether the UDM can advertise an NTP server to IPv6 clients (DHCPv6 option 56 or an RA option) — without that, no client learns the address regardless of how it is held.