Adds the generic half of DHCP reservation management: diff_dhcp_reservations
matches desired against live reservations by normalised MAC, and
apply_dhcp_reservationset walks the diff and commits once at the end.
Both are concrete here because neither is vendor-specific — only
get_dhcp_reservations/apply_dhcp_reservation/commit_dhcp_reservations touch
the device (Kea REST on OPNsense, dnsmasq/odhcpd UCI on OpenWrt).
Two deliberate choices:
- The MAC is the matching key, not a description as with firewall rules. A
reservation has a natural identity and this is it. That also means a host
moving to another VLAN is an update of the existing entry rather than a
second one for the same MAC.
- An empty diff skips the commit. Committing reloads the DHCP daemon and
drops in-flight requests, which is too high a price for a no-op run. This
differs from apply_firewall_ruleset, which always commits.
Live reservations with no desired counterpart are never reported for
deletion — a DHCP server routinely carries hand-created entries the caller's
desired set was never meant to describe.
Mixed into FirewallDriver and ResidentialGatewayDriver: both device types
commonly run the DHCP server for their networks.