Skip to content

Allow Dualstack Networking (ENABLE_IPv6 AND ENABLE_IPv4)#3616

Open
DonavanFritz wants to merge 1 commit intoaws:masterfrom
DonavanFritz:dual-stack-same-eni
Open

Allow Dualstack Networking (ENABLE_IPv6 AND ENABLE_IPv4)#3616
DonavanFritz wants to merge 1 commit intoaws:masterfrom
DonavanFritz:dual-stack-same-eni

Conversation

@DonavanFritz
Copy link
Copy Markdown

@DonavanFritz DonavanFritz commented Mar 2, 2026

What type of PR is this?
feature

Which issue does this PR fix?:
#3615

What does this PR do / Why do we need it?:

Enables dual-stack pod networking by allowing ENABLE_IPv4=true and ENABLE_IPv6=true simultaneously. Both address families are assigned to pod eth0 from prefix-delegated addresses on the same ENI. No NAT/SNAT, no egress interfaces.

Currently the CNI rejects this combination in isConfigValid(). Pods must choose IPv4-only or IPv6-only, relying on NAT egress (v4if0/v6if0) for the other family. This change removes that restriction when ENABLE_PREFIX_DELEGATION=true.

Key behaviors:

  • IPv6 /80 and IPv4 /28 prefixes are allocated on the same ENI (primary first, secondary for overflow)
  • Both addresses assigned directly to pod eth0 — no egress interfaces created
  • No SNAT/CONNMARK iptables rules (upstream updateHostIptablesRules() returns nil when enableIPv6=true)
  • IPv4 warm pool manages prefix capacity; IPv6 is abundant (2^48 addresses per /80)
  • Secondary ENIs get source-based routing for both families via per-ENI route tables
  • Egress plugin is automatically disabled in dual-stack mode regardless of ENABLE_V4_EGRESS/ENABLE_V6_EGRESS values
  • Single-stack behavior is completely unchanged

Testing done on this change:
Deployed to a dev EKS cluster (5 nodes, v1.21.0 base).

Sample pod verification:
$ ip addr show eth0
inet 100.89.89.128/32 scope global eth0
inet6 2a03:5640:f13c:1:7a::4/128 scope global

$ ip link show v4if0
Device "v4if0" does not exist.

$ ip link show v6if0
Device "v6if0" does not exist.

IPAMD logs confirm: "Dual-stack mode: IPv6 + IPv4 prefixes on same ENI (primary first)"
Entrypoint logs confirm: "Dual-stack mode: egress plugin disabled (both IPv4 and IPv6 on eth0)"

Will this PR introduce any new dependencies?:
No. No new APIs, IMDS calls, kernel modules, or binary dependencies. Uses existing EC2 prefix delegation APIs already called in single-stack modes.

Will this break upgrades or downgrades? Has updating a running cluster been tested?:
No. Dual-stack only activates when all three flags are explicitly true (ENABLE_IPv4, ENABLE_IPv6, ENABLE_PREFIX_DELEGATION). Existing single-stack configurations are unchanged. Tested upgrade from single-stack to dual-stack via kubectl set env on a running cluster — pods created after the rollout get dual-stack, existing pods continue working until recycled.

Does this change require updates to the CNI daemonset config files to work?:
Yes — set ENABLE_IPv6=true on a cluster already running with ENABLE_IPv4=true and ENABLE_PREFIX_DELEGATION=true. Works with kubectl set env daemonset/aws-node -n kube-system ENABLE_IPv6=true. No other config changes required.

Does this PR introduce any user-facing change?:

Add dual-stack support for IPAMD pods. Setting ENABLE_IPv4=true, ENABLE_IPv6=true, and ENABLE_PREFIX_DELEGATION=true simultaneously now assigns both IPv4 and IPv6 addresses to pod eth0 from prefix-delegated addresses on the same ENI. No NAT/SNAT
 is applied. The egress plugin (v4if0/v6if0) is automatically disabled in dual-stack mode. Single-stack behavior is unchanged.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Allow ENABLE_IPv4=true and ENABLE_IPv6=true simultaneously for IPAMD pods.
Both address families on the same ENI (primary first, secondary for overflow).
No branch ENI changes, no NAT/SNAT.

Changes:
- ipamd.go: enableDualStack derived field, isConfigValid() lifts mutual
  exclusivity, setupENI() uses IPv4 primary in dual-stack and adds trunk
  ENI guard, warm pool runs for dual-stack, configureIPRulesForPods()
  fixes mask selection and adds IPv6 loop
- rpc_handler.go: AddNetwork/DelNetwork dual-stack paths with
  family-qualified IPAM keys (/v4, /v6), rollback on partial failure
- data_store.go: AssignPodIPv6AddressFromENI (same-ENI allocation),
  AllocatedIPv6s (restart reconciliation)
- cni.go: IPAMD add/del paths populate IPv6Address in veth metadata
- driver.go: SetupPodNetwork/TeardownPodNetwork handle IPv6,
  addSecondaryIPToContainer with DAD disable and fe80::1 gateway
- network.go: AddIPv6DefaultRouteToENITable for secondary ENI IPv6
  routing (separate method to avoid breaking NetworkAPIs interface)
- aws-vpc-cni/main.go: disable egress plugin in dual-stack mode
  (prevents v4if0/v6if0 when both ENABLE_IPv4 and ENABLE_IPv6 are true)

Incorporates trunk ENI fix (!isTrunkENI guard in setupENI to prevent
panic on trunk ENIs with no primary IP).
@DonavanFritz DonavanFritz requested a review from a team as a code owner March 2, 2026 22:58
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.

1 participant