Hello community,
I am experiencing a persistent issue with the Kea DHCP implementation on an OPNsense HA Cluster. When using the default configuration (Raw Sockets + Multi-threading), the Kea service seems to "hear double" on interfaces where CARP is active, leading to duplicated logs and, more critically, conflicting IP offers to the same client.
Environment Setup:
Version: OPNsense 25.7.11_9-amd64.
Setup: Two nodes in HA (Master: Physical / Backup: Virtual).
Networking: High Availability with CARP acting as gateways across multiple VLANs.
DHCP: Kea DHCP configured in HA (Hot-Standby).
The Problem:
When Kea is configured with the default Socket Type: Raw, the service seems to "double-process" incoming broadcast packets on interfaces that have both a physical IP and a CARP VIP.
Because Kea uses multi-threading by default (4 threads), two (or more) different threads capture the same DHCPDISCOVER or DHCPREQUEST at the exact same millisecond. This creates a race condition: each thread checks the lease database, sees an available IP, and sends a separate DHCPOFFER or DHCPACK. In some instances, they even offer different IPs to the same client for the same transaction.
Evidence (Logs):
Notice the different thread IDs (e.g., ...9808 and ...a008) processing the same Transaction ID (tid=0xcb0e85d2) at the exact same millisecond:
Troubleshooting already performed:
Network Mask Check: Validated that there are no subnet overlaps on CARP VIPs.
Socket Type Change: * When switching to Socket Type: UDP, the duplication stops and logs become clean. However, many clients (especially those initiating discovery from 0.0.0.0) fail to receive IPs in UDP mode.
Analysis:
Binding: sockstat -4 -l shows Kea binding to both the Physical IP (e.g., 10.x.x.2:67) and the CARP VIP (e.g., 10.x.x.1:67).
It appears that with Raw Sockets, the BPF (Berkeley Packet Filter) delivers the packet to all listening threads. Since both the Physical IP and the CARP VIP are on the same interface, Kea seems to be binding in a way that triggers this double processing.
Questions:
Persistent Thread Limit: Is there a way to limit Kea threads to 1 through the GUI or a tunable?
Deny Service Binding: I noticed the "Deny service binding" option in the CARP settings.
If I enable this for the CARP, would it prevent Kea from listening on the Virtual IP, thus solving the duplication while keeping Raw Sockets?
What are the side effects for other services like ntpd or unbound if they rely on the CARP to serve clients?
Best Practice: Is this a known limitation of Kea on FreeBSD when CARP is involved, and what is the recommended way to use Kea in an HA setup without duplicate processing?
Any insights would be greatly appreciated!
I am experiencing a persistent issue with the Kea DHCP implementation on an OPNsense HA Cluster. When using the default configuration (Raw Sockets + Multi-threading), the Kea service seems to "hear double" on interfaces where CARP is active, leading to duplicated logs and, more critically, conflicting IP offers to the same client.
Environment Setup:
Version: OPNsense 25.7.11_9-amd64.
Setup: Two nodes in HA (Master: Physical / Backup: Virtual).
Networking: High Availability with CARP acting as gateways across multiple VLANs.
DHCP: Kea DHCP configured in HA (Hot-Standby).
The Problem:
When Kea is configured with the default Socket Type: Raw, the service seems to "double-process" incoming broadcast packets on interfaces that have both a physical IP and a CARP VIP.
Because Kea uses multi-threading by default (4 threads), two (or more) different threads capture the same DHCPDISCOVER or DHCPREQUEST at the exact same millisecond. This creates a race condition: each thread checks the lease database, sees an available IP, and sends a separate DHCPOFFER or DHCPACK. In some instances, they even offer different IPs to the same client for the same transaction.
Evidence (Logs):
Notice the different thread IDs (e.g., ...9808 and ...a008) processing the same Transaction ID (tid=0xcb0e85d2) at the exact same millisecond:
Code Select
2026-04-29T08:46:41-03:00 kea-dhcp4 INFO [kea-dhcp4.packets.0x3fb7b6ac9808] DHCP4_PACKET_RECEIVED [hwtype=1 74:86:e2:xx:xx:43], cid=[01:74:86:e2:xx:xx:43], tid=0xcb0e85d2: DHCPREQUEST received from 0.0.0.0 to 255.255.255.255 on interface vlan031
2026-04-29T08:46:41-03:00 kea-dhcp4 INFO [kea-dhcp4.packets.0x3fb7b6aca008] DHCP4_PACKET_RECEIVED [hwtype=1 74:86:e2:xx:xx:43], cid=[01:74:86:e2:xx:xx:43], tid=0xcb0e85d2: DHCPREQUEST received from 0.0.0.0 to 255.255.255.255 on interface vlan031
2026-04-29T08:46:41-03:00 kea-dhcp4 INFO [kea-dhcp4.leases.0x3fb7b6ac9808] DHCP4_LEASE_OFFER [hwtype=1 74:86:e2:xx:xx:43], tid=0xcb0e85d2: lease 10.x.x.11 will be offered
2026-04-29T08:46:41-03:00 kea-dhcp4 INFO [kea-dhcp4.leases.0x3fb7b6aca008] DHCP4_LEASE_OFFER [hwtype=1 74:86:e2:xx:xx:43], tid=0xcb0e85d2: lease 10.x.x.10 will be offeredTroubleshooting already performed:
Network Mask Check: Validated that there are no subnet overlaps on CARP VIPs.
Socket Type Change: * When switching to Socket Type: UDP, the duplication stops and logs become clean. However, many clients (especially those initiating discovery from 0.0.0.0) fail to receive IPs in UDP mode.
Analysis:
Binding: sockstat -4 -l shows Kea binding to both the Physical IP (e.g., 10.x.x.2:67) and the CARP VIP (e.g., 10.x.x.1:67).
Code Select
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
0 kea-dhcp4 47445 18 udp4 10.x.x.2:67 *:*
0 kea-dhcp4 47445 20 udp4 10.x.x.1:67 *:*It appears that with Raw Sockets, the BPF (Berkeley Packet Filter) delivers the packet to all listening threads. Since both the Physical IP and the CARP VIP are on the same interface, Kea seems to be binding in a way that triggers this double processing.
Questions:
Persistent Thread Limit: Is there a way to limit Kea threads to 1 through the GUI or a tunable?
Deny Service Binding: I noticed the "Deny service binding" option in the CARP settings.
If I enable this for the CARP, would it prevent Kea from listening on the Virtual IP, thus solving the duplication while keeping Raw Sockets?
What are the side effects for other services like ntpd or unbound if they rely on the CARP to serve clients?
Best Practice: Is this a known limitation of Kea on FreeBSD when CARP is involved, and what is the recommended way to use Kea in an HA setup without duplicate processing?
Any insights would be greatly appreciated!
"