Part of netork#85. Reservations were the only DHCP desired state the mixin
knew about; this adds the layer above them — the ranges a device serves and
the options it publishes with them.
The identity is the CIDR, matched rather than compared, the way `mac` is for
a reservation. normalize_cidr deliberately does not rewrite the network
address: turning 10.10.20.5/24 into 10.10.20.0/24 would make a typo silently
match a real subnet and then apply that caller's pools and options to it.
option_data is compared per option, and only over the options the caller
named. An absent key means "not managed", not "should be empty" — without
that rule a caller managing only domain_search would diff against every
option the server autocollects (routers, domain_name_servers, ntp_servers)
and reconfigure the DHCP daemon on every single run.
Neither diff deletes. For subnets that is not merely conservative: removing
one takes DHCP down for a whole VLAN, and the diff cannot tell "no longer
wanted" from "was never this caller's to describe".
commit_dhcp_subnets is separate from commit_dhcp_reservations even where a
driver implements both with the same call — the two desired-state sets are
applied independently, and a caller that changed only subnets should not
have to know which reload the vendor happens to share.
19 new tests against an in-memory fake; no vendor driver needed.