host-local: implement CNI v1.1 GC - #1289
Open
ravi-arnan wants to merge 1 commit into
Open
Conversation
ravi-arnan
force-pushed
the
feat/host-local-gc
branch
from
August 10, 2026 02:52
5502f8b to
108f1c6
Compare
Adds the GC verb to host-local, replacing the FIXME placeholder in main. The runtime hands GC the complete set of attachments it still considers live, and every reservation outside that set is released. That is how an allocation leaked by a DEL which never arrived gets reclaimed, which is the case the issue calls out. Three details the implementation has to get right, each covered by a test: The lock and the per-range last_reserved_ip markers live in the same directory as the reservations, so a GC that simply walked the data dir would delete them. Reservations written by older versions hold only a container ID with no ifname. ReleaseByID already falls back to matching those, and GC has to agree, otherwise the first GC after an upgrade would release every pre-upgrade allocation. An empty valid-attachments list means every reservation for this network is stale. It is not the same as having nothing to do. GC deliberately does not rewind last_reserved_ip, so a reclaimed address returns to service on wrap-around rather than being handed out next. That keeps allocation order unchanged for everyone else. Status is left as a separate change. Signed-off-by: Ravi Arnan <raviarnankeren@gmail.com>
ravi-arnan
force-pushed
the
feat/host-local-gc
branch
from
August 10, 2026 03:01
108f1c6 to
ab26d31
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1047.
Implements the GC verb for host-local, replacing the
/* FIXME GC */placeholder inmain.go. The runtime supplies the complete set of attachments it still considers live viacni.dev/valid-attachments, and every reservation outside that set is released. That reclaims an allocation leaked by a DEL which never arrived, which is the case the issue calls out.As far as I can tell this is the first GC implementation in this repo, so I have tried to keep the semantics conservative and to write down the reasoning where a later plugin will face the same question.
Three things the implementation has to get right
Each has a test, because each is a way to silently destroy live allocations rather than a way to fail loudly.
The data dir is not only reservations.
lockand the per-rangelast_reserved_ip.<rangeID>markers live alongside them, so a GC that just walked the directory would delete them.isReservationskips both, andlockFileNameis now a shared constant so the skip cannot drift from the nameNewFileLockactually uses.Reservations predating ifname hold only a container ID.
ReleaseByIDalready has a fallback for those, and GC has to agree with it. Without that, the first GC after an upgrade would release every pre-upgrade allocation on the host.An empty valid-attachments list is meaningful. It means every reservation for this network is stale, not that there is nothing to do. Treating absent as no-op would make GC quietly useless in exactly the situation it exists for.
One deliberate non-behaviour
GC does not rewind
last_reserved_ip. A reclaimed address therefore comes back into service on wrap-around rather than being the next one handed out. Rewinding would change allocation order for everyone in order to make reclamation look more immediate, which seemed like the wrong trade for a garbage collector. The address is genuinely free either way, and the disk-level test asserts that directly by reserving it again.I have called this out because it is the one thing where a reasonable reviewer might want the opposite, and it is a one-line change if you do.
Scope
GCis a method on*disk.Storerather than an addition to thebackend.Storeinterface, matching howcmdCheckalready reaches for the concrete store. Happy to move it onto the interface if you would rather every backend be required to implement it; that just means touching the fake store too. I asked on the issue and went with the smaller change in the meantime.Tests
plugins/ipam/host-local/backend/disk/gc_test.go, 7 specs at the store level: valid set honoured, ifname distinguishes two attachments of the same container, empty set releases everything, lock andlast_reserved_ipsurvive, legacy container-ID-only reservations are both kept when live and released when stale, and a reclaimed address is reservable again.plugins/ipam/host-local/host_local_test.go, 3 specs at the plugin level drivingcmdGCthrough a real config: a leaked attachment is released while a live one is kept, an empty list empties the store, and the store still serves allocations afterwards.go build ./...is clean andgo vet ./plugins/ipam/host-local/...is clean.Unrelated pre-existing failure, confirmed by stashing this branch and re-running on a clean
main:pkg/utils/sysctlfails without root because it writes under/proc/sys. Not touched by this change.