Skip to content

deallocateIPAM cross-process deallocation is a no-op #156

Description

@privateip

Problem

deallocateIPAM creates a fresh PoolAllocator and calls Deallocate on it. Since each CNI invocation is a separate process, the allocations from cmdAdd are never visible to cmdDel. The Deallocate call is a no-op — subnets are never returned to the pool.

Partial fix applied (2026-06-30): CRD annotation tracking is now in place:

  • publishBGPState (cni.go:624-627) writes the allocated subnet to a BGPAdvertisement annotation during ADD.
  • getAllocatedSubnetFromCRD (cni.go:1111-1138) reads the annotation during DEL to know which subnet to deallocate.

What is still broken: The core architectural bug. deallocateIPAM (cni.go:1104) still creates a fresh PoolAllocator, and Deallocate (ipam.go:89) only removes from that in-memory sync.Map. The annotation tracking ensures the correct subnet CIDR is known at deallocation time, but the deallocation itself still operates on a blank slate.

Files: internal/cni/cni.go:1080-1108 (partial fix), ipam.go:27-33,89 (root cause)

Impact

On nodes with sustained pod churn, the in-memory pool will eventually exhaust, causing new pod attachments to fail with "pool exhausted" errors. This is a production stability risk on any node that sees more than ~2^32 / 2^32 = 1 pod churn cycle (i.e., practically any node with more than ~65K pods over its lifetime).

Recommended Fix

Persist allocations in the BGPAdvertisement CRD annotation/status and have deallocateIPAM mark them as released via a shared backend:

// Option A: CRD-based deallocation
func deallocateIPAM(ctx context.Context, k8sClient client.Client, vpcAttachmentID string, subnetCIDR string) error {
    // Read BGPAdvertisement CRD to find the annotation
    // Update the CRD annotation to mark the subnet as released
    // Alternatively, use a dedicated IPAM CRD for state
    return nil
}

// Option B: Shared singleton backed by a distributed store (e.g., etcd/Redis)
// Less ideal for a CNI plugin — adds external dependency

The simplest approach: during DEL, update the BGPAdvertisement CRD annotation to indicate the subnet is released, and maintain a separate "released" set that Allocate() checks before handing out subnets.

Acceptance Criteria

  • deallocateIPAM updates a persistent store (CRD annotation) to mark subnet as released
  • A subsequent cmdAdd on the same node can see released subnets and reuse them
  • Cross-process deallocation works: DEALLOCATE in one process is visible to ALLOCATE in another
  • Unit tests verify the deallocation → reallocation round-trip
  • deallocateIPAM is tested with a mock K8s client that simulates the CRD annotation flow

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions