Skip to content

upstream: Implement Happy Eyeballs address sorting#18906

Merged
RyanTheOptimist merged 10 commits intoenvoyproxy:mainfrom
RyanTheOptimist:sortAddresses
Nov 16, 2021
Merged

upstream: Implement Happy Eyeballs address sorting#18906
RyanTheOptimist merged 10 commits intoenvoyproxy:mainfrom
RyanTheOptimist:sortAddresses

Conversation

@RyanTheOptimist
Copy link
Contributor

upstream: Implement Happy Eyeballs address sorting with address families interleaved, as per Section 4 of RFC 8305, Happy Eyeballs v2. Sorting as per Section 6 of RFC6724 already happens in ares_getaddrinfo() and is not part of this.

Risk Level: Low - Happy Eyeballs is not yet used
Testing: Unit tests
Docs Changes: N/A
Release Notes: N/A
Platform Specific Features: N/A
Signed-off-by: Ryan Hamilton rch@google.com

Signed-off-by: Ryan Hamilton <rch@google.com>
@RyanTheOptimist
Copy link
Contributor Author

/assign @RenjieTang

ip_v6_3, ip_v4_3, ip_v6_4, ip_v4_4};
EXPECT_EQ(interleaved3, HappyEyeballsConnectionImpl::sortAddresses(mixed));
for (size_t i = 0; i < interleaved3.size(); ++i) {
std::cout << i << " " << interleaved3[i]->asString() << "\n";
Copy link
Contributor

Choose a reason for hiding this comment

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

debug log?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops! Done.


// Bubble the address up to the current position.
for (size_t i = next; i > current; i--) {
using std::swap;
Copy link
Contributor

Choose a reason for hiding this comment

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

Since std::swap is only called once here, would it be cleaner to just call std::swap without the using clause?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Apparently not, as per go/using-std-swap. Who knew?! (Believe it or not, there is a potential behavior difference between the two)

Copy link
Contributor

Choose a reason for hiding this comment

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

Amazing... Thanks for providing the context!

Signed-off-by: Ryan Hamilton <rch@google.com>
RenjieTang
RenjieTang previously approved these changes Nov 5, 2021

// Bubble the address up to the current position.
for (size_t i = next; i > current; i--) {
using std::swap;
Copy link
Contributor

Choose a reason for hiding this comment

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

Amazing... Thanks for providing the context!

@RyanTheOptimist
Copy link
Contributor Author

/assign @junr03

@RyanTheOptimist
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #18906 (comment) was created by @RyanTheOptimist.

see: more, trace.

Copy link
Member

@davinci26 davinci26 left a comment

Choose a reason for hiding this comment

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

some drive-by c++ comments. If we commit to using std libraries we could make the code a bit shorter but I don't have a strong opinion. Up to you if you want to change it or not

Signed-off-by: Ryan Hamilton <rch@google.com>
Signed-off-by: Ryan Hamilton <rch@google.com>
Signed-off-by: Ryan Hamilton <rch@google.com>
davinci26
davinci26 previously approved these changes Nov 9, 2021
Copy link
Member

@davinci26 davinci26 left a comment

Choose a reason for hiding this comment

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

LGTM

@RyanTheOptimist
Copy link
Contributor Author

/assign @alyssawilk

const ConnectionSocket::OptionsSharedPtr options)
: id_(ConnectionImpl::next_global_id_++), dispatcher_(dispatcher), address_list_(address_list),
: id_(ConnectionImpl::next_global_id_++), dispatcher_(dispatcher),
address_list_(sortAddresses(address_list)),
Copy link
Member

Choose a reason for hiding this comment

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

food for thought: do we care about making this behavior configurable? i.e., opt-out via config?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm. I'm inclined to say "no", or at least "not unless someone asks for it". Happy Eyeballs itself is already configurable and I can't really imagine why this would be something we'd want to disable if Happy Eyeballs were in use. That being said, if someone ask for it then we could definitely make it configurable. WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

fair. sg!

// Returns a new vector containing the contents of |address_list| sorted
// with address families interleaved, as per Section 4 of RFC 8305, Happy
// Eyeballs v2. It is assumed that The list must already sorted as per
// Section 6 of RFC6724, which happens in ares_getaddrinfo().
Copy link
Member

Choose a reason for hiding this comment

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

does the Apple implementation also do this? If not, then we would be breaking this requirement for iOS

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it does, according to what I read online.

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe comment as such.
is there any way to CHECK on this, in case there are other DNS impls that might not realize the constraint?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a comment about Apple DNS. Good idea. As for detecting that this sorting might be missing, I'm not sure how we would do that short of implementing the sorting rules and checking that addr[i] < addr[i+1] but that's non-trivial. I'm open to suggestions though!

Co-authored-by: Jose Ulises Nino Rivera <junr03@users.noreply.github.com>

Signed-off-by: Ryan Hamilton <ryan@optimism.cc>
Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

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

Awesome, thanks so much for implementing this, and sorting out we don't need to do all those kernel calls!
/wait

// Returns a new vector containing the contents of |address_list| sorted
// with address families interleaved, as per Section 4 of RFC 8305, Happy
// Eyeballs v2. It is assumed that The list must already sorted as per
// Section 6 of RFC6724, which happens in ares_getaddrinfo().
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe comment as such.
is there any way to CHECK on this, in case there are other DNS impls that might not realize the constraint?

for (auto current = address_list.begin(); current != address_list.end(); ++current) {
// Find the first address with a different address family than the current address.
auto it = std::find_if(current, address_list.end(), [&](const auto& val) {
return (val->type() != Address::Type::Ip || (*current)->type() != Address::Type::Ip ||
Copy link
Contributor

Choose a reason for hiding this comment

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

kinda curious, does the spec say what to do with non IP addresses? Should we just remove those if we see any?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The specs refer specifically to IP addresses. I don't think they even consider non-IP addresses. The other address types are Pipe and EnvoyInternal. Are these valid addresses for passing into a Network::ClientConnection? From spelunking down in the code, it kinda looks like we end up in SocketInterfaceImpl::socket which seems to support non-IP addresses so I think we need to keep them in the list, but maybe we don't need them if we're doing Happy Eyeballs?

Signed-off-by: Ryan Hamilton <rch@google.com>
Signed-off-by: Ryan Hamilton <rch@google.com>
@RyanTheOptimist
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #18906 (comment) was created by @RyanTheOptimist.

see: more, trace.

@RyanTheOptimist
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #18906 (comment) was created by @RyanTheOptimist.

see: more, trace.

alyssawilk
alyssawilk previously approved these changes Nov 11, 2021
Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

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

Yeah this looks better thanks. Throwing over to @ggreenway for non-google pass

@moderation
Copy link
Contributor

Wondering if this PR addresses #18572 and streams results (or was this fixed in #18464) /cc @junr03

@RyanTheOptimist
Copy link
Contributor Author

Wondering if this PR addresses #18572 and streams results (or was this fixed in #18464) /cc @junr03

I don't believe that either this PR nor #18464 address the concern in #18572. That issue is motivated to start a connection attempt as soon as the first DNS response arrives. For example, if we send an A request and an AAAA request we currently wait until both responses have arrived. But we could start an attempt to the first address in the first response. This current PR merely sorts the list of addresses but does not change the timing.

Copy link
Member

@ggreenway ggreenway left a comment

Choose a reason for hiding this comment

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

LGTM. One minor grammar nit.

/wait


// Returns a new vector containing the contents of |address_list| sorted
// with address families interleaved, as per Section 4 of RFC 8305, Happy
// Eyeballs v2. It is assumed that the list must already sorted as per
Copy link
Member

Choose a reason for hiding this comment

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

"list must already BE sorted...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. PTAL?

Signed-off-by: Ryan Hamilton <rch@google.com>
Signed-off-by: Ryan Hamilton <rch@google.com>
@RyanTheOptimist
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #18906 (comment) was created by @RyanTheOptimist.

see: more, trace.

@RyanTheOptimist RyanTheOptimist merged commit d981914 into envoyproxy:main Nov 16, 2021
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.

7 participants