Skip to content

fix(network): stop injecting ipRange into the CNI config - #5078

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

fix(network): stop injecting ipRange into the CNI config#5078
mayur-tolexo wants to merge 1 commit into
containerd:mainfrom
mayur-tolexo:fix/network-iprange-cni

Conversation

@mayur-tolexo

Copy link
Copy Markdown
Contributor

Fixes #5068.

network create --ip-range was writing an ipRange property into the host-local IPAM ranges on disk, but host-local has no such field — it only reads subnet/rangeStart/rangeEnd/gateway and silently ignores anything else. So the property never affected allocation; it was only being read back by network inspect (via case-insensitive JSON) to report Docker's IPRange.

This drops the field from the CNI config and instead recomputes the range CIDR from rangeStart/rangeEnd at inspect time. FirstIPInSubnet only bumps the network's last byte and LastIPInSubnet gives the broadcast, so the bounds invert cleanly back to the original CIDR. network inspect still reports the same IPRange as before and as Docker — the existing inspect e2e that asserts it is unchanged, plus a unit test covers the reconstruction across v4/v6 prefixes.

Same class of issue as --aux-address in #5041; there the reserved pairs aren't derivable so they move to a nerdctl label, whereas ipRange is fully derivable and needs no storage.

Keeping this a draft until #5041 settles, since both touch the same IPAM code and I'll rebase whichever lands second.

host-local's IPAM range has no ipRange field, so `network create --ip-range`
was writing a property the plugin ignores into the on-disk conflist. Drop it
and instead recompute the range CIDR from rangeStart/rangeEnd when reporting
IPRange in `network inspect`, which is the only place the value was read back.

Fixes containerd#5068

Signed-off-by: Mayur Das <mayur.das@neevcloud.com>
@mayur-tolexo
mayur-tolexo force-pushed the fix/network-iprange-cni branch from c7aebfd to 7191d26 Compare July 17, 2026 09:53
@mayur-tolexo

mayur-tolexo commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Re-verified inspect parity against Docker 29.4.0 with this branch built in a Linux/containerd sandbox. The fix drops ipRange from the on-disk CNI config and rebuilds it on inspect from the rangeStart/rangeEnd bounds host-local actually stores (subnet.CIDRFromRange, the inverse of FirstIPInSubnet/LastIPInSubnet).

nerdctl built off this branch:

$ nerdctl network create --subnet 172.28.0.0/16 --ip-range 172.28.5.0/24 --gateway 172.28.5.254 iprv4a
$ nerdctl network inspect iprv4a --format '{{json .IPAM.Config}}'
[{"Subnet":"172.28.0.0/16","Gateway":"172.28.5.254","IPRange":"172.28.5.0/24"}]

$ nerdctl network create --subnet 10.24.0.0/16 --ip-range 10.24.24.0/25 iprv4b
$ nerdctl network inspect iprv4b --format '{{json .IPAM.Config}}'
[{"Subnet":"10.24.0.0/16","Gateway":"10.24.0.1","IPRange":"10.24.24.0/25"}]

$ nerdctl network create --ipv6 --subnet 2001:db8::/48 --ip-range 2001:db8:0:5::/64 iprv6
$ nerdctl network inspect iprv6 --format '{{json .IPAM.Config}}'
[{"Subnet":"2001:db8::/48","Gateway":"2001:db8::1","IPRange":"2001:db8:0:5::/64"}, ...]

Docker 29.4.0, same inputs:

$ docker network inspect <net> --format '{{json .IPAM.Config}}'
[{"Subnet":"172.28.0.0/16","IPRange":"172.28.5.0/24","Gateway":"172.28.5.254"}]
[{"Subnet":"10.24.0.0/16","IPRange":"10.24.24.0/25","Gateway":"10.24.24.0"}]
[{"Subnet":"2001:db8::/48","IPRange":"2001:db8:0:5::/64","Gateway":"2001:db8:0:5::"}]

IPRange comes out identical to Docker in all three, including the /25 that doesn't align to the subnet prefix and the v6 /64. (The gateway still differs because nerdctl defaults it to .1 of the subnet rather than the range's network address, which is a pre-existing default unrelated to this change.)

And the actual point of the fix — the field is no longer written to the on-disk conflist, and inspect rebuilds it from the bounds host-local does store:

$ python3 -c 'import json;print(json.load(open("/etc/cni/net.d/nerdctl-iprv4a.conflist"))["plugins"][0]["ipam"]["ranges"])'
[[{'gateway': '172.28.5.254', 'rangeEnd': '172.28.5.255', 'rangeStart': '172.28.5.1', 'subnet': '172.28.0.0/16'}]]

$ grep -o ipRange /etc/cni/net.d/nerdctl-iprv4a.conflist
(no match)

rangeStart 172.28.5.1 / rangeEnd 172.28.5.255 invert back to 172.28.5.0/24, which is what inspect reports. The v6 case stores rangeEnd 2001:db8:0:5:ffff:ffff:ffff:ffff (the full /64, nothing dropped) and reconstructs 2001:db8:0:5::/64.

One limitation worth noting: a /31 or /127 ip-range collapses to a single stored address (network+1 equals the broadcast), indistinguishable from a /32//128, so those recompute as /32//128. There is a unit-test case pinning that; every other prefix round-trips exactly.

@mayur-tolexo
mayur-tolexo marked this pull request as ready for review July 25, 2026 08:21
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.

nerdctl network create --ip-range injects a non-existent property ipRange to CNI IPAM config

1 participant