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

dfp: Insert correct preresolved hostname key in DNS cache #30784

Merged
merged 5 commits into from
Nov 10, 2023

Conversation

abeyad
Copy link
Contributor

@abeyad abeyad commented Nov 8, 2023

Previously, preresolved hostnames didn't include the port in the host that is used as a key in the DNS cache. This behavior differed from the regular resolution path which always normalized the host (via DnsHostInfo::normalizeHostForDfp). There was also a bug in the DnsCacheImplTest.PreresolveSuccess test, where the preresolve hostnames config included the port in the socket address, which is not how it would normally be specified and masked this issue.

This PR fixes the problem by ensuring the preresolved hostnames have the host normalized (via DnsHostInfo::normalizeHostForDfp) before inserting into the DNS cache, just like the host is normalized before retrieving from the DNS cache. The test issue is also fixed so we can now verify that the correct cache key is being used for insertion, retrieval, and removal, and test coverage is added to ensure we can fetch the cache entry correctly whether the host includes the port or not.

Previously, preresolved hostnames didn't include the port in the `host`
that is used as a key in the DNS cache. This behavior differed from the
regular resolution path which always normalized the host (via
DnsHostInfo::normalizeHostForDfp). There was also a bug in the
DnsCacheImplTest.PreresolveSuccess test, where the preresolve hostnames
config included the port in the socket address, which is not how it
would normally be specified and masked this issue.

This PR fixes the problem by ensuring the preresolved hostnames have the
host normalized (via DnsHostInfo::normalizeHostForDfp) before inserting
into the DNS cache, just like the host is normalized before retrieving
from the DNS cache. The test issue is also fixed so we can now verify
that the correct cache key is being used for insertion, retrieval, and
removal, and test coverage is added to ensure we can fetch the cache
entry correctly whether the host includes the port or not.

Signed-off-by: Ali Beyad <[email protected]>
Copy link
Contributor

@RyanTheOptimist RyanTheOptimist left a comment

Choose a reason for hiding this comment

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

Nice catch!

EXPECT_CALL(*resolver_, resolve("bar.baz.com", _, _))
std::string host = "bar.baz.com";
uint32_t port = 443;
std::string authority = host + ":" + std::to_string(port);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I think absl::StrCat() is the canonical way to do this sort of concatenation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah i was debating whether to do that and add the new include or just use + and to_string() (since I see test code that use these quite liberally), but i just changed it to StrCat

@@ -58,7 +58,10 @@ DnsCacheImpl::DnsCacheImpl(
// cache to load an entry. Further if this particular resolution fails all the is lost is the
Copy link
Contributor

Choose a reason for hiding this comment

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

(I'm trying to comment on line 56)

Wow, is this the correct type for hostname?

repeated config.core.v3.SocketAddress preresolve_hostnames = 10;

Hostname is a bizarre term for this as it seems to be a protocol (tcp/udp), an IP address, a port, and a resolver name. Am I reading that correctly? bizarre

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 was also surprised SocketAddress was used for preresolved hostnames config, and doesn't seem to be the right structure to represent a DNS cache entry. Changing it is a good idea but probably outside the scope of the PR. I do share your concern though..

@@ -58,7 +58,10 @@ DnsCacheImpl::DnsCacheImpl(
// cache to load an entry. Further if this particular resolution fails all the is lost is the
// potential optimization of having the entry be preresolved the first time a true consumer of
// this DNS cache asks for it.
startCacheLoad(hostname.address(), hostname.port_value(), false);
const std::string host =
DnsHostInfo::normalizeHostForDfp(hostname.address(), hostname.port_value());
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need a runtime guard for this, since it looks like a behavior change? (Or is there some reason we're safe here)

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 was debating this myself, and could be convinced of adding a runtime guard. I just figured that no one is using this currently (preresolved hostnames config), and in any case, all that will happen if the cache key change causes a cache miss is that the DNS record will have to be fetched (which is actually what was happening previously on "production" use cases, i.e. my traffic director integration test, without us knowing about it, you can just tell from the logs).

Copy link
Contributor

Choose a reason for hiding this comment

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

I think I'd be inclined to add a guard (which will default to true) since it's easy to add and better safe than sorry. I think we know that nobody is using the mobile APIs for this config, but I'm not sure if we know about DFP users in the wild?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point, i had assumed DFP is only used for mobile but didn't consider the possibility it's used outside of mobile. runtime guard has been added!

Signed-off-by: Ali Beyad <[email protected]>
Signed-off-by: Ali Beyad <[email protected]>
Copy link

CC @envoyproxy/runtime-guard-changes: FYI only for changes made to (source/common/runtime/runtime_features.cc).

🐱

Caused by: #30784 was synchronize by abeyad.

see: more, trace.

RyanTheOptimist
RyanTheOptimist previously approved these changes Nov 9, 2023
Copy link
Contributor

@RyanTheOptimist RyanTheOptimist 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 doing this!

@abeyad
Copy link
Contributor Author

abeyad commented Nov 9, 2023

Adding @lizan as DFP owner and cross-company reviewer

@abeyad
Copy link
Contributor Author

abeyad commented Nov 9, 2023

/retest

Copy link
Member

@lizan lizan left a comment

Choose a reason for hiding this comment

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

one style nit. otherwise LGTM. @RyanTheOptimist feel free to merge.

config_.set_name("foo");
config_.set_dns_lookup_family(envoy::config::cluster::v3::Cluster::V4_ONLY);
config_.mutable_max_hosts()->set_value(max_hosts);
if (!preresolve_hostnames.empty()) {
for (const auto& hostname : preresolve_hostnames) {
for (const auto& host_pair : preresolve_hostnames) {
Copy link
Member

Choose a reason for hiding this comment

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

nit:

Suggested change
for (const auto& host_pair : preresolve_hostnames) {
for (const auto& [host, port] : preresolve_hostnames) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the recommendation, done!

Signed-off-by: Ali Beyad <[email protected]>
@RyanTheOptimist
Copy link
Contributor

I think the protobuf check will fail until #30826 lands and is merged into this PR :(

@abeyad
Copy link
Contributor Author

abeyad commented Nov 10, 2023

/retest

@abeyad
Copy link
Contributor Author

abeyad commented Nov 10, 2023

/retest

@abeyad abeyad merged commit 32e8b48 into envoyproxy:main Nov 10, 2023
104 of 105 checks passed
@abeyad abeyad deleted the dfp_dns_cache branch November 10, 2023 22:08
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.

3 participants