Skip to content

libnetwork: provide endpoint name for IPAM drivers#50586

Merged
thaJeztah merged 1 commit intomoby:masterfrom
olljanat:endpoint-name-label
Sep 4, 2025
Merged

libnetwork: provide endpoint name for IPAM drivers#50586
thaJeztah merged 1 commit intomoby:masterfrom
olljanat:endpoint-name-label

Conversation

@olljanat
Copy link
Copy Markdown
Contributor

@olljanat olljanat commented Jul 31, 2025

- What I did
I'm building IPAM driver which integrates Docker and HashiCorp Nomad in way that it is possible dynamically allocate sub ranges (like can do manually with --ip-range) by utilizing Nomad namespace metadata.

So for example I would create network to Windows nodes like this:

docker network create `
  --driver transparent `
  --subnet 10.0.0.0/16 `
  --gateway 10.0.0.1 `
  containers

and to Linux nodes like this:

docker network create \
  -d ipvlan \
  --subnet 10.0.0.0/16 \
  --gateway 10.0.0.1 \
  --opt parent=eth0 \
  --opt ipvlan_mode=l2 \
  containers

And then create application environments with Nomad namespace configuration like this:

name = "example"
meta {
  subnet = "10.0.1.0/24"
}
name = "foobar"
meta {
  subnet = "10.0.2.0/24"
}

But it requires that IPAM driver knows that to which Nomad namespace container sending RequestAddress belongs to.

Initially I tried to solve that by enabling RequiresMACAddress capability and using that to find correct container and it's labels but it turns out that ContainerInspect cannot be called inside of RequestAddress function because libnetwork has locks enabled in that point.

So this PR provides minimal change to libnetwork allowing this to be done in IPAM drivers.

- How I did it
Added logic which will always send com.docker.network.endpoint.name label to IPAM driver containing name of the endpoint (=> name of the container).

That solves issue for me because containers naming is hardcoded in Nomad so I can simply parse allocation ID from it and call Read Allocation API

- How to verify it
In current form it it should not need anything more than pass CI. If maintainers want, this can be also put behind of capability flag but I don't think that it is necessary as it is just extra label.

EDIT: Plugin described above is now available in here and seems to be working fine with this.

- A picture of a cute animal (not mandatory but encouraged)
nomad-docker

@olljanat olljanat force-pushed the endpoint-name-label branch from 6dc78eb to 827c0c7 Compare July 31, 2025 20:21
@olljanat olljanat force-pushed the endpoint-name-label branch 2 times, most recently from e49bd02 to e934704 Compare July 31, 2025 21:08
Copy link
Copy Markdown
Contributor

@austinvazquez austinvazquez left a comment

Choose a reason for hiding this comment

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

Approach lgtm, just a minor suggestion.

Comment thread daemon/libnetwork/network.go Outdated
@austinvazquez austinvazquez added kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. area/networking Networking area/networking/ipam Networking labels Aug 5, 2025
@austinvazquez austinvazquez added this to the 29.1.0 milestone Aug 5, 2025
@olljanat olljanat force-pushed the endpoint-name-label branch from e934704 to 1f909d8 Compare August 5, 2025 13:19
@corhere corhere self-requested a review August 5, 2025 16:21
@olljanat
Copy link
Copy Markdown
Contributor Author

@akerouanton PTAL

Comment thread daemon/libnetwork/network.go Outdated
var err error

ep := &Endpoint{name: name, generic: make(map[string]any), iface: &EndpointInterface{}}
ep := &Endpoint{name: name, generic: make(map[string]any), iface: &EndpointInterface{}, ipamOptions: map[string]string{netlabel.EndpointName: name}}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

CreateOptionIpam overwrites ipamOptions:

func CreateOptionIpam(ipV4, ipV6 net.IP, llIPs []net.IP, ipamOptions map[string]string) EndpointOption {
return func(ep *Endpoint) {
ep.prefAddress = ipV4
ep.prefAddressV6 = ipV6
if len(llIPs) != 0 {
for _, ip := range llIPs {
nw := &net.IPNet{IP: ip, Mask: linkLocalMask}
if ip.To4() == nil {
nw.Mask = linkLocalMaskIPv6
}
ep.iface.llAddrs = append(ep.iface.llAddrs, nw)
}
}
ep.ipamOptions = ipamOptions
}
}

So, I believe this currently works because no CreateOptionIpam was passed to (*Network).CreateEndpoint(), which means no IPAM flags were specified on docker network create ….

Could you touch CreateOptionIpam up, and add a unit test please?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah, and it's probably worth putting &Endpoint{} instantiation on multiple lines to improve readability.

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.

Afaiu options provided with docker network create --ipam-opt ... are only passed to IPAM driver functionRequestPool. Not to RequestAddress. So CreateOptionIpam will not need update but will add unit test for this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So CreateOptionIpam will not need update but will add unit test for this.

Ah, right. I confused myself, sorry 🙈 You're changing createEndpoint, so it's definitely docker run --ip ….

For the record, I ran the following commands with breakpoints set before / after ep.processOptions(options...) and I can confirm that CreateOptionIpam removes the predefined endpoint name label.

$ docker network create --subnet 172.21.0.0/24 testnet
$ docker run --rm --network testnet --ip 172.21.0.10 alpine true

One way to test this PR would be to add a test specifically for CreateOptionIpam. Call the func it returns with an endpoint initialized with a non-empty map of labels, and verify that CreateOptionIpam preserve them. (And you can remove the change you made in TestIpamReleaseOnNetDriverFailures as it's not related to this PR.)

Copy link
Copy Markdown
Member

@akerouanton akerouanton Aug 13, 2025

Choose a reason for hiding this comment

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

Afaiu options provided with docker network create --ipam-opt ... are only passed to IPAM driver functionRequestPool. Not to RequestAddress.

Ah, right. I confused myself, sorry 🙈 You're changing createEndpoint, so it's definitely docker run --ip ….

For the record, I ran the following commands with breakpoints set before / after ep.processOptions(options...) and I can confirm that CreateOptionIpam removes the predefined endpoint name label.

$ docker network create --subnet 172.21.0.0/24 testnet
$ docker run --rm --network testnet --ip 172.21.0.10 alpine true

One way to test this PR would be to add a test specifically for CreateOptionIpam. Call the func it returns with an endpoint initialized with a non-empty map of labels, and verify that CreateOptionIpam preserve them. (And you can remove the change you made in TestIpamReleaseOnNetDriverFailures as it's not related to this PR.)

Copy link
Copy Markdown
Contributor Author

@olljanat olljanat Aug 14, 2025

Choose a reason for hiding this comment

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

Oh, my original solution was actually correct. It was change suggested in #50586 (comment) which broke case where --ip flag is used.

This cannot be handled in CreateOptionIpam because endpoint name is not known in there so perhaps it would be enough for now just leave comment for those who might touch this in future?

Also I think that ep.ipamOptions is always nil before initialization so it should not be needed to check it but let's see what is result of CI.

Copy link
Copy Markdown
Contributor Author

@olljanat olljanat Aug 25, 2025

Choose a reason for hiding this comment

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

@akerouanton test added and verified that it would fail if ipamOptions was added in line 1188 like it was in f4a72b8 which you tested.

Ping also @corhere as I see that you self-requested a review for this.

EDIT: Ended up to disable new test in Windows because creating and removing networks like this will easily get HNS to unknown state and this is not OS specific logic.

@olljanat olljanat force-pushed the endpoint-name-label branch 3 times, most recently from f4a72b8 to d678c1d Compare August 14, 2025 17:20
@olljanat olljanat force-pushed the endpoint-name-label branch 3 times, most recently from 6a4cb4e to 875f3b0 Compare August 25, 2025 19:59
Copy link
Copy Markdown
Member

@akerouanton akerouanton left a comment

Choose a reason for hiding this comment

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

A few nits, otherwise LGTM

Comment thread daemon/libnetwork/network.go Outdated
Comment thread daemon/libnetwork/libnetwork_internal_test.go Outdated
Comment thread daemon/libnetwork/libnetwork_internal_test.go Outdated
Comment thread daemon/libnetwork/libnetwork_internal_test.go Outdated
@olljanat olljanat force-pushed the endpoint-name-label branch from 875f3b0 to c6717f4 Compare August 28, 2025 07:55
@olljanat
Copy link
Copy Markdown
Contributor Author

A few nits, otherwise LGTM

@akerouanton Those are fixed now.

Copy link
Copy Markdown
Member

@akerouanton akerouanton left a comment

Choose a reason for hiding this comment

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

LGTM

@thaJeztah thaJeztah merged commit aead996 into moby:master Sep 4, 2025
175 checks passed
@corhere corhere modified the milestones: 29.1.0, 29.0.0 Sep 4, 2025
@thompson-shaun thompson-shaun moved this from New to Complete in 🔦 Maintainer spotlight Sep 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/networking/ipam Networking area/networking Networking kind/enhancement Enhancements are not bugs or new features but can improve usability or performance.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants