Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ syntax = "proto3";
package envoy.extensions.common.dynamic_forward_proxy.v3;

import "envoy/config/cluster/v3/cluster.proto";
import "envoy/config/core/v3/address.proto";
import "envoy/config/core/v3/resolver.proto";

import "google/protobuf/duration.proto";
Expand All @@ -29,7 +30,7 @@ message DnsCacheCircuitBreakers {

// Configuration for the dynamic forward proxy DNS cache. See the :ref:`architecture overview
// <arch_overview_http_dynamic_forward_proxy>` for more information.
// [#next-free-field: 10]
// [#next-free-field: 11]
message DnsCacheConfig {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.common.dynamic_forward_proxy.v2alpha.DnsCacheConfig";
Expand Down Expand Up @@ -108,4 +109,9 @@ message DnsCacheConfig {

// DNS resolution configuration which includes the underlying dns resolver addresses and options.
config.core.v3.DnsResolutionConfig dns_resolution_config = 9;

// Hostnames that should be preresolved into the cache upon creation. This might provide a
// performance improvement, in the form of cache hits, for hostnames that are going to be
// resolved during steady state and are known at config load time.
repeated config.core.v3.SocketAddress preresolve_hostnames = 10;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ New Features
* bootstrap: added :ref:`dns_resolution_config <envoy_v3_api_field_config.bootstrap.v3.Bootstrap.dns_resolution_config>` to aggregate all of the DNS resolver configuration in a single message. By setting one such configuration option *no_default_search_domain* as true the DNS resolver will not use the default search domains. And by setting the configuration *resolvers* we can specify the external DNS servers to be used for external DNS query.
* cluster: added :ref:`dns_resolution_config <envoy_v3_api_field_config.cluster.v3.Cluster.dns_resolution_config>` to aggregate all of the DNS resolver configuration in a single message. By setting one such configuration option *no_default_search_domain* as true the DNS resolver will not use the default search domains.
* crash support: restore crash context when continuing to processing requests or responses as a result of an asynchronous callback that invokes a filter directly. This is unlike the call stacks that go through the various network layers, to eventually reach the filter. For a concrete example see: ``Envoy::Extensions::HttpFilters::Cache::CacheFilter::getHeaders`` which posts a callback on the dispatcher that will invoke the filter directly.
* dns cache: added :ref:`preresolve_hostnames <envoy_v3_api_field_extensions.common.dynamic_forward_proxy.v3.DnsCacheConfig.preresolve_hostnames>` option to the DNS cache config. This option allows hostnames to be preresolved into the cache upon cache creation. This might provide performance improvement, in the form of cache hits, for hostnames that are going to be resolved during steady state and are known at config load time.
* dns resolver: added *DnsResolverOptions* protobuf message to reconcile all of the DNS lookup option flags. By setting the configuration option :ref:`use_tcp_for_dns_lookups <envoy_v3_api_field_config.core.v3.DnsResolverOptions.use_tcp_for_dns_lookups>` as true we can make the underlying dns resolver library to make only TCP queries to the DNS servers and by setting the configuration option :ref:`no_default_search_domain <envoy_v3_api_field_config.core.v3.DnsResolverOptions.no_default_search_domain>` as true the DNS resolver library will not use the default search domains.
* dns resolver: added *DnsResolutionConfig* to combine :ref:`dns_resolver_options <envoy_v3_api_field_config.core.v3.DnsResolutionConfig.dns_resolver_options>` and :ref:`resolvers <envoy_v3_api_field_config.core.v3.DnsResolutionConfig.resolvers>` in a single protobuf message. The field *resolvers* can be specified with a list of DNS resolver addresses. If specified, DNS client library will perform resolution via the underlying DNS resolvers. Otherwise, the default system resolvers (e.g., /etc/resolv.conf) will be used.
* dns_filter: added :ref:`dns_resolution_config <envoy_v3_api_field_extensions.filters.udp.dns_filter.v3alpha.DnsFilterConfig.ClientContextConfig.dns_resolution_config>` to aggregate all of the DNS resolver configuration in a single message. By setting the configuration option *use_tcp_for_dns_lookups* to true we can make dns filter's external resolvers to answer queries using TCP only, by setting the configuration option *no_default_search_domain* as true the DNS resolver will not use the default search domains. And by setting the configuration *resolvers* we can specify the external DNS servers to be used for external DNS query which replaces the pre-existing alpha api field *upstream_resolvers*.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,25 @@ DnsCacheImpl::DnsCacheImpl(
host_ttl_(PROTOBUF_GET_MS_OR_DEFAULT(config, host_ttl, 300000)),
max_hosts_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, max_hosts, 1024)) {
tls_slot_.set([&](Event::Dispatcher&) { return std::make_shared<ThreadLocalHostInfo>(*this); });

if (static_cast<size_t>(config.preresolve_hostnames().size()) > max_hosts_) {
throw EnvoyException(fmt::format(
"DNS Cache [{}] configured with preresolve_hostnames={} larger than max_hosts={}",
config.name(), config.preresolve_hostnames().size(), max_hosts_));
}

// Preresolved hostnames are resolved without a read lock on primary hosts because it is done
// during object construction.
for (const auto& hostname : config.preresolve_hostnames()) {
// No need to get a resolution handle on this resolution as the only outcome needed is for the
// 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.
main_thread_dispatcher_.post(
[this, host = hostname.address(), default_port = hostname.port_value()]() {
startCacheLoad(host, default_port);
});
}
}

DnsCacheImpl::~DnsCacheImpl() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,17 @@ namespace {

class DnsCacheImplTest : public testing::Test, public Event::TestUsingSimulatedTime {
public:
void initialize() {
void initialize(std::vector<std::string> preresolve_hostnames = {}, uint32_t max_hosts = 1024) {
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) {
envoy::config::core::v3::SocketAddress* address = config_.add_preresolve_hostnames();
address->set_address(hostname);
address->set_port_value(443);
}
}

EXPECT_CALL(dispatcher_, isThreadSafe).WillRepeatedly(Return(true));

Expand Down Expand Up @@ -98,6 +106,34 @@ MATCHER_P(CustomDnsResolversSizeEquals, expected_resolvers, "") {
return expected_resolvers.size() == arg.size();
}

TEST_F(DnsCacheImplTest, PreresolveSuccess) {
Network::DnsResolver::ResolveCb resolve_cb;
EXPECT_CALL(*resolver_, resolve("bar.baz.com", _, _))
.WillOnce(DoAll(SaveArg<2>(&resolve_cb), Return(&resolver_->active_query_)));
EXPECT_CALL(
update_callbacks_,
onDnsHostAddOrUpdate("bar.baz.com", DnsHostInfoEquals("10.0.0.1:443", "bar.baz.com", false)));

initialize({"bar.baz.com"} /* preresolve_hostnames */);

resolve_cb(Network::DnsResolver::ResolutionStatus::Success,
TestUtility::makeDnsResponse({"10.0.0.1"}));
checkStats(1 /* attempt */, 1 /* success */, 0 /* failure */, 1 /* address changed */,
1 /* added */, 0 /* removed */, 1 /* num hosts */);

MockLoadDnsCacheEntryCallbacks callbacks;
auto result = dns_cache_->loadDnsCacheEntry("bar.baz.com", 80, callbacks);
EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::InCache, result.status_);
EXPECT_EQ(result.handle_, nullptr);
EXPECT_NE(absl::nullopt, result.host_info_);
}

TEST_F(DnsCacheImplTest, PreresolveFailure) {
EXPECT_THROW_WITH_MESSAGE(
initialize({"bar.baz.com"} /* preresolve_hostnames */, 0 /* max_hosts */), EnvoyException,
"DNS Cache [foo] configured with preresolve_hostnames=1 larger than max_hosts=0");
}

// Basic successful resolution and then re-resolution.
TEST_F(DnsCacheImplTest, ResolveSuccess) {
initialize();
Expand Down Expand Up @@ -698,8 +734,7 @@ TEST_F(DnsCacheImplTest, InvalidPort) {

// Max host overflow.
TEST_F(DnsCacheImplTest, MaxHostOverflow) {
config_.mutable_max_hosts()->set_value(0);
initialize();
initialize({} /* preresolve_hostnames */, 0 /* max_hosts */);
InSequence s;

MockLoadDnsCacheEntryCallbacks callbacks;
Expand Down
2 changes: 2 additions & 0 deletions tools/spelling/spelling_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,8 @@ preorder
prepend
prepended
prepends
preresolve
preresolved
prev
probabilistically
proc
Expand Down