Summary
When service dhcp-server high-availability is configured, VyOS generates Kea
HA hook parameters in python/vyos/template.py (kea_high_availability_json)
as:
"heartbeat-delay": 10000, "max-response-delay": 10000, "max-ack-delay": 5000, "max-unacked-clients": 0
Kea's Administrator Reference Manual (HA hook / libdhcp_ha.so) documents:
- heartbeat-delay — default 10000 ms
- max-response-delay — default 60000 ms; duration since last successful partner communication after which communication is assumed interrupted. "This duration should be greater than the heartbeat-delay; typically it should be a multiple of heartbeat-delay."
- max-unacked-clients — default 10; special value 0 disables the client-based failure-detection mechanism and transitions to partner-down immediately when the control channel fails
- max-ack-delay — default 10000 ms (VyOS currently emits 5000; secondary)
With max-response-delay equal to heartbeat-delay, Kea opens a false-positive
window every heartbeat cycle: peer age reaches ~10s →
communication-interrupted=true for a fraction of a second while in-touch can
still be true and HA state stays load-balancing. That matches production
status-get polling and the ISC guidance that equal timers are incorrect.
max-unacked-clients: 0 additionally means any real communication-interrupted
condition skips unacked-client failure detection and can go partner-down
immediately (ARM: "disables the failure-detection mechanism").
Why it matters
- Healthy HA pairs log HA_COMMUNICATION_INTERRUPTED / CLIENT4 noise and briefly flip communication-interrupted on status-get even when the SYNC control channel and peer are fine.
- Monitoring that keys on communication-interrupted (or HA state) false-fires or goes "pending" without a real peer outage.
- Operators who trust stock generated Kea JSON are not getting Kea's documented defaults — they are getting a more aggressive / flaky timer set.
Reproduction
- Configure two routers with service dhcp-server high-availability (active-active / load-balancing or active-passive).
- Inspect /run/kea/kea-dhcp4.conf — observe equal 10000/10000 and max-unacked-clients 0.
- Poll status-get ~0.5s for 30–60s while healthy: remote.age cycles 0..10 remote.communication-interrupted becomes true when age hits 10 remote.in-touch often remains true; local state stays load-balancing
- Optional: patch max-response-delay to 60000, re-apply dhcp-server — age=10 no longer sets communication-interrupted.
Suggested fix
In kea_high_availability_json (python/vyos/template.py), align with Kea ARM
defaults:
'heartbeat-delay': 10000, # unchanged 'max-response-delay': 60000, # was 10000 'max-ack-delay': 5000, # optional: 10000 to match Kea default 'max-unacked-clients': 10, # was 0
Minimal change is max-response-delay + max-unacked-clients only.
Optional follow-up: expose the four timers under
service dhcp-server high-availability …
with those defaults, so sites can tune without patching template.py.
No CLI schema change is required for the minimal fix.
Environment
- VyOS 1.5 Circinus rolling
- Kea DHCP4 HA over a dedicated SYNC network (TCP :647)
- Confirmed on multiple HA pairs (load-balancing)
Workaround
Patch installed template.py kea_high_availability_json defaults, then re-run
conf_mode service_dhcp-server.py (or any dhcp-server re-apply). Does not
survive image upgrades until fixed upstream.
References
- Kea ARM — High Availability hook parameters (heartbeat-delay, max-response-delay, max-ack-delay, max-unacked-clients): https://kea.readthedocs.io/en/latest/arm/hooks.html (section libdhcp_ha.so / high availability parameters)
- Related but distinct: T8392 (peer name must be peer hostname; Closed, Wontfix). That task's attached kea-dhcp4.conf also showed the equal 10000/10000 timers as generated by VyOS; this task is only about timer defaults, not peer naming.