Skip to content

feat: prefix-preserving dual-stack IPAM for pre-decided addresses - #438

Merged
scotwells merged 1 commit into
mainfrom
feat/static-dualstack-ipam
Aug 21, 2026
Merged

feat: prefix-preserving dual-stack IPAM for pre-decided addresses#438
scotwells merged 1 commit into
mainfrom
feat/static-dualstack-ipam

Conversation

@scotwells

@scotwells scotwells commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Datum's networking layer decides an interface's addresses before the workload is scheduled — an IPv6 endpoint block, optionally an IPv4 address, each with a prefix length that means something. Galactic's CNI cannot currently be told to use them.

static_ip takes a single IPv6 address, forces a /64 mask and allocates no IPv4, so an externally decided /96 comes out as a /64. The only alternative is the pool path, where galactic re-decides the address and the platform's allocation becomes fiction.

This adds an addresses path that carries pre-decided addresses exactly: any number, both families, prefix length preserved, gateway honoured.

{
  "type": "galactic-ipam",
  "addresses": [
    {"address": "fd00:10:ff01:0:1::1/96", "gateway": "fd00:10:ff01::1"},
    {"address": "172.20.1.7/32", "gateway": "172.20.1.1"}
  ]
}

It reuses ipam.addresses, which was already declared and documented as vestigial, rather than inventing a key. static_ip is unchanged as the legacy single-address path. Combining addresses with static_ip or a subnet is a config error rather than a precedence question.

Galactic stores nothing on this path

The marker files under the pool allocators exist because galactic has had to be its own IPAM authority: the file is the allocation, and losing it means double-allocating. That authority is what produces #156, #328 and #329.

Nothing is allocated here, so there is nothing to persist. ADD parses and returns, DEL has nothing to release, and CHECK passes — exactly what static_ip already does two lines away, for the same reason. galactic-ipam is a delegated plugin and on the tap path galactic never configures a guest address at all, so there is nothing on-node for it to verify either.

An earlier revision of this PR added a reservation store. Removing it keeps the new path out of #328's scope rather than extending it.

Related

This is the CNI-side mechanism #197 needs. That issue's problem is two systems each believing they know what is allocated; a plugin that can be handed a decided address, and honour it exactly, is what lets an external authority own the pool. Consumed by the VPC controller in datum-cloud/cloud#6, which renders these addresses into the NAD from what NSO allocated (datum-cloud/network-services-operator#164).

Two existing issues, and how the new path stands against them:

#156 is unchanged — this PR adds a path alongside the pool allocators rather than altering them.

🤖 Generated with Claude Code

@scotwells
scotwells requested a review from privateip August 21, 2026 01:17
@scotwells
scotwells marked this pull request as ready for review August 21, 2026 01:17
@scotwells
scotwells requested a review from a team as a code owner August 21, 2026 01:17
privateip
privateip previously approved these changes Aug 21, 2026
Adds an "addresses" IPAM path that assigns addresses decided outside
galactic-ipam exactly as given: both families, prefix length preserved, one
gateway per address. The static_ip path could only express a single IPv6
address, re-masked to /64 with no IPv4, and the pool path re-decides the
address the platform already allocated.

Reuses the standard CNI "addresses" key already declared on the IPAM struct.
Mode selection stays explicit: combining addresses with static_ip or a pool
CIDR is a config error. Nothing is allocated and nothing is persisted, so DEL
has nothing to release and CHECK nothing to verify — the same shape static_ip
already has.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@scotwells
scotwells merged commit 07f79ff into main Aug 21, 2026
11 checks passed
@scotwells
scotwells deleted the feat/static-dualstack-ipam branch August 21, 2026 01:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants