Migrate from Microsoft, ISC, or Kea

No -All on Get-DhcpServerv4*. ClientId is hyphenated MAC. Bring scopes as prefixes, pools, and reservations.

Lattice does not parse dhcpd.conf, Microsoft XML, Kea JSON, or Infoblox CSV in-process. Same rule as NetBox: you dump, you map, you POST /api/v1. There is no “import leases and keep talking ISC failover.”

Microsoft DHCP is the primary buyer we wrote this for. Failover relationships and split scopes do not come with you. Relays (ip helper-address) stay on the L3 switch; you change the helper target. relays. Prefix vs scope: first-subnet. Linux/SSH: windows-admin.

This page is the playbook. Objects: 04-DATA-MODEL.md. API: 08-API.md. Cutover DNS: dns-how.

Just show me the steps — dump + POST at the bottom, without the mapping lecture.

Vendor documentation (cmdlet names and export UIs change between Windows Server releases). Use these for the latest dump steps; this page is the Lattice mapping.

TopicOfficial docs
Full server dumpExport-DhcpServer
Scopes / reservations / exclusions / leases / optionsGet-DhcpServerv4Scope · Get-DhcpServerv4Reservation · Get-DhcpServerv4ExclusionRange · Get-DhcpServerv4Lease · Get-DhcpServerv4OptionValue
Failover (do not import)DHCP failover
ISC dhcpd.confdhcpd.conf (ISC)
ISC KeaKea ARM

1. What you are actually moving

Their objectLattice objectImport?
Scope / subnetprefix (plan) + subnet (L3)Yes — create
Dynamic rangepoolYes — create
Exclusion / reserved-but-not-DHCPexcludeYes — gateway, VIP, junk statics
Reservation / host / fixed-address (DHCP client)reservation (IP + MAC or DUID)Yes — printers, phones
Static server / no DHCPassignment (IP + hostname)Yes — counts on the license cap
Server VLAN with no DHCPsubnet dhcp_enabled=falseYes — no pools
Scope option (router, DNS, NTP, domain)Subnet fields + dhcp_optionYes — map, do not paste dhcpd.conf snippets
PXE next-server / filenameSubnet next_server / boot_fileYes
Client class / vendor classclient_class + pool class_idMaybe — start simple
Live leaseslease rowsNo
Failover partner / split scope / ISC failoverThrow away. Shared Postgres is HA
Super-scope / shared-networkOne subnet per L3, or two subnets if you truly have two prefixes on the wireMap carefully
DDNS on the old serverSubnet ddns_* + a Lattice adapterRebuild; do not copy nsupdate cron

Do not import the lease database. Leases are reality this dhcpd granted. If you inject Microsoft/ISC lease rows, Lattice will defend IPs it never Acked, clocks will not match, and a Renew from a client the old server knew can still NAK.

How clients keep (or change) their IP is section 5.

NetBox is not a DHCP migration. netbox only creates missing prefixes. Pools, reservations, and leases stay Lattice’s.


2. Order of operations

  1. Install Lattice beside the old server. Relays still point at the old box. install-prerequisites.
  2. Recreate intent in Lattice: prefix → subnet → exclude gateway/VIP → pool → reservations → options. Dark: dhcpd may run but nothing relays to it yet.
  3. Match the license cap. Reservations count as managed IPs. 800 Microsoft reservations on community (1,000) leaves little room for dynamic leases.
  4. Pick one DNS mode per zone before cutover. dns-how. Option 6 on the subnet must be whatever the site resolver is (usually AD/Unbound), not lattice-dns, unless that zone is all clients query.
  5. Prove one VLAN: list the relay in Settings → trusted relays, then point one relay at Lattice (giaddr in that subnet). Or on the node: lattice-dhcptest -server 127.0.0.1:67 -giaddr <gateway>. Overview shows a lease. Same-VLAN broadcasts often miss Dockerized dhcpd.
  6. Lower old lease time (e.g. 1h) a day before, so Renews come soon after you switch. Leave the Lattice subnet at 1 day unless it is guest (DHCP lease time).
  7. Switch relays (or the VIP they already use) to Lattice. Confirm those relay IPs are in Settings → trusted relays. Disable new Offers on the old server (deactivate scopes) the same hour.
  8. Do not turn the old box into scrap until Renews have succeeded for a full old-lease period. Keep it for rollback: point relays back.

3. Mapping (any vendor)

Prefix vs subnet vs pool

Their “scope 10.20.20.0/24” is usually:

  • Prefix 10.20.20.0/24 (or a parent 10.20.0.0/16 you already use as the plan)
  • Subnet 10.20.20.0/24 with gateway = their router option
  • Pool startend = their dynamic range minus exclusions you will model as excludes/reservations

If they had a /16 scope with a small range, still make the subnet the L3 network (what giaddr sits in), not the range. Microsoft “start range .10” is a pool, not the subnet CIDR.

You can recreate the first VLAN entirely in the console (Addresses → subnet → pool) without curl. Use the API when you have hundreds of reservations — Excel → script, or a few dozen POST clicks is still normal. first-subnet.

Reservations

IP + MAC (DHCPv4) or DUID (v6). Hostname optional. At least one identity is required. Unique per subnet per IP and per MAC.

If the address is in an exclude, reservation create is rejected. Exclude the gateway; reserve the printer.

Options

Common old optionLattice
1 maskBuilt-in from subnet CIDR
3 routerSubnet gateway
6 DNSDHCP option code 6, {"addresses":["10.0.0.1"]}dns-how
15 domainOption 15, {"string":"office.example.com"}
42 NTPSubnet NTP servers (or option 42 JSON; stored option wins)
51 leaseSubnet lease_time_seconds
66/67 PXESubnet PXE next-server / boot file, not JSON
43 vendorOption 43 + vendor_class if needed

Classes

Match vendor_class, user_class, or mac_prefix. Attach to a pool to steer. Do not recreate every Microsoft vendor-class as a Lattice class on day one. Reservations cover the devices that must not move.


4. Vendor export

Use their tools. Then POST Lattice JSON. Idempotency-Key on creates if you re-run a script.

Microsoft DHCP (Windows Server)

Primary buyer we wrote the vision for. Failover relationships and split scopes do not come with you.

On the DHCP server (PowerShell as administrator). These cmdlets do not take -All. Reservation, exclusion, lease, and per-scope option cmdlets need a scope: pipe from Get-DhcpServerv4Scope (that object carries ScopeId). Confirm parameters on Microsoft Learn if your Server version differs.

Get-DhcpServerv4Scope | Export-Csv scopes.csv -NoTypeInformation
Get-DhcpServerv4Scope | Get-DhcpServerv4Reservation | Export-Csv reservations.csv -NoTypeInformation
Get-DhcpServerv4Scope | Get-DhcpServerv4ExclusionRange | Export-Csv exclusions.csv -NoTypeInformation
# Server-level options (no scope):
Get-DhcpServerv4OptionValue | Export-Csv options-server.csv -NoTypeInformation
# Per-scope options:
Get-DhcpServerv4Scope | Get-DhcpServerv4OptionValue | Export-Csv options-scope.csv -NoTypeInformation
# Optional: current bindings to *turn into reservations* (section 5)
Get-DhcpServerv4Scope | Get-DhcpServerv4Lease |
  Where-Object AddressState -eq 'Active' |
  Export-Csv leases.csv -NoTypeInformation

Export-DhcpServer -File C:\temp\dhcp.xml is a full dump (Microsoft Learn); still map by hand or script — Lattice will not ingest the XML. Add -Leases only if you want the lease table for section 5.

Columns you care about:

  • Scope: ScopeId, SubnetMask, Name, LeaseDuration
  • Reservation: IPAddress, ClientId (MAC), Name, Description
  • Exclusion: StartRange, EndRange
  • Option 3/6/15/42 at scope vs server level — server-level becomes every Lattice subnet unless you meant that

Microsoft ClientId for Windows clients is typically a hyphenated MAC (F0-DE-F1-7A-00-5E), not colon-separated. Normalize to lowercase aa:bb:cc:dd:ee:ff before POST. If ClientId is not a six-octet hardware address (custom identifiers exist), do not treat it as a Lattice MAC.

ISC dhcpd (dhcpd.conf)

There is no first-class parser. Read the conf:

subnet 10.20.20.0 netmask 255.255.255.0 {
  range 10.20.20.100 10.20.20.200;
  option routers 10.20.20.1;
  option domain-name-servers 10.0.0.1;
}
host printer {
  hardware ethernet aa:bb:cc:dd:ee:ff;
  fixed-address 10.20.20.10;
}

→ subnet + pool + gateway + option 6 + reservation.

allow/deny unknown-clients, pool { } allow lists, and shared-network need a human. dhcpd.leases is not an import file (section 5).

ISC Kea

kea-dhcp4.conf is JSON (subnet4, pools, reservations, option-data). Same mapping. kea-admin lease-dump is the same as Microsoft leases.csv — optional reservation seed, not a lease import.

dnsmasq

dhcp-range= → pool. dhcp-host=mac,ip,name → reservation. dhcp-option=6,… → option 6. Tiny configs: type them under Addresses.

Infoblox / BlueCat / EfficientIP

Export CSV or API (networks, DHCP ranges, fixed addresses, exclusion). Map to the same four objects. Do not expect Grid/BAM XML to load. Their HA/Anycast story is not ours; relays point at the Lattice VIP and health-check /readyz.

Cisco IOS / pfSense / OPNsense / libvirt

Same four objects. show ip dhcp binding / pfSense “leases” are lease dumps (section 5). pfSense/OPNsense are often ISC or Kea under the GUI — export the backend config if you can.


5. Cutover and IP stability

When a client Renews at Lattice with an IP Lattice never Acked, Lattice NAKs. The client Discovers. Lattice Offers from the pool (or a reservation). The client may get a different IP.

That is expected. Pick a strategy before you switch relays:

GoalWhat to do
IPs may changeImport pools + real reservations only. Shorten old lease time. Switch relays. Accept NAK→Discover.
Printers/servers keep IPsImport those as reservations. Dynamic laptops can move.
Almost everyone keeps current IPFrom the old lease dump, create Lattice reservations (MAC→IP) for active bindings that sit in the pool. After a week of clean Renews, delete reservations you want to become dynamic again. Counts against the license cap until you delete them.
Zero surprise on one VLANCut that relay first. Watch Overview + NAK logs.

Do not: copy dhcpd.leases into Postgres. Do not: run Microsoft and Lattice on the same UDP VIP. Do not: leave both offering on the same giaddr.

Rollback: relays back to the old server. Lattice leases stay in Postgres (harmless). Old server still has its own lease file — clients that already took a new Lattice IP will Renew to the old box and may NAK there too. Rollback is cleanest before many clients have rediscovered.


6. API sketch (after dump)

Admin token. Default tenant if you omit tenant_id. Idempotency-Key per create if the script is replay-safe.

# prefix (plan)
curl -s -X POST "$API/api/v1/prefixes" -H "authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  -d '{"cidr":"10.20.0.0/16","description":"from microsoft"}'

# subnet (use the prefix id)
curl -s -X POST "$API/api/v1/subnets" -H "authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  -d '{"prefix_id":"…","cidr":"10.20.20.0/24","gateway":"10.20.20.1","lease_time_seconds":3600}'

# exclude gateway
curl -s -X POST "$API/api/v1/subnets/$SUB/excludes" -H "authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  -d '{"start_ip":"10.20.20.1","end_ip":"10.20.20.1"}'

# pool
curl -s -X POST "$API/api/v1/subnets/$SUB/pools" -H "authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  -d '{"name":"dynamic","start_ip":"10.20.20.100","end_ip":"10.20.20.200"}'

# reservation
curl -s -X POST "$API/api/v1/subnets/$SUB/reservations" -H "authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  -d '{"ip":"10.20.20.10","mac":"aa:bb:cc:dd:ee:ff","hostname":"printer-01"}'

# option 6 (site resolver — usually AD, not lattice-dns)
curl -s -X POST "$API/api/v1/subnets/$SUB/options" -H "authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  -d '{"code":6,"payload":{"addresses":["10.0.0.1","10.0.0.2"]}}'

Conflicts (409) on overlap are the importer telling you the dump double-counted a range. 402 license_limit means too many reservations for this entitlement — delete optional MAC→IP seeds or raise the tier.

The console Addresses / subnet pages are the same objects. Spreadsheet → a few dozen curl POSTs is a normal first site. Thousands of reservations: script the CSV; do not paste XML into the UI.


7. DNS during migration

Old Microsoft/ISC DDNS into AD can keep running until you switch adapters.

  • Keep AD: set subnet ddns_adapter=ad_gsstsig (all tiers, including community), same forward/reverse zones, option 6 still the DCs. Worker GSS-TSIG replaces the old dhcpd nsupdate. Creating the dedicated user and keytab: ad-ddns.
  • Keep BIND: bind_tsig. Option 6 unchanged. Minting the TSIG key: bind-ddns.
  • Keep PowerDNS Auth: powerdns_http. Zones must already exist. powerdns.
  • Do not enable embedded on a zone the old server still updates. Split brain.

Map of adapters: integrations. Clients do not “find Lattice DNS” because you migrated DHCP. dns-how.


8. What success looks like

  • One test VLAN: Discover/Request/Ack on Lattice; unique IPs; Overview lease count moves.
  • Reservations: that MAC always gets that IP (lattice-dhcptest cannot steal it).
  • Relays: giaddr in the subnet; /readyz on dhcpd; LATTICE_TRUSTED_RELAYS set.
  • Old failover pair is off. One Lattice VIP (or single node).
  • Names: if DDNS is on, A/PTR appear via the outbox, not on Ack.
  • Rollback window elapsed; old DHCP role uninstalled.

If NAK storms after cutover: clients are Renewing IPs Lattice does not know — you skipped reservations for devices that must keep the address, or the pool does not include their old IP. Add reservations or widen the pool, do not “import the lease file.”

Just the steps

On the old Microsoft DHCP server (PowerShell as administrator). These cmdlets do not take -All. Confirm on Microsoft Learn.

Get-DhcpServerv4Scope | Export-Csv scopes.csv -NoTypeInformation
Get-DhcpServerv4Scope | Get-DhcpServerv4Reservation | Export-Csv reservations.csv -NoTypeInformation
Get-DhcpServerv4Scope | Get-DhcpServerv4ExclusionRange | Export-Csv exclusions.csv -NoTypeInformation
Get-DhcpServerv4OptionValue | Export-Csv options-server.csv -NoTypeInformation
Get-DhcpServerv4Scope | Get-DhcpServerv4OptionValue | Export-Csv options-scope.csv -NoTypeInformation
Get-DhcpServerv4Scope | Get-DhcpServerv4Lease |
  Where-Object AddressState -eq 'Active' |
  Export-Csv leases.csv -NoTypeInformation

Normalize reservation ClientId from F0-DE-F1-… to aa:bb:cc:dd:ee:ff. Then POST Lattice objects (prefix → subnet → exclude gateway → pool → reservations → option 6). Full curl bodies are in §6. Do not import the lease file as leases. Relays: one helper, trusted in Settings, then cut.