Skip to content

feat(network): add --ipv4 to allow IPv6-only networks#5024

Open
mayur-tolexo wants to merge 1 commit into
containerd:mainfrom
mayur-tolexo:fix/network-ipv4-disable
Open

feat(network): add --ipv4 to allow IPv6-only networks#5024
mayur-tolexo wants to merge 1 commit into
containerd:mainfrom
mayur-tolexo:fix/network-ipv4-disable

Conversation

@mayur-tolexo

Copy link
Copy Markdown
Contributor

Part of #5012. Docker's network create has --ipv4 (on by default) so you can pass --ipv4=false with --ipv6 to get an IPv6-only network. nerdctl had no equivalent — generateIPAM always appends a default IPv4 range when no v4 subnet is given, so every bridge network ends up with IPv4.

This adds the flag. It's carried through as DisableIPv4 (the inverse) so the zero value keeps IPv4 enabled and nothing changes for existing callers, including the default bridge network. When IPv4 is disabled the default v4 range is skipped, the host-local default route becomes ::/0 instead of 0.0.0.0/0, and an IPv4 subnet is rejected. It requires --ipv6 and an explicit IPv6 subnet, and is rejected on Windows where IPv6-only isn't supported.

One difference from Docker worth calling out: with --ipv6 --ipv4=false and no subnet, Docker auto-assigns a ULA /64. nerdctl doesn't allocate IPv6 subnets anywhere today — even a plain --ipv6 without a subnet only gets the default IPv4 range — so this errors and asks for an explicit --subnet instead. Auto-allocating a ULA range is worth doing on its own since it would apply to the dual-stack case too.

Verified against Docker 29.4 locally: same addresses for an IPv6-only network, same rejection without --ipv6. Logs in a comment below.

@mayur-tolexo

Copy link
Copy Markdown
Contributor Author

Ran it side by side with Docker 29.4 to confirm the IPv6-only behaviour lines up. In both cases eth0 comes up with only an inet6 address (no inet), out of the subnet that was passed, and disabling IPv4 without --ipv6 is rejected.

Docker:

$ docker network create --ipv6 --ipv4=false --subnet fd00:dead::/64 v6demo
$ docker run --rm --net v6demo alpine ip -o addr show eth0
eth0    inet6 fd00:dead::2/64 scope global
eth0    inet6 fe80::eceb:f3ff:fe52:137c/64 scope link tentative

$ docker network create --ipv4=false noipv6
Error response from daemon: IPv4 or IPv6 must be enabled

nerdctl with this PR:

$ nerdctl network create --ipv6 --ipv4=false --subnet fd00:dead::/64 v6demo
$ nerdctl run --rm --net v6demo alpine ip -o addr show eth0
eth0    inet6 fd00:dead::2/64 scope global
eth0    inet6 fe80::4cf4:47ff:fecf:5beb/64 scope link

$ nerdctl network create --ipv4=false noipv6
--ipv4=false can only be used together with --ipv6

The host-local config nerdctl writes for the network is IPv6-only, with the v6 default route and no IPv4 range:

routes: [{"dst": "::/0"}]
ranges: [[{"gateway": "fd00:dead::1", "subnet": "fd00:dead::/64"}]]

And the other guard rails, matching what you'd expect:

$ nerdctl network create --ipv6 --ipv4=false noipsubnet
--ipv4=false requires an IPv6 subnet, specify --subnet manually

$ nerdctl network create --ipv6 --ipv4=false --subnet 10.9.0.0/16 v4subnet
--ipv4=false conflicts with an IPv4 subnet

@mayur-tolexo mayur-tolexo force-pushed the fix/network-ipv4-disable branch from 22e30f6 to 37b5347 Compare June 30, 2026 07:12
@mayur-tolexo mayur-tolexo marked this pull request as ready for review June 30, 2026 07:12
@AkihiroSuda AkihiroSuda added this to the v2.4.0 milestone Jun 30, 2026
Comment thread cmd/nerdctl/network/network_create.go Outdated
IPRange: ipRangeStr,
Labels: labels,
IPv6: ipv6,
DisableIPv4: !ipv4,

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.

lets not introduce it as DisableIPv4 lets introduce it as IPv4 matches the existing implementation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Had to set IPv4: true in createDefaultNetworkConfig too, else the default network's zero-value bool leaves IPv4 off.

Comment thread pkg/cmd/network/create.go Outdated
)

func Create(options types.NetworkCreateOptions, stdout io.Writer) error {
if options.DisableIPv4 {

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.

Then here check for mutual exclusion here with IPv4 and IPv6 flags

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moved it here and matched docker's IPv4 or IPv6 must be enabled.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds --ipv4 support to nerdctl network create to allow creating IPv6-only bridge networks (when combined with --ipv6 and an explicit IPv6 --subnet), by plumbing an IPv4 enable/disable signal through option parsing and IPAM generation.

Changes:

  • Introduces --ipv4 CLI flag (default true) and forwards it into NetworkCreateOptions.
  • Updates IPAM generation to skip the default IPv4 range when IPv4 is disabled, and to use an IPv6 default route (::/0) for IPv6-only networks.
  • Adds a Linux integration test validating IPv6-only networks created with --ipv6 --ipv4=false --subnet ….

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
pkg/netutil/netutil.go Passes IPv4 enablement into IPAM generation; sets IPv4: true for the default network config.
pkg/netutil/netutil_unix.go Implements IPv6-only behavior in host-local IPAM (route + default IPv4 range suppression + IPv4 subnet rejection).
pkg/netutil/netutil_windows.go Rejects --ipv4=false on Windows (IPv6-only not supported).
pkg/cmd/network/create.go Adds validation around address-family enablement and IPv6-only subnet requirements.
pkg/api/types/network_types.go Extends NetworkCreateOptions with a new IPv4 bool field.
cmd/nerdctl/network/network_create.go Adds --ipv4 flag and plumbs it into NetworkCreateOptions.
docs/command-reference.md Documents the new --ipv4 flag.
cmd/nerdctl/network/network_create_linux_test.go Adds coverage for IPv6-only network creation via --ipv4=false.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/api/types/network_types.go Outdated
Comment on lines +38 to +42
// IPv4 enables IPv4 on the network. It defaults to on; setting it false
// together with IPv6 yields an IPv6-only network. Callers constructing this
// struct directly must set it, since the zero value means IPv4 disabled.
IPv4 bool
Internal bool

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Keeping it as IPv4 to match the existing IPv6 field (and the ask above). Reworded the comment so it's clear the default-on lives on the CLI flag, and the zero value is false for anyone building the struct directly.

Comment thread pkg/cmd/network/create.go
Comment on lines +30 to +34
// At least one address family must be enabled, matching docker which
// rejects a network with both IPv4 and IPv6 turned off.
if !options.IPv4 && !options.IPv6 {
return fmt.Errorf("IPv4 or IPv6 must be enabled")
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Left as-is to match docker's exact string; it starts with the IPv4 initialism so ST1005 doesn't flag it.

Comment thread pkg/cmd/network/create.go
Comment on lines +35 to +40
if !options.IPv4 && len(options.Subnets) == 0 {
// IPv6-only needs a concrete IPv6 subnet: unlike docker, nerdctl does
// not auto-allocate one, and the empty-subnet default below would pick
// an IPv4 range, contradicting the disabled IPv4.
return fmt.Errorf("IPv6-only network requires an IPv6 subnet, specify --subnet manually")
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same — starts with IPv6, so the lowercase-error rule is fine with it.

cmd.Flags().StringArray("gateway", nil, "IPv4 or IPv6 Gateway for the master subnet")
cmd.Flags().String("ip-range", "", `Allocate container ip from a sub-range`)
cmd.Flags().StringArray("label", nil, "Set metadata for a network")
cmd.Flags().Bool("ipv4", true, "Enable IPv4 networking (set to false together with --ipv6 for an IPv6-only network)")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Put the Windows note in the command reference instead; the help strings here stay terse and don't spell out per-OS caveats.

Comment thread docs/command-reference.md Outdated
Docker's network create takes --ipv4 (default on) so that --ipv4=false
together with --ipv6 yields an IPv6-only network. nerdctl had no
equivalent: generateIPAM always appended a default IPv4 range when no v4
subnet was given, so every bridge network ended up with IPv4.

Add the flag and carry it as a positive IPv4 option, matching the
existing IPv6 field and docker's EnableIPv4. When IPv4 is off, skip the
default v4 range, switch the host-local default route to ::/0, and reject
an IPv4 subnet. Require at least one address family (docker's "IPv4 or
IPv6 must be enabled"), and require an explicit IPv6 subnet since nerdctl
does not auto-allocate one. Reject the combination on Windows where
IPv6-only is unsupported.

Part of containerd#5012.

Signed-off-by: Mayur Das <mayur.das@neevcloud.com>
@mayur-tolexo mayur-tolexo force-pushed the fix/network-ipv4-disable branch from e58fd43 to 8f8f16e Compare July 6, 2026 04:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants