This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Whereabouts is an IP Address Management (IPAM) CNI plugin for Kubernetes that assigns IP addresses cluster-wide. Unlike host-local which only works per-node, Whereabouts provides cluster-wide IP assignment by tracking allocations in either Kubernetes Custom Resources (CRDs) or etcd.
The plugin assigns IPs from a specified range (CIDR notation), always allocating the lowest available address. It supports both IPv4 and IPv6, and is commonly used with Multus CNI for multi-network configurations.
# Build the CNI plugin binary
./hack/build-go.sh
# Build Docker image
make docker-build
# or with custom registry/tag:
IMAGE_REGISTRY=myregistry IMAGE_TAG=v1.0 make docker-build# Run unit tests (builds, installs tools, runs tests with coverage)
make test
# Run unit tests without static check (faster for iteration)
make test-skip-static
# Run unit tests for a single package
go test -v ./pkg/allocate/
# Run unit tests without cache (force re-run)
go test -count=1 -v ./pkg/storage/
# Run e2e tests locally
# 1. Install godotenv: go install github.com/joho/godotenv/cmd/godotenv@latest
# 2. Create kind cluster: make kind
# 3. Create e2e/.env with: KUBECONFIG=$HOME/.kube/config
# 4. Run tests from e2e directory:
cd e2e && godotenv -f .env go test -v . -timeout=1h# Verify generated code is up to date
./hack/verify-codegen.sh
# Update generated code (clientsets, informers, listers)
./hack/update-codegen.sh
# Regenerate API code and clean up artifacts
make generate-api# Update Go dependencies
make update-deps
# This runs: go mod tidy && go mod vendor && go mod verify# Create a kind cluster with whereabouts installed (default: 2 worker nodes)
make kind
# Create with specific number of worker nodes
make kind COMPUTE_NODES=3CNI Plugin Entry Point (cmd/whereabouts.go)
- Implements the CNI specification interface (ADD, DEL, CHECK, VERSION commands)
cmdAddFunc: Allocates an IP address when a pod interface is createdcmdDelFunc: Releases an IP address when a pod interface is deleted- Loads IPAM configuration from stdin and creates a Kubernetes IPAM client
IP Allocation Logic (pkg/allocate/)
AssignIP: Main allocation function that assigns IPs from a range- Iterates through the IP range to find the lowest available IP
- Checks for existing allocations by podRef and ifName (idempotent behavior)
- Respects exclude ranges and avoids IPs ending in
.0
Storage Backend (pkg/storage/)
- Abstract interface for IP pool management (currently Kubernetes CRDs primary, etcd legacy)
Storeinterface: GetIPPool, GetOverlappingRangeStore, Status, CloseIPPoolinterface: Allocations, Update- Kubernetes implementation in
pkg/storage/kubernetes/handles:- IPPool CRDs for tracking allocations per IP range
- OverlappingRangeIPReservation CRDs for cross-range IP uniqueness
- Retry logic with exponential backoff for concurrent updates
Configuration (pkg/config/)
- Parses CNI configuration from JSON
- Supports both inline config and flat-file configuration (
/etc/cni/net.d/whereabouts.d/whereabouts.conf) - Handles range specifications: single CIDR, range with start/end, ipRanges for multi-IP/dual-stack
IP Reconciler (pkg/reconciler/)
- Runs as a Kubernetes CronJob to clean up stranded IP allocations
- Compares allocated IPs against running pods
- Deallocates IPs for pods that no longer exist (handles node failures, force deletes)
- Reconciler cron expression configurable via ConfigMap or environment variable
Controllers
- IP Reconciliation Controller (
cmd/controlloop/): Watches pods and reconciles IP allocations - Node Slice Controller (
cmd/nodeslicecontroller/): Experimental "Fast IPAM" feature that pre-allocates IP slices per node to reduce contention
IPPool (pkg/api/whereabouts.cni.cncf.io/v1alpha1/ippool_types.go)
- Stores IP allocations for a specific range
- Key format:
<namespace>-<network-name>-<normalized-range> - Contains array of IPReservation entries with IP, PodRef, ContainerID, IfName
OverlappingRangeIPReservation (pkg/api/whereabouts.cni.cncf.io/v1alpha1/overlappingrangeipreservation_types.go)
- Ensures IP uniqueness across overlapping ranges when
enable_overlapping_ranges: true - Prevents same IP from being allocated in different ranges that overlap
NodeSlicePool (pkg/api/whereabouts.cni.cncf.io/v1alpha1/nodeslicepool_types.go)
- Experimental: Tracks node-specific IP slice allocations for Fast IPAM
- Enabled by setting
node_slice_sizein IPAM config
-
IP Allocation (ADD command):
- Load IPAM config from CNI stdin
- Create Kubernetes IPAM client with pod context
- Get or create IPPool CR for the range
- Check if podRef+ifName already allocated (idempotent)
- Find lowest available IP using
IterateForAssignment - Update IPPool CR with new reservation (with retries for conflicts)
- Handle overlapping range checks if enabled
- Return allocated IP to CNI runtime
-
IP Deallocation (DEL command):
- Load IPAM config
- Get IPPool CR
- Remove reservation matching containerID+ifName
- Update IPPool CR
- Clean up overlapping range reservation if present
-
Conflict Resolution:
- Uses optimistic locking with Kubernetes resource versions
- Retries up to DatastoreRetries (100) times on conflict
- Exponential backoff between retries
pkg/allocate: IP assignment algorithms, iteration logicpkg/iphelpers: IP address arithmetic, range calculations, CIDR parsingpkg/storage/kubernetes: Kubernetes CRD-based storage implementationpkg/types: Core data structures (RangeConfiguration, IPReservation, IPAMConfig)pkg/config: Configuration parsing and validationpkg/reconciler: Cleanup and reconciliation logicpkg/controlloop: Kubernetes controllers (pod watcher, node slice management)pkg/generated: Auto-generated Kubernetes clientsets, informers, listers
Unit Tests: Ginkgo/Gomega framework used extensively
- Test files colocated with implementation:
*_test.go - Use fake Kubernetes clients for testing without cluster
- Run with
make testwhich includesgo vetandstaticcheck
E2E Tests: Located in e2e/ directory
- Requires a running Kubernetes cluster (create with
make kind) - Tests actual CNI plugin behavior with pods
- Tests in
e2e/e2e_test.goande2e/e2e_node_slice/for Fast IPAM - Pool consistency tests in
e2e/poolconsistency/
Test Utilities:
e2e/client/: Kubernetes client wrappers for test operationse2e/entities/: Test entity generators (pods, deployments, etc.)e2e/testenvironment/: Test environment configuration
- Enabled by adding
node_slice_sizefield to IPAM config - Requires running the node slice controller:
doc/crds/node-slice-controller.yaml - Controller and daemonset must run in same namespace as NetworkAttachmentDefinitions
- Pre-allocates IP slices per node to reduce allocation contention in large clusters
Whereabouts merges configuration from multiple sources (priority: high to low):
- Inline IPAM configuration in NetworkAttachmentDefinition
- CNI config file parameters
- Flat file configuration at
configuration_pathor default locations
The plugin checks for existing allocations by podRef and ifName before allocating. This ensures that re-running ADD for the same pod interface returns the same IP, which is critical for CNI plugin reliability.
- Default and recommended: Kubernetes CRDs (no additional infrastructure)
- Legacy: etcd (deprecated, requires separate etcd cluster)
- Overlapping range protection only works with Kubernetes backend
Use network_name parameter to allow multiple independent allocations from the same CIDR in multi-tenant scenarios. This creates separate IPPool CRs per network name.