Skip to content

fix(cni): Cut galactic-cni eBPF map memory at startup - #841

Merged
privateip merged 3 commits into
mainfrom
fix/cni-service-map-memory
Oct 12, 2026
Merged

privateip merged 3 commits into
mainfrom
fix/cni-service-map-memory

Conversation

@privateip

@privateip privateip commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Upgrading a node from the last release makes the new CNI pod pay for about 59 MiB of new eBPF maps at start, close to the memory limit on the busiest production compute node.

Five of those maps are policy tables that only userspace writes, so they now allocate rows on demand instead of reserving their full size up front.

CI measured the maps at 35 MiB against the 128 MiB limit, and a full set of policy rows costs what it did before.

Nodes that already have these maps, which is only staging today, recreate them once at start while the router rebuilds their rows.

Test plan

  • CI is green, including the root unit tests that load the datapath and check its memory against the container limit
  • On staging, the CNI pod restarts cleanly and the router rebuilds private service routes after the maps are recreated
  • A staging private service keeps answering after the rollout

Related to #808

🤖 Generated with Claude Code

The private service route maps added about 52 MiB of eBPF maps, and the
kernel charges a map's memory to the memory cgroup of the process that
creates it. galactic-cni's credential-refresh container creates them, so a
node upgrading from v0.5.4, which has none of them pinned, charges the new
pod about 59 MiB of maps at start. Five of those maps are plain hashes
preallocated at max_entries, about 28 MiB, although production holds no
service policy at all. On the busiest production compute node that puts
the upgraded container at about 87% of its 128Mi limit.

service_route_table, service_access_table, service_deny_table,
service_remote_grant_table and attachment_identity_table are now
BPF_F_NO_PREALLOC. Only userspace writes them and the datapath only looks
rows up, so the per-packet path never allocates. An empty map costs only
its bucket array, about 3.5 MiB for the five, and the maps created at start
drop from about 59.6 MiB to about 35.3 MiB (the kernel's sizing formula
applied to the compiled spec, which reproduces the 59 MiB #808 measured).
Rows are still charged to galactic-cni's cgroup as they are written
(galactic-router writes the four policy maps, galactic-cni the identity
table), so a full set costs what it did before; a row that does not fit now
fails that write, which its writer retries, instead of the container's
start.

service_reverse_table keeps its preallocation: the datapath writes it, and
the kernel requires preallocation for an LRU hash. Resizing it is a
capacity decision left for later.

The flag change makes the five pinned maps incompatible on nodes that
already have them, which today means staging only. galactic-cni unpins and
recreates them at start, and galactic-router sees the new map IDs and
rebuilds its rows, the path the service route maps were built for.

Related to #808

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@privateip privateip self-assigned this Oct 12, 2026
The root unit test measured the uSID maps galactic-cni creates at
35 MiB, against a 128 MiB container limit. The comment on the policy
maps ran long and repeated the reasoning, so it now says only why
they are not preallocated and why the reverse table is. The README
states the measured size.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@privateip privateip changed the title fix(cni): Stop charging galactic-cni for empty service policy maps fix(cni): Cut galactic-cni eBPF map memory at startup Oct 12, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@privateip
privateip marked this pull request as ready for review October 12, 2026 11:15
@privateip
privateip requested a review from a team as a code owner October 12, 2026 11:15
@privateip
privateip enabled auto-merge October 12, 2026 11:15
@privateip

Copy link
Copy Markdown
Collaborator Author

Second-pass review of this PR is settled. pr-conventions-reviewer at 6a05012 returned VERDICT merge, with nits only. pr-rereviewer at 6a05012 confirmed all four first-pass findings fixed or settled, with only nits remaining.

The wrap-width nits were applied in d338b57, a formatting-only commit on top of the reviewed head. The squash nit was declined because it would need a force-push and the PR is merged as a single unit anyway.

CI is green on d338b57: Build, Lint, Unit Tests, Unit Tests (root), E2E Tests, and every image and kustomize bundle publish job passed.

Two warnings were carried knowingly. The two staging test-plan checks stay unchecked and run after merge, because staging tracks main. PR #835 also adds maps to the same datapath source, so it should land after this one and re-run the map memory test (TestUsid_MapMemoryFitsGalacticCNILimit) in its own CI.

Auto-merge is enabled with the merge method, the only one the main branch ruleset allows. The ruleset requires one approving review from a code owner and dismisses stale approvals on push, so this lands in front of a person.

@0xmc 0xmc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@privateip
privateip merged commit 9345305 into main Oct 12, 2026
15 checks passed
@privateip
privateip deleted the fix/cni-service-map-memory branch October 12, 2026 14:43
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