Skip to content

libnetwork: respect gw priority per address family#52328

Merged
thaJeztah merged 1 commit intomoby:masterfrom
Varun5711:gw-priority-per-family
Apr 9, 2026
Merged

libnetwork: respect gw priority per address family#52328
thaJeztah merged 1 commit intomoby:masterfrom
Varun5711:gw-priority-per-family

Conversation

@Varun5711
Copy link
Copy Markdown
Contributor

@Varun5711 Varun5711 commented Apr 7, 2026

Fixes #51999

Problem

When a sandbox is attached to both:

  • a higher-priority IPv4-only network, and
  • a lower-priority dual-stack network,

Moby may pick the dual-stack endpoint as the IPv4 default gateway even though GwPriority says the IPv4-only endpoint should win.

Root cause

Endpoint.Less() already sorts endpoints using:

  1. gateway priority
  2. gateway network/internal ordering
  3. gateway capability
  4. network name

But getGatewayEndpoint() in daemon/libnetwork/default_gateway.go bypasses that ordering by returning the first dual-stack endpoint for both address families.

As a result, a lower-priority dual-stack endpoint can take over IPv4 gateway selection.

Fix

Select IPv4 and IPv6 gateway endpoints independently from the sorted endpoint list:

  • first endpoint with IPv4 connectivity wins IPv4
  • first endpoint with IPv6 connectivity wins IPv6
  • stop once both families have been resolved

This makes gateway selection honor priority per address family while preserving current tie behavior.

Tests

Add a regression test covering:

  • one dual-stack endpoint
  • one higher-priority IPv4-only endpoint

Expected:

  • IPv4 gateway endpoint is the IPv4-only endpoint
  • IPv6 gateway endpoint is the dual-stack endpoint

Validation

Built with:

GOOS=linux GOARCH=amd64 go test -c ./daemon/libnetwork

I could not run the full daemon/libnetwork test suite locally because it is Linux-only and my current environment is macOS.

- if a container has an IPv4-only or an IPv6-only endpoint with higher "gateway priority" than a dual stack endpoint, the single stack endpoint will now be used as the default gateway for its address family.

@robmry
Copy link
Copy Markdown
Contributor

robmry commented Apr 7, 2026

Hi @Varun5711 - thank you for taking a look at this, from a quick check I think the change is good.

I'll paste @thaJeztah's explanation of the DCO sign-off below.

I could not run the full daemon/libnetwork test suite locally because it is Linux-only and my current environment is macOS.

I also use a Mac ... if you want to run the tests, the contributing guide describes how to use a container for development - https://github.com/moby/moby/blob/master/docs/contributing/set-up-dev-env.md - but we can also just see what happens in CI once you've added the "Signed-off-by".


Thank you for contributing! It appears your commit message is missing a DCO sign-off,
causing the DCO check to fail.

We require all commit messages to have a Signed-off-by line with your name
and e-mail (see "Sign your work"
in the CONTRIBUTING.md in this repository), which looks something like:

Signed-off-by: YourFirsName YourLastName yourname@example.org
There is no need to open a new pull request, but to fix this (and make CI pass),
you need to amend the commit(s) in this pull request, and "force push" the amended
commit.

Unfortunately, it's not possible to do so through GitHub's web UI, so this needs
to be done through the git commandline.

You can find some instructions in the output of the DCO check (which can be found
in the "checks" tab on this pull request), as well as in the Moby contributing guide.

Steps to do so "roughly" come down to:

Set your name and e-mail in git's configuration:

git config --global user.name "YourFirstName YourLastName"
git config --global user.email "yourname@example.org"
(Make sure to use your real name (not your GitHub username/handle) and e-mail)

Clone your fork locally

Check out the branch associated with this pull request

Sign-off and amend the existing commit(s)

git commit --amend --no-edit --signoff
If your pull request contains multiple commits, either squash the commits (if
needed) or sign-off each individual commit.

Force push your branch to GitHub (using the --force or --force-with-lease flags) to update the pull request.

Let me know if you need help or more detailed instructions!

@Varun5711 Varun5711 force-pushed the gw-priority-per-family branch from 608a9e1 to 7870ca0 Compare April 7, 2026 18:37
@Varun5711
Copy link
Copy Markdown
Contributor Author

Hi @robmry — thanks for the guidance! I’ve added the DCO sign-off and updated the commit. Please let me know if anything else is needed.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes default gateway endpoint selection in daemon/libnetwork so that gateway priority is respected independently for IPv4 and IPv6 when a sandbox is attached to mixed single/dual-stack networks (fixes #51999).

Changes:

  • Update Sandbox.getGatewayEndpoint() to select IPv4 and IPv6 gateway endpoints independently from the already-sorted endpoint list.
  • Add a regression test covering a higher-priority IPv4-only endpoint alongside a lower-priority dual-stack endpoint.

Reviewed changes

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

File Description
daemon/libnetwork/default_gateway.go Adjusts gateway endpoint selection to honor gw-priority per address family (v4/v6 resolved independently).
daemon/libnetwork/sandbox_unix_test.go Adds a regression test intended to ensure per-family gateway priority selection.

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

Comment thread daemon/libnetwork/sandbox_unix_test.go Outdated
Comment thread daemon/libnetwork/default_gateway.go Outdated
@Varun5711 Varun5711 force-pushed the gw-priority-per-family branch from 7870ca0 to 686edb0 Compare April 7, 2026 19:28
@Varun5711
Copy link
Copy Markdown
Contributor Author

Hi @robmry — I’ve pushed a fix for the failing test related to gateway selection per address family. Please let me know if you’d like any changes or once CI is approved. Thanks!

Copy link
Copy Markdown
Contributor

@robmry robmry left a comment

Choose a reason for hiding this comment

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

LGTM - thank you

@thaJeztah thaJeztah added this to the 29.4.1 milestone Apr 9, 2026
@robmry robmry added the kind/bugfix PR's that fix bugs label Apr 9, 2026
@robmry robmry requested a review from thaJeztah April 9, 2026 09:39
Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

Thanks! I left some comment (sorry for being nit-picky), but LGTM after those are addressed.

Comment on lines +202 to 206
if ep4 != nil && ep6 != nil {
return ep4, ep6
}
}
return ep4, ep6
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.

Really a nit; the really return is a bit confusing, because .. it does the same thing as the return at the end, but I had to look twice to see if there was no bug (because the return at the end would unconditionally return the values, even if one (or both) are nil).

Perhaps a break would be more clear in this case (could even add a comment to be explicit);

		if ep4 != nil && ep6 != nil {
			// Found both; we're done.
			break
		}
	}
	return ep4, ep6

Comment thread daemon/libnetwork/sandbox_unix_test.go Outdated

ctrlr, nws := getTestEnv(t, opts...)

sbx, err := ctrlr.NewSandbox(context.Background(), "sandbox-prio-per-family")
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.

We can use t.Context() now (we haven't updated all tests to do so, but for new tests we may as well do so).

Comment thread daemon/libnetwork/sandbox_unix_test.go Outdated
Comment on lines +231 to +233
if err != nil {
t.Fatal(err)
}
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.

Looks like we're mixing stdlib and gotest.tools asserting within the same test; can you use assert for these as well?

assert.NilError(t, err)

@thaJeztah
Copy link
Copy Markdown
Member

Oh! For those changes; you can amend the commit (we generally prefer not having separate "fix up" commits)

Signed-off-by: Varun Hotani <varunhotani@gmail.com>
@Varun5711 Varun5711 force-pushed the gw-priority-per-family branch from 686edb0 to e30a6fa Compare April 9, 2026 10:40
@Varun5711
Copy link
Copy Markdown
Contributor Author

Addressed the requested nits in the existing commit and force-pushed the branch:

  • switched the early return to a break with an explicit comment
  • updated the new test to use t.Context()
  • changed the new test to use gotest.tools assertions consistently

@Varun5711 Varun5711 requested a review from thaJeztah April 9, 2026 11:41
Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

thanks for updating!

LGTM

@thaJeztah thaJeztah merged commit 994a849 into moby:master Apr 9, 2026
182 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gw_priority is ignored on ipv4 network if service also joins an ipv6 network without priority

4 participants