IP Address Management (IPAM)¶
IPAM owns pools and the address lifecycle: allocation, reservation, assignment, quarantine and release, with an append-only history trail.


Canonical addresses¶
Every comparison, import and duplicate check goes through a canonical address
value object: inet_pton-validated parse and IPv6 compressed to lowercase
canonical form. A unique (pool_id, address) index is the raw-string backstop;
application-layer uniqueness is canonical.
Pool types¶
allocation_type: subnet, range, routed_single or prefix_pool. Pools
carry:
start_address/end_address(range pools),allow_customer_extra_ips(whether secondaries may come from this pool),quarantine_seconds(release quarantine window;0recycles immediately),default_reverse_zoneandrdns_driver(manual|provider|none).
Subnet pools of /22 or smaller and range pools are pre-expanded
(network + broadcast + gateway skipped, idempotent). Larger subnets,
routed_single and prefix_pool pools create rows on demand. IPv6 pools are
never pre-generated.
Bulk import (admin)¶
previewBulkImport classifies every line without writing: valid,
duplicates (existing or repeated), outside the pool, invalid, reserved
(network/broadcast/gateway). The admin UI shows the buckets; the commit inserts
the valid set in one transaction, defensively skipping rows that raced in.
Allocation algorithms¶
- IPv4 — claim rows inside one transaction with row locks, conditional updates and the unique index as a hard guard.
- IPv6 — compose addresses from the pool CIDR and insert directly, retrying on unique violations. A membership guard skips any composition outside the pool CIDR.
- Prefix delegation (
prefix_pool) — walk child prefixes under a pool lock, recycle expired quarantines first, then insert with a canonical collision check and a unique index backstop.
Address lifecycle¶
status: free → reserved → assigned, with quarantined between release and
re-availability.
reserveSpecific— admin hold of a specific address.releaseWithHistory— the single release path; honors the pool's quarantine window and always writes history.quarantineSweep— returns expired quarantines tofree.promoteToPrimary— atomically demotes the old primary, flipsis_primaryand updates the instance's denormalized primary columns.
Concurrency guarantees¶
- Row locks serialize candidates per pool.
- Conditional updates with row-count assertions lose races safely.
UNIQUE(pool_id, address)is the hard guard.- Prefix allocation serializes on the pool row lock + canonical pre-check + unique index.
- Floating-IP transitions serialize on a per-address cache lock.
Audit¶
php artisan pterocloud:ipam:audit
php artisan pterocloud:ip:inspect <address>
pterocloud:ipam:audit checks the ledger invariants and exits 1 on findings.
Related¶
- Networking
- VPS networking
- Troubleshooting: networking
PC-IPAM-###in the error reference