Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pickfirst: Interleave IPv6 and IPv4 addresses for happy eyeballs #7742

Merged

Conversation

arjan-bal
Copy link
Contributor

@arjan-bal arjan-bal commented Oct 15, 2024

This PR adds the address interleaving mentioned in A61

In the flattened list, interleave addresses from the two address families, as per RFC-8305 section 4. Doing this on the flattened address list ensures the best behavior if only one of the two address families is working.

RELEASE NOTES:

  • The experimental pickfirstleaf LB policy interleaves IPv4 and IPv6 address as described in RFC-8305 section 4 before starting connection attempts.

@arjan-bal arjan-bal added the Type: Feature New features or improvements in behavior label Oct 15, 2024
@arjan-bal arjan-bal added this to the 1.68 Release milestone Oct 15, 2024
@arjan-bal arjan-bal requested a review from easwars October 15, 2024 17:53
Copy link

codecov bot commented Oct 15, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 81.88%. Comparing base (d66fc3a) to head (4d5c3a9).
Report is 8 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7742      +/-   ##
==========================================
+ Coverage   81.71%   81.88%   +0.17%     
==========================================
  Files         374      373       -1     
  Lines       38166    37735     -431     
==========================================
- Hits        31188    30901     -287     
+ Misses       5699     5550     -149     
- Partials     1279     1284       +5     
Files with missing lines Coverage Δ
balancer/pickfirst/pickfirstleaf/pickfirstleaf.go 88.77% <100.00%> (+1.10%) ⬆️
internal/testutils/balancer.go 84.40% <100.00%> (+0.08%) ⬆️

... and 41 files with indirect coverage changes

@arjan-bal arjan-bal force-pushed the happy-eyeballs-interlease-addresses branch from b9b602c to f68c03d Compare October 15, 2024 19:26
@arjan-bal arjan-bal force-pushed the happy-eyeballs-interlease-addresses branch from f68c03d to f7dcbc9 Compare October 15, 2024 19:30
@purnesh42H purnesh42H modified the milestones: 1.68 Release, 1.69 Release Oct 16, 2024
@arjan-bal arjan-bal requested a review from dfawley October 16, 2024 19:17
@arjan-bal arjan-bal force-pushed the happy-eyeballs-interlease-addresses branch from e4a4300 to 7b42222 Compare October 19, 2024 21:28
Copy link
Contributor

@easwars easwars left a comment

Choose a reason for hiding this comment

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

Mostly minor nits.

balancer/pickfirst/pickfirstleaf/pickfirstleaf.go Outdated Show resolved Hide resolved
balancer/pickfirst/pickfirstleaf/pickfirstleaf.go Outdated Show resolved Hide resolved
balancer/pickfirst/pickfirstleaf/pickfirstleaf.go Outdated Show resolved Hide resolved
balancer/pickfirst/pickfirstleaf/pickfirstleaf.go Outdated Show resolved Hide resolved
balancer/pickfirst/pickfirstleaf/pickfirstleaf_ext_test.go Outdated Show resolved Hide resolved
balancer/pickfirst/pickfirstleaf/pickfirstleaf_ext_test.go Outdated Show resolved Hide resolved
balancer/pickfirst/pickfirstleaf/pickfirstleaf_ext_test.go Outdated Show resolved Hide resolved
@easwars easwars assigned arjan-bal and unassigned easwars Oct 22, 2024
@arjan-bal arjan-bal assigned easwars and dfawley and unassigned dfawley and arjan-bal Oct 23, 2024
@easwars easwars assigned arjan-bal and unassigned easwars Oct 25, 2024
Copy link
Member

@dfawley dfawley left a comment

Choose a reason for hiding this comment

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

LGTM, just a couple suggestions that would simplify things a bit.


func addressFamily(address string) ipAddrFamily {
// Try parsing addresses without a port specified.
ip := net.ParseIP(address)
Copy link
Member

Choose a reason for hiding this comment

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

Can we not safely assume a port is always present (if it's any IP address)?

I was pretty sure we require that? The DNS resolver is where we add the default port to addresses if needed. So I think we can always do SplitHostPort and return Unknown on error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're correct, the port must be specified. I didn't check if the default port is added in the DNS resolver or somewhere before the dialer. I tried using passthrough to omit the port and the rpc fails with the following error:

code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp: address 127.0.0.1: missing port in address"

Removed the handling of addresses without ports, updating the test cases accordingly.

// If using a resolver like passthrough, the hostnames may not be IP
// addresses but in some format that the dialer can parse.
switch {
case ip == nil:
Copy link
Member

Choose a reason for hiding this comment

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

This could be simplified to:

switch len(ip) {
	case IPv4len:
		return ipAddrFamilyV4
	case IPv6len:
		return ipAddrFamilyV16
	default:
		return ipAddrFamilyUnknown
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This will not work as the length of the slice held by net.IP is always 16 bytes, see https://stackoverflow.com/a/22751285.

This did uncover an edge case where ip.To4() returns true for IPv4-mapped IPv6 addresses like ::FFFF:127.0.0.1. I've added the check to classify them as IPv6 for interleaving purposes and updated a test case to verify this.

@dfawley dfawley removed their assignment Oct 28, 2024
@arjan-bal arjan-bal force-pushed the happy-eyeballs-interlease-addresses branch from 0152d54 to 26425ef Compare November 4, 2024 10:20
@arjan-bal arjan-bal assigned dfawley and unassigned arjan-bal Nov 4, 2024
// Check for existence of IPv4-mapped IPv6 addresses, which are
// considered as IPv4 by net.IP.
// e.g: "::FFFF:127.0.0.1"
case ip.To4() != nil && !strings.Contains(host, ":"):
Copy link
Member

Choose a reason for hiding this comment

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

IPv4-mapped IPv6 addresses probably weren't considered in the dual stack design at all.

I chatted with @ejona86 about this and we think it's unnecessary to check for the colon here. If the resolver produces an IPv4-mapped IPv6 address, we can treat it as either IPv4 or IPv6, whichever is more convenient.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Acknowledged, removed the special handling.

@dfawley dfawley assigned arjan-bal and unassigned dfawley Nov 5, 2024
@arjan-bal arjan-bal merged commit 18d218d into grpc:master Nov 6, 2024
15 checks passed
@arjan-bal arjan-bal deleted the happy-eyeballs-interlease-addresses branch November 6, 2024 06:08
misvivek pushed a commit to misvivek/grpc-go that referenced this pull request Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature New features or improvements in behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants