Skip to content

fix: prevent CNS duplicate-IP corruption by serializing managed IPAM and endpoint state - #4698

Open
Evan Baker (rbtr) wants to merge 1 commit into
fix/cns-endpoint-state-atomic-writesfrom
fix/cns-ipam-endpoint-transactions
Open

fix: prevent CNS duplicate-IP corruption by serializing managed IPAM and endpoint state#4698
Evan Baker (rbtr) wants to merge 1 commit into
fix/cns-endpoint-state-atomic-writesfrom
fix/cns-ipam-endpoint-transactions

Conversation

@rbtr

@rbtr Evan Baker (rbtr) commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

This is the fix for the duplicate-IP crashloop.

On master, a managed ADD spans two separate critical sections (assign the IP,
then write endpoint state) and a DEL spans two more (remove endpoint state, then
release the IP). CNI DEL can arrive before or during its ADD — containerd/Cilium
run DEL cleanup when the ADD times out — which allows this interleaving:

  1. DEL's removeEndpointState finds nothing (ADD has not written yet) — no-op.
  2. ADD assigns the IP in memory.
  3. ADD writes endpoint state container -> IP.
  4. DEL releases that IP back to Available in memory.

IPAM now says the IP is free while the endpoint statefile says it is owned. A
later pod legitimately takes the IP and writes a second endpoint record for it.
On restart endpointStateToPodInfoByIP sees two owners and CNS refuses to start
with duplicate IP detected in CNS initialization.

Fix

Hold the service lock across the whole of each managed ADD and DEL, so IPAM
ownership and endpoint persistence can never interleave. With that, both
orderings leave consistent state and the split brain is impossible.

  • Cancelled queued ADDs are rejected before they mutate anything.
  • If the endpoint-state write fails, roll back only IPs newly allocated by this
    call; an idempotently returned existing assignment is never released.
  • Lock-free *Untransacted internals are factored out for the combined
    transaction. The lock-taking wrappers that still have callers
    (releaseIPConfigs for the non-managed path, requestIPConfigsHelper for
    startup reconcile) are retained.
  • GetIPFamilyCount/getIPFamiliesMap now run inside the lock. They take no
    lock themselves, so there is no reentrancy, and this incidentally fixes an
    unsynchronized read of service.state that existed on master.

Tests

  • concurrent ADD/DEL ordering with a blocking store
  • endpoint-write failure rollback vs. existing-assignment preservation
  • multi-IP all-or-nothing persistence
  • cancelled queued ADD

Validation

  • go test -race -count=1 ./cns/restserver/...

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@rbtr
Evan Baker (rbtr) marked this pull request as ready for review August 13, 2026 21:55
@rbtr
Evan Baker (rbtr) requested a review from a team as a code owner August 13, 2026 21:55
@rbtr
Evan Baker (rbtr) requested review from Ashvin Deodhar (ashvindeodhar) and a lite review from Copilot August 13, 2026 21:55
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI 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.

Pull request overview

This PR tightens CNS IPAM correctness in managed endpoint-state mode by serializing endpoint state persistence with IP allocation/release under a single service lock, preventing ADD/DEL interleaving and improving rollback behavior when endpoint state persistence fails.

Changes:

  • Introduces locked “transactional” paths for IP allocation + endpoint-state update, with rollback only for newly allocated IPs on endpoint-state write failure.
  • Serializes DEL (endpoint-state removal + IP release) under the same lock to prevent ordering races.
  • Adds deterministic unit tests covering endpoint-store write failures, canceled requests, and ADD/DEL ordering.
Show a summary per file
File Description
cns/restserver/ipam.go Adds transactional, lock-held helpers for managed endpoint state and adjusts error/rollback behavior.
cns/restserver/ipam_test.go Updates existing endpoint-state tests to go through handlers and adds new tests for rollback, cancellation, and concurrency ordering.

Review details

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread cns/restserver/ipam.go
Comment on lines +119 to +125

service.Lock()
defer service.Unlock()

if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("ip config request canceled: %w", err)
}
Comment on lines +424 to +426
<-blockingStore.entered
require.False(t, svc.TryLock(), "ADD must hold the service lock while endpoint state is persisted")

@rbtr
Evan Baker (rbtr) force-pushed the fix/cns-ipam-endpoint-transactions branch from 253f8cd to ef29a39 Compare August 13, 2026 22:10
Hold the CNS service lock across each managed endpoint-state ADD and DEL so
IPAM ownership and endpoint persistence cannot interleave. Roll back only IPs
newly allocated by the failing ADD, preserving existing idempotent assignments.
Stop canceled queued ADDs before mutation.

Factor lock-free internal helpers for the combined transaction and remove the
obsolete exported/private wrappers that no longer have production callers.
Add deterministic coverage for write failures and concurrent ADD/DEL ordering.
@rbtr
Evan Baker (rbtr) force-pushed the fix/cns-ipam-endpoint-transactions branch from ef29a39 to 2386f7a Compare August 14, 2026 17:57
@rbtr Evan Baker (rbtr) changed the title fix: serialize managed CNS IPAM and endpoint state fix: prevent CNS duplicate-IP corruption by serializing managed IPAM and endpoint state Aug 14, 2026
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.

4 participants