feat(network): add --ipv4 to allow IPv6-only networks#5024
Conversation
|
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 Docker: nerdctl with this PR: The host-local config nerdctl writes for the network is IPv6-only, with the v6 default route and no IPv4 range: And the other guard rails, matching what you'd expect: |
22e30f6 to
37b5347
Compare
| IPRange: ipRangeStr, | ||
| Labels: labels, | ||
| IPv6: ipv6, | ||
| DisableIPv4: !ipv4, |
There was a problem hiding this comment.
lets not introduce it as DisableIPv4 lets introduce it as IPv4 matches the existing implementation
There was a problem hiding this comment.
Done. Had to set IPv4: true in createDefaultNetworkConfig too, else the default network's zero-value bool leaves IPv4 off.
| ) | ||
|
|
||
| func Create(options types.NetworkCreateOptions, stdout io.Writer) error { | ||
| if options.DisableIPv4 { |
There was a problem hiding this comment.
Then here check for mutual exclusion here with IPv4 and IPv6 flags
There was a problem hiding this comment.
Moved it here and matched docker's IPv4 or IPv6 must be enabled.
37b5347 to
e58fd43
Compare
There was a problem hiding this comment.
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
--ipv4CLI flag (defaulttrue) and forwards it intoNetworkCreateOptions. - 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.
| // 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 |
There was a problem hiding this comment.
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.
| // 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") | ||
| } |
There was a problem hiding this comment.
Left as-is to match docker's exact string; it starts with the IPv4 initialism so ST1005 doesn't flag it.
| 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") | ||
| } |
There was a problem hiding this comment.
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)") |
There was a problem hiding this comment.
Put the Windows note in the command reference instead; the help strings here stay terse and don't spell out per-OS caveats.
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>
e58fd43 to
8f8f16e
Compare
Part of #5012. Docker's
network createhas--ipv4(on by default) so you can pass--ipv4=falsewith--ipv6to get an IPv6-only network. nerdctl had no equivalent —generateIPAMalways 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::/0instead of0.0.0.0/0, and an IPv4 subnet is rejected. It requires--ipv6and 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=falseand no subnet, Docker auto-assigns a ULA /64. nerdctl doesn't allocate IPv6 subnets anywhere today — even a plain--ipv6without a subnet only gets the default IPv4 range — so this errors and asks for an explicit--subnetinstead. 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.