From 7dec55de5a876016f60c3e943b249ee504f8b44e Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Fri, 31 Mar 2023 13:52:06 -0700 Subject: [PATCH] [EventEngine] Implement the EventEngine-driven client channel resolver. (#32632) This PR also centralizes the client channel resolver selection. Resolver selection is still done using the plugin system, but when the Ares and native client channel resolvers go away, we can consider bootstrapping this differently. --- BUILD | 6 +- CMakeLists.txt | 6 + Makefile | 6 + build_autogenerated.yaml | 16 + config.m4 | 5 + config.w32 | 4 + gRPC-C++.podspec | 10 + gRPC-Core.podspec | 13 + grpc.gemspec | 8 + grpc.gyp | 6 + package.xml | 8 + src/core/BUILD | 86 ++- .../resolver/dns/c_ares/dns_resolver_ares.cc | 139 +---- .../resolver/dns/c_ares/dns_resolver_ares.h | 30 + .../resolver/dns/dns_resolver_plugin.cc | 60 ++ .../resolver/dns/dns_resolver_plugin.h | 27 + .../event_engine_client_channel_resolver.cc | 524 ++++++++++++++++++ .../event_engine_client_channel_resolver.h | 35 ++ .../dns/event_engine/service_config_helper.cc | 97 ++++ .../dns/event_engine/service_config_helper.h | 32 ++ .../resolver/dns/native/dns_resolver.cc | 15 +- .../resolver/dns/native/dns_resolver.h | 24 + src/core/lib/event_engine/trace.cc | 1 + src/core/lib/event_engine/trace.h | 6 + src/core/lib/experiments/experiments.cc | 3 + src/core/lib/experiments/experiments.h | 5 +- src/core/lib/experiments/experiments.yaml | 7 + .../plugin_registry/grpc_plugin_registry.cc | 6 +- src/python/grpcio/grpc_core_dependencies.py | 3 + test/cpp/naming/resolver_component_test.cc | 3 +- .../naming/resolver_component_tests_runner.py | 4 +- .../naming/resolver_test_record_groups.yaml | 6 +- tools/doxygen/Doxyfile.c++.internal | 8 + tools/doxygen/Doxyfile.core.internal | 8 + 34 files changed, 1069 insertions(+), 148 deletions(-) create mode 100644 src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h create mode 100644 src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc create mode 100644 src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h create mode 100644 src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc create mode 100644 src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h create mode 100644 src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc create mode 100644 src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h create mode 100644 src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h diff --git a/BUILD b/BUILD index e4ba2807a84..d01332e4bbf 100644 --- a/BUILD +++ b/BUILD @@ -783,6 +783,7 @@ grpc_cc_library( "//src/core:grpc_transport_chttp2_server", "//src/core:grpc_transport_inproc", "//src/core:grpc_fault_injection_filter", + "//src/core:grpc_resolver_dns_plugin", ], ) @@ -2952,6 +2953,7 @@ grpc_cc_library( "//src/core:ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc", ], hdrs = [ + "//src/core:ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h", "//src/core:ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h", "//src/core:ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h", ], @@ -2994,12 +2996,10 @@ grpc_cc_library( "//src/core:grpc_sockaddr", "//src/core:iomgr_fwd", "//src/core:iomgr_port", - "//src/core:json", - "//src/core:json_reader", - "//src/core:json_writer", "//src/core:polling_resolver", "//src/core:pollset_set", "//src/core:resolved_address", + "//src/core:service_config_helper", "//src/core:slice", "//src/core:status_helper", "//src/core:time", diff --git a/CMakeLists.txt b/CMakeLists.txt index e73bbf6c513..1890df768e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1775,6 +1775,9 @@ add_library(grpc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc + src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc + src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc @@ -2790,6 +2793,9 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc + src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc + src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc src/core/ext/filters/client_channel/resolver/polling_resolver.cc diff --git a/Makefile b/Makefile index 8196861a80e..303dce89f56 100644 --- a/Makefile +++ b/Makefile @@ -1010,6 +1010,9 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc \ + src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc \ + src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \ @@ -1879,6 +1882,9 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc \ + src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc \ + src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ src/core/ext/filters/client_channel/resolver/polling_resolver.cc \ diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 5e891d57dc6..f090139bd4a 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -371,8 +371,13 @@ libs: - src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h - src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h - src/core/ext/filters/client_channel/local_subchannel_pool.h + - src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h + - src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h + - src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h + - src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h + - src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h - src/core/ext/filters/client_channel/resolver/polling_resolver.h - src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h @@ -1165,6 +1170,9 @@ libs: - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc + - src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc + - src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc + - src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc - src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc - src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc @@ -2048,8 +2056,13 @@ libs: - src/core/ext/filters/client_channel/lb_policy/subchannel_list.h - src/core/ext/filters/client_channel/lb_policy/weighted_round_robin/static_stride_scheduler.h - src/core/ext/filters/client_channel/local_subchannel_pool.h + - src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h + - src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h + - src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h + - src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h + - src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h - src/core/ext/filters/client_channel/resolver/polling_resolver.h - src/core/ext/filters/client_channel/retry_filter.h @@ -2452,6 +2465,9 @@ libs: - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc + - src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc + - src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc + - src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc - src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc - src/core/ext/filters/client_channel/resolver/polling_resolver.cc diff --git a/config.m4 b/config.m4 index f6f6798832b..50cee4fc2f4 100644 --- a/config.m4 +++ b/config.m4 @@ -89,6 +89,9 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc \ + src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc \ + src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \ @@ -1297,7 +1300,9 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/xds) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/binder) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/c_ares) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/event_engine) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/native) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/fake) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/google_c2p) diff --git a/config.w32 b/config.w32 index c9008c9af32..8b46db51c86 100644 --- a/config.w32 +++ b/config.w32 @@ -55,6 +55,9 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_posix.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_windows.cc " + + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\dns_resolver_plugin.cc " + + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\event_engine\\event_engine_client_channel_resolver.cc " + + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\event_engine\\service_config_helper.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native\\dns_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\google_c2p\\google_c2p_resolver.cc " + @@ -1297,6 +1300,7 @@ if (PHP_GRPC != "no") { FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\binder"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares"); + FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\event_engine"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\fake"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\google_c2p"); diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index e5cfa4bce99..e4619ca1147 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -276,8 +276,13 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h', 'src/core/ext/filters/client_channel/local_subchannel_pool.h', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h', + 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', @@ -1234,8 +1239,13 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h', 'src/core/ext/filters/client_channel/local_subchannel_pool.h', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h', + 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index c35d1f9317f..30a81414fac 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -287,6 +287,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/local_subchannel_pool.h', 'src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', @@ -294,7 +295,14 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc', @@ -1944,8 +1952,13 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h', 'src/core/ext/filters/client_channel/local_subchannel_pool.h', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h', + 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', diff --git a/grpc.gemspec b/grpc.gemspec index 91a8da2964f..a73f1bfc65c 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -194,6 +194,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/local_subchannel_pool.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc ) @@ -201,7 +202,14 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc ) diff --git a/grpc.gyp b/grpc.gyp index e6410454c7b..056ee50ae24 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -425,6 +425,9 @@ 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc', @@ -1235,6 +1238,9 @@ 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/resolver/polling_resolver.cc', diff --git a/package.xml b/package.xml index bdf6045729d..18cacf2ebb8 100644 --- a/package.xml +++ b/package.xml @@ -176,6 +176,7 @@ + @@ -183,7 +184,14 @@ + + + + + + + diff --git a/src/core/BUILD b/src/core/BUILD index f77f59c2237..e3bf05011a9 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -4890,11 +4890,96 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "service_config_helper", + srcs = ["ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc"], + hdrs = ["ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h"], + external_deps = [ + "absl/status:statusor", + "absl/strings", + ], + language = "c++", + deps = [ + "json", + "json_args", + "json_object_loader", + "json_reader", + "json_writer", + "status_helper", + "//:gpr_platform", + "//:grpc_base", + ], +) + +grpc_cc_library( + name = "grpc_resolver_dns_event_engine", + srcs = ["ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc"], + hdrs = ["ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h"], + external_deps = [ + "absl/base:core_headers", + "absl/cleanup", + "absl/container:flat_hash_set", + "absl/status", + "absl/status:statusor", + "absl/strings", + "absl/types:optional", + ], + language = "c++", + deps = [ + "channel_args", + "event_engine_common", + "event_engine_utils", + "grpc_service_config", + "polling_resolver", + "service_config_helper", + "time", + "validation_errors", + "//:backoff", + "//:debug_location", + "//:gpr", + "//:gpr_platform", + "//:grpc_base", + "//:grpc_grpclb_balancer_addresses", + "//:grpc_resolver", + "//:grpc_service_config_impl", + "//:grpc_trace", + "//:orphanable", + "//:ref_counted_ptr", + "//:server_address", + "//:uri_parser", + ], +) + +grpc_cc_library( + name = "grpc_resolver_dns_plugin", + srcs = [ + "ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc", + ], + hdrs = [ + "ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h", + ], + external_deps = ["absl/strings"], + language = "c++", + deps = [ + "experiments", + "grpc_resolver_dns_event_engine", + "grpc_resolver_dns_native", + "//:config", + "//:config_vars", + "//:gpr", + "//:grpc_resolver", + "//:grpc_resolver_dns_ares", + ], +) + grpc_cc_library( name = "grpc_resolver_dns_native", srcs = [ "ext/filters/client_channel/resolver/dns/native/dns_resolver.cc", ], + hdrs = [ + "ext/filters/client_channel/resolver/dns/native/dns_resolver.h", + ], external_deps = [ "absl/functional:bind_front", "absl/status", @@ -4910,7 +4995,6 @@ grpc_cc_library( "time", "//:backoff", "//:config", - "//:config_vars", "//:debug_location", "//:gpr", "//:grpc_base", diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index 4a264dad400..6838ea58a9e 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -17,11 +17,9 @@ #include #include -#include #include #include -#include #include #include #include @@ -40,6 +38,7 @@ #include #include +#include "src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h" #include "src/core/lib/config/core_configuration.h" #include "src/core/lib/debug/trace.h" #include "src/core/lib/gprpp/debug_location.h" @@ -60,8 +59,6 @@ #if GRPC_ARES == 1 -#include - #include #include "absl/container/flat_hash_set.h" @@ -74,11 +71,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/config/config_vars.h" #include "src/core/lib/event_engine/handle_containers.h" -#include "src/core/lib/iomgr/gethostname.h" #include "src/core/lib/iomgr/resolve_address.h" -#include "src/core/lib/json/json.h" -#include "src/core/lib/json/json_reader.h" -#include "src/core/lib/json/json_writer.h" #include "src/core/lib/resolver/server_address.h" #include "src/core/lib/service_config/service_config_impl.h" #include "src/core/lib/transport/error_utils.h" @@ -237,97 +230,6 @@ OrphanablePtr AresClientChannelDNSResolver::StartRequest() { Ref(DEBUG_LOCATION, "dns-resolving")); } -bool ValueInJsonArray(const Json::Array& array, const char* value) { - for (const Json& entry : array) { - if (entry.type() == Json::Type::kString && entry.string() == value) { - return true; - } - } - return false; -} - -std::string ChooseServiceConfig(char* service_config_choice_json, - grpc_error_handle* error) { - auto json = JsonParse(service_config_choice_json); - if (!json.ok()) { - *error = absl_status_to_grpc_error(json.status()); - return ""; - } - if (json->type() != Json::Type::kArray) { - *error = GRPC_ERROR_CREATE( - "Service Config Choices, error: should be of type array"); - return ""; - } - const Json* service_config = nullptr; - std::vector error_list; - for (const Json& choice : json->array()) { - if (choice.type() != Json::Type::kObject) { - error_list.push_back(GRPC_ERROR_CREATE( - "Service Config Choice, error: should be of type object")); - continue; - } - // Check client language, if specified. - auto it = choice.object().find("clientLanguage"); - if (it != choice.object().end()) { - if (it->second.type() != Json::Type::kArray) { - error_list.push_back(GRPC_ERROR_CREATE( - "field:clientLanguage error:should be of type array")); - } else if (!ValueInJsonArray(it->second.array(), "c++")) { - continue; - } - } - // Check client hostname, if specified. - it = choice.object().find("clientHostname"); - if (it != choice.object().end()) { - if (it->second.type() != Json::Type::kArray) { - error_list.push_back(GRPC_ERROR_CREATE( - "field:clientHostname error:should be of type array")); - } else { - char* hostname = grpc_gethostname(); - if (hostname == nullptr || - !ValueInJsonArray(it->second.array(), hostname)) { - continue; - } - } - } - // Check percentage, if specified. - it = choice.object().find("percentage"); - if (it != choice.object().end()) { - if (it->second.type() != Json::Type::kNumber) { - error_list.push_back(GRPC_ERROR_CREATE( - "field:percentage error:should be of type number")); - } else { - int random_pct = rand() % 100; - int percentage; - if (sscanf(it->second.string().c_str(), "%d", &percentage) != 1) { - error_list.push_back(GRPC_ERROR_CREATE( - "field:percentage error:should be of type integer")); - } else if (random_pct > percentage || percentage == 0) { - continue; - } - } - } - // Found service config. - it = choice.object().find("serviceConfig"); - if (it == choice.object().end()) { - error_list.push_back(GRPC_ERROR_CREATE( - "field:serviceConfig error:required field missing")); - } else if (it->second.type() != Json::Type::kObject) { - error_list.push_back(GRPC_ERROR_CREATE( - "field:serviceConfig error:should be of type object")); - } else if (service_config == nullptr) { - service_config = &it->second; - } - } - if (!error_list.empty()) { - service_config = nullptr; - *error = GRPC_ERROR_CREATE_FROM_VECTOR("Service Config Choices Parser", - &error_list); - } - if (service_config == nullptr) return ""; - return JsonDump(*service_config); -} - void AresClientChannelDNSResolver::AresRequestWrapper::OnHostnameResolved( void* arg, grpc_error_handle error) { auto* self = static_cast(arg); @@ -402,18 +304,16 @@ AresClientChannelDNSResolver::AresRequestWrapper::OnResolvedLocked( result.addresses = ServerAddressList(); } if (service_config_json_ != nullptr) { - grpc_error_handle service_config_error; - std::string service_config_string = - ChooseServiceConfig(service_config_json_, &service_config_error); - if (!service_config_error.ok()) { + auto service_config_string = ChooseServiceConfig(service_config_json_); + if (!service_config_string.ok()) { result.service_config = absl::UnavailableError( absl::StrCat("failed to parse service config: ", - StatusToString(service_config_error))); - } else if (!service_config_string.empty()) { + StatusToString(service_config_string.status()))); + } else if (!service_config_string->empty()) { GRPC_CARES_TRACE_LOG("resolver:%p selected service config choice: %s", - this, service_config_string.c_str()); + this, service_config_string->c_str()); result.service_config = ServiceConfigImpl::Create( - resolver_->channel_args(), service_config_string); + resolver_->channel_args(), *service_config_string); if (!result.service_config.ok()) { result.service_config = absl::UnavailableError( absl::StrCat("failed to parse service config: ", @@ -811,27 +711,22 @@ class AresDNSResolver : public DNSResolver { intptr_t aba_token_ ABSL_GUARDED_BY(mu_) = 0; }; -bool ShouldUseAres(absl::string_view resolver_env) { - return resolver_env.empty() || absl::EqualsIgnoreCase(resolver_env, "ares"); -} +} // namespace -bool UseAresDnsResolver() { - return ShouldUseAres(ConfigVars::Get().DnsResolver()); +bool ShouldUseAresDnsResolver(absl::string_view resolver_env) { + return resolver_env.empty() || absl::EqualsIgnoreCase(resolver_env, "ares"); } -} // namespace - void RegisterAresDnsResolver(CoreConfiguration::Builder* builder) { - if (UseAresDnsResolver()) { - builder->resolver_registry()->RegisterResolverFactory( - std::make_unique()); - } + builder->resolver_registry()->RegisterResolverFactory( + std::make_unique()); } } // namespace grpc_core void grpc_resolver_dns_ares_init() { - if (grpc_core::UseAresDnsResolver()) { + if (grpc_core::ShouldUseAresDnsResolver( + grpc_core::ConfigVars::Get().DnsResolver())) { address_sorting_init(); grpc_error_handle error = grpc_ares_init(); if (!error.ok()) { @@ -843,7 +738,8 @@ void grpc_resolver_dns_ares_init() { } void grpc_resolver_dns_ares_shutdown() { - if (grpc_core::UseAresDnsResolver()) { + if (grpc_core::ShouldUseAresDnsResolver( + grpc_core::ConfigVars::Get().DnsResolver())) { address_sorting_shutdown(); grpc_ares_cleanup(); } @@ -852,6 +748,9 @@ void grpc_resolver_dns_ares_shutdown() { #else // GRPC_ARES == 1 namespace grpc_core { +bool ShouldUseAresDnsResolver(absl::string_view /* resolver_env */) { + return false; +} void RegisterAresDnsResolver(CoreConfiguration::Builder*) {} } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h new file mode 100644 index 00000000000..5b80fe5db40 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h @@ -0,0 +1,30 @@ +// Copyright 2022 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_DNS_RESOLVER_ARES_H +#define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_DNS_RESOLVER_ARES_H + +#include + +#include "absl/strings/string_view.h" + +#include "src/core/lib/config/core_configuration.h" + +namespace grpc_core { + +bool ShouldUseAresDnsResolver(absl::string_view resolver_env); +void RegisterAresDnsResolver(CoreConfiguration::Builder*); + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_DNS_RESOLVER_ARES_H diff --git a/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc b/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc new file mode 100644 index 00000000000..5aec267e2a0 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc @@ -0,0 +1,60 @@ +// Copyright 2022 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include + +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h" + +#include + +#include "absl/strings/match.h" + +#include + +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h" +#include "src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h" +#include "src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h" +#include "src/core/lib/config/config_vars.h" +#include "src/core/lib/experiments/experiments.h" +#include "src/core/lib/gprpp/crash.h" +#include "src/core/lib/resolver/resolver_factory.h" + +namespace grpc_core { + +void RegisterDnsResolver(CoreConfiguration::Builder* builder) { + if (IsEventEngineDnsEnabled()) { + gpr_log(GPR_DEBUG, "Using EventEngine dns resolver"); + builder->resolver_registry()->RegisterResolverFactory( + std::make_unique()); + return; + } + auto resolver = ConfigVars::Get().DnsResolver(); + // ---- Ares resolver ---- + if (ShouldUseAresDnsResolver(resolver)) { + gpr_log(GPR_DEBUG, "Using ares dns resolver"); + RegisterAresDnsResolver(builder); + return; + } + // ---- Native resolver ---- + if (absl::EqualsIgnoreCase(resolver, "native") || + !builder->resolver_registry()->HasResolverFactory("dns")) { + gpr_log(GPR_DEBUG, "Using native dns resolver"); + RegisterNativeDnsResolver(builder); + return; + } + Crash( + "Unable to set DNS resolver! Likely a logic error in gRPC-core, " + "please file a bug."); +} + +} // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h b/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h new file mode 100644 index 00000000000..97318f12c6c --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h @@ -0,0 +1,27 @@ +// Copyright 2022 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_DNS_RESOLVER_PLUGIN_H +#define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_DNS_RESOLVER_PLUGIN_H +#include + +#include "src/core/lib/config/core_configuration.h" + +namespace grpc_core { + +// Centralized decision logic about which client channel DNS resolver to enable. +void RegisterDnsResolver(CoreConfiguration::Builder* builder); + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_DNS_RESOLVER_PLUGIN_H diff --git a/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc new file mode 100644 index 00000000000..78bb58438bb --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc @@ -0,0 +1,524 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include + +#include "src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/cleanup/cleanup.h" +#include "absl/container/flat_hash_set.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/strip.h" +#include "absl/types/optional.h" + +#include +#include +#include + +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h" +#include "src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h" +#include "src/core/ext/filters/client_channel/resolver/polling_resolver.h" +#include "src/core/lib/backoff/backoff.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/event_engine/handle_containers.h" +#include "src/core/lib/event_engine/resolved_address_internal.h" +#include "src/core/lib/event_engine/utils.h" +#include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/gprpp/sync.h" +#include "src/core/lib/gprpp/time.h" +#include "src/core/lib/gprpp/validation_errors.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/resolver/resolver.h" +#include "src/core/lib/resolver/resolver_factory.h" +#include "src/core/lib/resolver/server_address.h" +#include "src/core/lib/service_config/service_config.h" +#include "src/core/lib/service_config/service_config_impl.h" + +// IWYU pragma: no_include + +namespace grpc_core { +namespace { + +#define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1 +#define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6 +#define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120 +#define GRPC_DNS_RECONNECT_JITTER 0.2 +#define GRPC_DNS_DEFAULT_QUERY_TIMEOUT_MS 120000 + +using grpc_event_engine::experimental::EventEngine; +using grpc_event_engine::experimental::HandleToString; +using grpc_event_engine::experimental::LookupTaskHandleSet; + +// TODO(hork): Investigate adding a resolver test scenario where the first +// balancer hostname lookup result is an error, and the second contains valid +// addresses. +// TODO(hork): Add a test that checks for proper authority from balancer +// addresses. + +// TODO(hork): replace this with `dns_resolver` when all other resolver +// implementations are removed. +TraceFlag grpc_event_engine_client_channel_resolver_trace( + false, "event_engine_client_channel_resolver"); + +#define GRPC_EVENT_ENGINE_RESOLVER_TRACE(format, ...) \ + if (GRPC_TRACE_FLAG_ENABLED( \ + grpc_event_engine_client_channel_resolver_trace)) { \ + gpr_log(GPR_DEBUG, "(event_engine client channel resolver) " format, \ + __VA_ARGS__); \ + } + +// ---------------------------------------------------------------------------- +// EventEngineClientChannelDNSResolver +// ---------------------------------------------------------------------------- +class EventEngineClientChannelDNSResolver : public PollingResolver { + public: + EventEngineClientChannelDNSResolver(ResolverArgs args, + Duration min_time_between_resolutions); + OrphanablePtr StartRequest() override; + + private: + // ---------------------------------------------------------------------------- + // EventEngineDNSRequestWrapper declaration + // ---------------------------------------------------------------------------- + class EventEngineDNSRequestWrapper + : public InternallyRefCounted { + public: + EventEngineDNSRequestWrapper( + RefCountedPtr resolver, + std::unique_ptr event_engine_resolver); + ~EventEngineDNSRequestWrapper() override; + + // Note that thread safety cannot be analyzed due to this being invoked from + // OrphanablePtr<>, and there's no way to pass the lock annotation through + // there. + void Orphan() override ABSL_NO_THREAD_SAFETY_ANALYSIS; + + private: + void OnHostnameResolved( + absl::StatusOr> addresses); + void OnSRVResolved( + absl::StatusOr> + srv_records); + void OnBalancerHostnamesResolved( + std::string authority, + absl::StatusOr> addresses); + void OnTXTResolved(absl::StatusOr service_config); + // Returns a Result if resolution is complete. + // callers must release the lock and call OnRequestComplete if a Result is + // returned. This is because OnRequestComplete may Orphan the resolver, + // which requires taking the lock. + absl::optional OnResolvedLocked() + ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_); + // Helper method to populate server addresses on resolver result. + void MaybePopulateAddressesLocked(Resolver::Result* result) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_); + // Helper method to populate balancer addresses on resolver result. + void MaybePopulateBalancerAddressesLocked(Resolver::Result* result) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_); + // Helper method to populate service config on resolver result. + void MaybePopulateServiceConfigLocked(Resolver::Result* result) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_); + + RefCountedPtr resolver_; + Mutex on_resolved_mu_; + // Lookup callbacks + absl::optional hostname_handle_ + ABSL_GUARDED_BY(on_resolved_mu_); + absl::optional srv_handle_ + ABSL_GUARDED_BY(on_resolved_mu_); + absl::optional txt_handle_ + ABSL_GUARDED_BY(on_resolved_mu_); + LookupTaskHandleSet balancer_hostname_handles_ + ABSL_GUARDED_BY(on_resolved_mu_); + // Output fields from requests. + ServerAddressList addresses_ ABSL_GUARDED_BY(on_resolved_mu_); + ServerAddressList balancer_addresses_ ABSL_GUARDED_BY(on_resolved_mu_); + ValidationErrors errors_ ABSL_GUARDED_BY(on_resolved_mu_); + absl::StatusOr service_config_json_ + ABSL_GUARDED_BY(on_resolved_mu_); + // Other internal state + size_t number_of_balancer_hostnames_resolved_ + ABSL_GUARDED_BY(on_resolved_mu_) = 0; + bool orphaned_ ABSL_GUARDED_BY(on_resolved_mu_) = false; + std::unique_ptr event_engine_resolver_; + }; + + /// whether to request the service config + const bool request_service_config_; + // whether or not to enable SRV DNS queries + const bool enable_srv_queries_; + // timeout in milliseconds for active DNS queries + EventEngine::Duration query_timeout_ms_; + std::shared_ptr event_engine_; +}; + +EventEngineClientChannelDNSResolver::EventEngineClientChannelDNSResolver( + ResolverArgs args, Duration min_time_between_resolutions) + : PollingResolver(std::move(args), min_time_between_resolutions, + BackOff::Options() + .set_initial_backoff(Duration::Milliseconds( + GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000)) + .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER) + .set_jitter(GRPC_DNS_RECONNECT_JITTER) + .set_max_backoff(Duration::Milliseconds( + GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)), + &grpc_event_engine_client_channel_resolver_trace), + request_service_config_( + !channel_args() + .GetBool(GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION) + .value_or(true)), + enable_srv_queries_(channel_args() + .GetBool(GRPC_ARG_DNS_ENABLE_SRV_QUERIES) + .value_or(false)), + // TODO(yijiem): decide if the ares channel arg timeout should be reused. + query_timeout_ms_(std::chrono::milliseconds( + std::max(0, channel_args() + .GetInt(GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS) + .value_or(GRPC_DNS_DEFAULT_QUERY_TIMEOUT_MS)))), + event_engine_(channel_args().GetObjectRef()) {} + +OrphanablePtr EventEngineClientChannelDNSResolver::StartRequest() { + return MakeOrphanable( + Ref(DEBUG_LOCATION, "dns-resolving"), + event_engine_->GetDNSResolver({/*dns_server=*/authority()})); +} + +// ---------------------------------------------------------------------------- +// EventEngineDNSRequestWrapper definition +// ---------------------------------------------------------------------------- + +EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + EventEngineDNSRequestWrapper( + RefCountedPtr resolver, + std::unique_ptr event_engine_resolver) + : resolver_(std::move(resolver)), + event_engine_resolver_(std::move(event_engine_resolver)) { + // Locking to prevent completion before all records are queried + MutexLock lock(&on_resolved_mu_); + GRPC_EVENT_ENGINE_RESOLVER_TRACE( + "DNSResolver::%p Starting hostname resolution for %s", resolver_.get(), + resolver_->name_to_resolve().c_str()); + hostname_handle_ = event_engine_resolver_->LookupHostname( + [self = Ref(DEBUG_LOCATION, "OnHostnameResolved")]( + absl::StatusOr> addresses) { + self->OnHostnameResolved(std::move(addresses)); + }, + resolver_->name_to_resolve(), kDefaultSecurePort, + resolver_->query_timeout_ms_); + GRPC_EVENT_ENGINE_RESOLVER_TRACE("hostname lookup handle: %s", + HandleToString(*hostname_handle_).c_str()); + if (resolver_->enable_srv_queries_) { + GRPC_EVENT_ENGINE_RESOLVER_TRACE( + "DNSResolver::%p Starting SRV record resolution for %s", + resolver_.get(), resolver_->name_to_resolve().c_str()); + srv_handle_ = event_engine_resolver_->LookupSRV( + [self = Ref(DEBUG_LOCATION, "OnSRVResolved")]( + absl::StatusOr> + srv_records) { self->OnSRVResolved(std::move(srv_records)); }, + resolver_->name_to_resolve(), resolver_->query_timeout_ms_); + GRPC_EVENT_ENGINE_RESOLVER_TRACE("srv lookup handle: %s", + HandleToString(*srv_handle_).c_str()); + } + if (resolver_->request_service_config_) { + GRPC_EVENT_ENGINE_RESOLVER_TRACE( + "DNSResolver::%p Starting TXT record resolution for %s", + resolver_.get(), resolver_->name_to_resolve().c_str()); + txt_handle_ = event_engine_resolver_->LookupTXT( + [self = Ref(DEBUG_LOCATION, "OnTXTResolved")]( + absl::StatusOr service_config) { + self->OnTXTResolved(std::move(service_config)); + }, + absl::StrCat("_grpc_config.", resolver_->name_to_resolve()), + resolver_->query_timeout_ms_); + GRPC_EVENT_ENGINE_RESOLVER_TRACE("txt lookup handle: %s", + HandleToString(*txt_handle_).c_str()); + } +} + +EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + ~EventEngineDNSRequestWrapper() { + resolver_.reset(DEBUG_LOCATION, "dns-resolving"); +} + +void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + Orphan() { + { + MutexLock lock(&on_resolved_mu_); + orphaned_ = true; + // Event if cancellation fails here, OnResolvedLocked will return early, and + // the resolver will never see a completed request. + if (hostname_handle_.has_value()) { + event_engine_resolver_->CancelLookup(*hostname_handle_); + } + if (srv_handle_.has_value()) { + event_engine_resolver_->CancelLookup(*srv_handle_); + } + for (const auto& handle : balancer_hostname_handles_) { + event_engine_resolver_->CancelLookup(handle); + } + if (txt_handle_.has_value()) { + event_engine_resolver_->CancelLookup(*txt_handle_); + } + } + Unref(DEBUG_LOCATION, "Orphan"); +} + +void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + OnHostnameResolved(absl::StatusOr> + new_addresses) { + ValidationErrors::ScopedField field(&errors_, "hostname lookup"); + absl::optional result; + { + MutexLock lock(&on_resolved_mu_); + if (orphaned_) return; + hostname_handle_.reset(); + if (!new_addresses.ok()) { + errors_.AddError(new_addresses.status().message()); + } else { + addresses_.reserve(addresses_.size() + new_addresses->size()); + for (const auto& addr : *new_addresses) { + addresses_.emplace_back(CreateGRPCResolvedAddress(addr), ChannelArgs()); + } + } + result = OnResolvedLocked(); + } + if (result.has_value()) { + resolver_->OnRequestComplete(std::move(*result)); + } +} + +void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + OnSRVResolved( + absl::StatusOr> + srv_records) { + ValidationErrors::ScopedField field(&errors_, "srv lookup"); + absl::optional result; + auto cleanup = absl::MakeCleanup([&]() { + if (result.has_value()) { + resolver_->OnRequestComplete(std::move(*result)); + } + }); + MutexLock lock(&on_resolved_mu_); + if (orphaned_) return; + srv_handle_.reset(); + if (!srv_records.ok()) { + // An error has occurred, finish resolving. + errors_.AddError(srv_records.status().message()); + result = OnResolvedLocked(); + return; + } + // Do a subsequent hostname query since SRV records were returned + for (auto& srv_record : *srv_records) { + GRPC_EVENT_ENGINE_RESOLVER_TRACE( + "DNSResolver::%p Starting balancer hostname resolution for %s:%d", + resolver_.get(), srv_record.host.c_str(), srv_record.port); + auto handle = event_engine_resolver_->LookupHostname( + [host = std::move(srv_record.host), + self = Ref(DEBUG_LOCATION, "OnBalancerHostnamesResolved")]( + absl::StatusOr> + new_balancer_addresses) mutable { + self->OnBalancerHostnamesResolved(std::move(host), + std::move(new_balancer_addresses)); + }, + srv_record.host, std::to_string(srv_record.port), + resolver_->query_timeout_ms_); + GRPC_EVENT_ENGINE_RESOLVER_TRACE("balancer hostname lookup handle: %s", + HandleToString(handle).c_str()); + balancer_hostname_handles_.insert(handle); + } +} + +void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + OnBalancerHostnamesResolved( + std::string authority, + absl::StatusOr> + new_balancer_addresses) { + ValidationErrors::ScopedField field( + &errors_, absl::StrCat("balancer lookup for ", authority)); + absl::optional result; + auto cleanup = absl::MakeCleanup([&]() { + if (result.has_value()) { + resolver_->OnRequestComplete(std::move(*result)); + } + }); + MutexLock lock(&on_resolved_mu_); + if (orphaned_) return; + ++number_of_balancer_hostnames_resolved_; + if (!new_balancer_addresses.ok()) { + // An error has occurred, finish resolving. + errors_.AddError(new_balancer_addresses.status().message()); + } else { + // Capture the addresses and finish resolving. + balancer_addresses_.reserve(balancer_addresses_.size() + + new_balancer_addresses->size()); + auto srv_channel_args = + ChannelArgs().Set(GRPC_ARG_DEFAULT_AUTHORITY, authority); + for (const auto& addr : *new_balancer_addresses) { + balancer_addresses_.emplace_back(CreateGRPCResolvedAddress(addr), + srv_channel_args); + } + } + result = OnResolvedLocked(); +} + +void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + OnTXTResolved(absl::StatusOr service_config) { + ValidationErrors::ScopedField field(&errors_, "txt lookup"); + absl::optional result; + { + MutexLock lock(&on_resolved_mu_); + if (orphaned_) return; + GPR_ASSERT(txt_handle_.has_value()); + txt_handle_.reset(); + if (!service_config.ok()) { + errors_.AddError(service_config.status().message()); + service_config_json_ = service_config.status(); + } else { + service_config_json_ = absl::StrCat("grpc_config=", *service_config); + } + result = OnResolvedLocked(); + } + if (result.has_value()) { + resolver_->OnRequestComplete(std::move(*result)); + } +} + +void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + MaybePopulateAddressesLocked(Resolver::Result* result) { + if (addresses_.empty()) return; + result->addresses = std::move(addresses_); +} + +void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + MaybePopulateBalancerAddressesLocked(Resolver::Result* result) { + if (!balancer_addresses_.empty()) { + result->args = + SetGrpcLbBalancerAddresses(result->args, balancer_addresses_); + } +} + +void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: + MaybePopulateServiceConfigLocked(Resolver::Result* result) { + // This function is called only if we are returning addresses. In that case, + // we currently ignore TXT lookup failures. + // TODO(roth): Consider differentiating between NXDOMAIN and other failures, + // so that we can return an error in the non-NXDOMAIN case. + if (!service_config_json_.ok()) return; + // TXT lookup succeeded, so parse the config. + auto service_config = ChooseServiceConfig(*service_config_json_); + if (!service_config.ok()) { + result->service_config = absl::UnavailableError(absl::StrCat( + "failed to parse service config: ", service_config.status().message())); + return; + } + if (service_config->empty()) return; + GRPC_EVENT_ENGINE_RESOLVER_TRACE( + "DNSResolver::%p selected service config choice: %s", + event_engine_resolver_.get(), service_config->c_str()); + result->service_config = + ServiceConfigImpl::Create(resolver_->channel_args(), *service_config); + if (!result->service_config.ok()) { + result->service_config = absl::UnavailableError( + absl::StrCat("failed to parse service config: ", + result->service_config.status().message())); + } +} + +absl::optional EventEngineClientChannelDNSResolver:: + EventEngineDNSRequestWrapper::OnResolvedLocked() { + if (orphaned_) return absl::nullopt; + // Wait for all requested queries to return. + if (hostname_handle_.has_value() || srv_handle_.has_value() || + txt_handle_.has_value() || + number_of_balancer_hostnames_resolved_ != + balancer_hostname_handles_.size()) { + GRPC_EVENT_ENGINE_RESOLVER_TRACE( + "DNSResolver::%p OnResolved() waiting for results (hostname: %s, " + "srv: %s, " + "txt: %s, " + "balancer addresses: %" PRIuPTR "/%" PRIuPTR " complete", + this, hostname_handle_.has_value() ? "waiting" : "done", + srv_handle_.has_value() ? "waiting" : "done", + txt_handle_.has_value() ? "waiting" : "done", + number_of_balancer_hostnames_resolved_, + balancer_hostname_handles_.size()); + return absl::nullopt; + } + GRPC_EVENT_ENGINE_RESOLVER_TRACE( + "DNSResolver::%p OnResolvedLocked() proceeding", this); + Resolver::Result result; + result.args = resolver_->channel_args(); + // If both addresses and balancer addresses failed, return an error for both + // addresses and service config. + if (addresses_.empty() && balancer_addresses_.empty()) { + absl::Status status = errors_.status( + absl::StatusCode::kUnavailable, + absl::StrCat("errors resolving ", resolver_->name_to_resolve())); + GRPC_EVENT_ENGINE_RESOLVER_TRACE("%s", status.message().data()); + result.addresses = status; + result.service_config = status; + return std::move(result); + } + if (!errors_.ok()) { + result.resolution_note = errors_.message( + absl::StrCat("errors resolving ", resolver_->name_to_resolve())); + } + // We have at least one of addresses or balancer addresses, so we're going to + // return a non-error for addresses. + result.addresses.emplace(); + MaybePopulateAddressesLocked(&result); + MaybePopulateServiceConfigLocked(&result); + MaybePopulateBalancerAddressesLocked(&result); + return std::move(result); +} + +} // namespace + +bool EventEngineClientChannelDNSResolverFactory::IsValidUri( + const URI& uri) const { + if (absl::StripPrefix(uri.path(), "/").empty()) { + gpr_log(GPR_ERROR, "no server name supplied in dns URI"); + return false; + } + return true; +} + +OrphanablePtr +EventEngineClientChannelDNSResolverFactory::CreateResolver( + ResolverArgs args) const { + Duration min_time_between_resolutions = std::max( + Duration::Zero(), args.args + .GetDurationFromIntMillis( + GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS) + .value_or(Duration::Seconds(30))); + return MakeOrphanable( + std::move(args), min_time_between_resolutions); +} + +} // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h b/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h new file mode 100644 index 00000000000..665b4781787 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h @@ -0,0 +1,35 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_EVENT_ENGINE_EVENT_ENGINE_CLIENT_CHANNEL_RESOLVER_H +#define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_EVENT_ENGINE_EVENT_ENGINE_CLIENT_CHANNEL_RESOLVER_H +#include + +#include "absl/strings/string_view.h" + +#include "src/core/lib/gprpp/orphanable.h" +#include "src/core/lib/resolver/resolver.h" +#include "src/core/lib/resolver/resolver_factory.h" +#include "src/core/lib/uri/uri_parser.h" + +namespace grpc_core { +class EventEngineClientChannelDNSResolverFactory : public ResolverFactory { + public: + absl::string_view scheme() const override { return "dns"; } + bool IsValidUri(const URI& uri) const override; + OrphanablePtr CreateResolver(ResolverArgs args) const override; +}; + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_EVENT_ENGINE_EVENT_ENGINE_CLIENT_CHANNEL_RESOLVER_H diff --git a/src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc b/src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc new file mode 100644 index 00000000000..1f6e2a33f95 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc @@ -0,0 +1,97 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include + +#include "src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h" + +#include + +#include +#include + +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" + +#include "src/core/lib/gprpp/status_helper.h" +#include "src/core/lib/iomgr/gethostname.h" +#include "src/core/lib/json/json.h" +#include "src/core/lib/json/json_args.h" +#include "src/core/lib/json/json_object_loader.h" +#include "src/core/lib/json/json_reader.h" +#include "src/core/lib/json/json_writer.h" + +namespace grpc_core { + +namespace { + +struct ServiceConfigChoice { + std::vector client_language; + int percentage = -1; + std::vector client_hostname; + Json::Object service_config; + + static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { + static const auto* loader = + JsonObjectLoader() + .OptionalField("clientLanguage", + &ServiceConfigChoice::client_language) + .OptionalField("percentage", &ServiceConfigChoice::percentage) + .OptionalField("clientHostname", + &ServiceConfigChoice::client_hostname) + .Field("serviceConfig", &ServiceConfigChoice::service_config) + .Finish(); + return loader; + } +}; + +bool vector_contains(const std::vector& v, + const std::string& value) { + return std::find(v.begin(), v.end(), value) != v.end(); +} + +} // namespace + +absl::StatusOr ChooseServiceConfig( + absl::string_view service_config_json) { + auto json = JsonParse(service_config_json); + GRPC_RETURN_IF_ERROR(json.status()); + auto choices = LoadFromJson>(*json); + GRPC_RETURN_IF_ERROR(choices.status()); + for (const ServiceConfigChoice& choice : *choices) { + // Check client language, if specified. + if (!choice.client_language.empty() && + !vector_contains(choice.client_language, "c++")) { + continue; + } + // Check client hostname, if specified. + if (!choice.client_hostname.empty()) { + const char* hostname = grpc_gethostname(); + if (!vector_contains(choice.client_hostname, hostname)) { + continue; + } + } + // Check percentage, if specified. + if (choice.percentage != -1) { + int random_pct = rand() % 100; + if (random_pct > choice.percentage || choice.percentage == 0) { + continue; + } + } + return JsonDump(choice.service_config); + } + // No matching service config was found + return ""; +} + +} // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h b/src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h new file mode 100644 index 00000000000..cbb7f5e9aa6 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h @@ -0,0 +1,32 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_EVENT_ENGINE_SERVICE_CONFIG_HELPER_H +#define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_EVENT_ENGINE_SERVICE_CONFIG_HELPER_H + +#include + +#include + +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" + +namespace grpc_core { + +absl::StatusOr ChooseServiceConfig( + absl::string_view service_config_json); + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_EVENT_ENGINE_SERVICE_CONFIG_HELPER_H diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc index 7c268fd38c6..019ce8706a8 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc @@ -25,7 +25,6 @@ #include "absl/functional/bind_front.h" #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" @@ -37,7 +36,6 @@ #include "src/core/ext/filters/client_channel/resolver/polling_resolver.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/config/config_vars.h" #include "src/core/lib/config/core_configuration.h" #include "src/core/lib/debug/trace.h" #include "src/core/lib/gprpp/debug_location.h" @@ -179,17 +177,8 @@ class NativeClientChannelDNSResolverFactory : public ResolverFactory { } // namespace void RegisterNativeDnsResolver(CoreConfiguration::Builder* builder) { - if (absl::EqualsIgnoreCase(ConfigVars::Get().DnsResolver(), "native")) { - gpr_log(GPR_DEBUG, "Using native dns resolver"); - builder->resolver_registry()->RegisterResolverFactory( - std::make_unique()); - } else { - if (!builder->resolver_registry()->HasResolverFactory("dns")) { - gpr_log(GPR_DEBUG, "Using native dns resolver"); - builder->resolver_registry()->RegisterResolverFactory( - std::make_unique()); - } - } + builder->resolver_registry()->RegisterResolverFactory( + std::make_unique()); } } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h new file mode 100644 index 00000000000..5ab6fb4c8a7 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h @@ -0,0 +1,24 @@ +// Copyright 2022 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_NATIVE_DNS_RESOLVER_H +#define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_NATIVE_DNS_RESOLVER_H +#include + +#include "src/core/lib/config/core_configuration.h" + +namespace grpc_core { +void RegisterNativeDnsResolver(CoreConfiguration::Builder* builder); +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_NATIVE_DNS_RESOLVER_H diff --git a/src/core/lib/event_engine/trace.cc b/src/core/lib/event_engine/trace.cc index 991cd2d4775..20ae3ae2341 100644 --- a/src/core/lib/event_engine/trace.cc +++ b/src/core/lib/event_engine/trace.cc @@ -16,6 +16,7 @@ #include "src/core/lib/debug/trace.h" grpc_core::TraceFlag grpc_event_engine_trace(false, "event_engine"); +grpc_core::TraceFlag grpc_event_engine_dns_trace(false, "event_engine_dns"); grpc_core::TraceFlag grpc_event_engine_endpoint_trace(false, "event_engine_endpoint"); grpc_core::TraceFlag grpc_event_engine_endpoint_data_trace( diff --git a/src/core/lib/event_engine/trace.h b/src/core/lib/event_engine/trace.h index 63511d161fc..ddc61706ab3 100644 --- a/src/core/lib/event_engine/trace.h +++ b/src/core/lib/event_engine/trace.h @@ -21,6 +21,7 @@ #include "src/core/lib/debug/trace.h" extern grpc_core::TraceFlag grpc_event_engine_trace; +extern grpc_core::TraceFlag grpc_event_engine_dns_trace; extern grpc_core::TraceFlag grpc_event_engine_endpoint_data_trace; extern grpc_core::TraceFlag grpc_event_engine_poller_trace; extern grpc_core::TraceFlag grpc_event_engine_endpoint_trace; @@ -40,4 +41,9 @@ extern grpc_core::TraceFlag grpc_event_engine_endpoint_trace; gpr_log(GPR_DEBUG, "(event_engine poller) " format, __VA_ARGS__); \ } +#define GRPC_EVENT_ENGINE_DNS_TRACE(format, ...) \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_event_engine_dns_trace)) { \ + gpr_log(GPR_DEBUG, "(event_engine dns) " format, __VA_ARGS__); \ + } + #endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_TRACE_H diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index 098521d226b..08dfe1ef8ee 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -58,6 +58,8 @@ const char* const description_schedule_cancellation_over_write = "Allow cancellation op to be scheduled over a write"; const char* const description_trace_record_callops = "Enables tracing of call batch initiation and completion."; +const char* const description_event_engine_dns = + "If set, use EventEngine DNSResolver for client channel resolution"; } // namespace namespace grpc_core { @@ -82,6 +84,7 @@ const ExperimentMetadata g_experiment_metadata[] = { {"schedule_cancellation_over_write", description_schedule_cancellation_over_write, false}, {"trace_record_callops", description_trace_record_callops, false}, + {"event_engine_dns", description_event_engine_dns, false}, }; } // namespace grpc_core diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h index 828a5225f83..2dfa23a025d 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -74,6 +74,7 @@ inline bool IsTransportSuppliesClientLatencyEnabled() { return false; } inline bool IsEventEngineListenerEnabled() { return false; } inline bool IsScheduleCancellationOverWriteEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } +inline bool IsEventEngineDnsEnabled() { return false; } #else #define GRPC_EXPERIMENT_IS_INCLUDED_TCP_FRAME_SIZE_TUNING inline bool IsTcpFrameSizeTuningEnabled() { return IsExperimentEnabled(0); } @@ -115,8 +116,10 @@ inline bool IsScheduleCancellationOverWriteEnabled() { } #define GRPC_EXPERIMENT_IS_INCLUDED_TRACE_RECORD_CALLOPS inline bool IsTraceRecordCallopsEnabled() { return IsExperimentEnabled(14); } +#define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_DNS +inline bool IsEventEngineDnsEnabled() { return IsExperimentEnabled(15); } -constexpr const size_t kNumExperiments = 15; +constexpr const size_t kNumExperiments = 16; extern const ExperimentMetadata g_experiment_metadata[kNumExperiments]; #endif diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index 2ff867b35fa..4f0a04c646a 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -148,3 +148,10 @@ expiry: 2023/07/01 owner: vigneshbabu@google.com test_tags: [] +- name: event_engine_dns + description: + If set, use EventEngine DNSResolver for client channel resolution + default: false + expiry: 2023/06/01 + owner: yijiem@google.com + test_tags: [] diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc index cf0d0b3c0c6..79dd42722e2 100644 --- a/src/core/plugin_registry/grpc_plugin_registry.cc +++ b/src/core/plugin_registry/grpc_plugin_registry.cc @@ -50,9 +50,8 @@ extern void RegisterServiceConfigChannelArgFilter( extern void RegisterExtraFilters(CoreConfiguration::Builder* builder); extern void RegisterResourceQuota(CoreConfiguration::Builder* builder); extern void FaultInjectionFilterRegister(CoreConfiguration::Builder* builder); +extern void RegisterDnsResolver(CoreConfiguration::Builder* builder); extern void RegisterBackendMetricFilter(CoreConfiguration::Builder* builder); -extern void RegisterNativeDnsResolver(CoreConfiguration::Builder* builder); -extern void RegisterAresDnsResolver(CoreConfiguration::Builder* builder); extern void RegisterSockaddrResolver(CoreConfiguration::Builder* builder); extern void RegisterFakeResolver(CoreConfiguration::Builder* builder); extern void RegisterPriorityLbPolicy(CoreConfiguration::Builder* builder); @@ -98,8 +97,7 @@ void BuildCoreConfiguration(CoreConfiguration::Builder* builder) { RegisterServiceConfigChannelArgFilter(builder); RegisterResourceQuota(builder); FaultInjectionFilterRegister(builder); - RegisterAresDnsResolver(builder); - RegisterNativeDnsResolver(builder); + RegisterDnsResolver(builder); RegisterSockaddrResolver(builder); RegisterFakeResolver(builder); RegisterHttpProxyMapper(builder); diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index dcab5dcd455..c331f32e6dd 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -64,6 +64,9 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc', diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc index 2d9dd2e2e56..1316143246d 100644 --- a/test/cpp/naming/resolver_component_test.cc +++ b/test/cpp/naming/resolver_component_test.cc @@ -272,7 +272,8 @@ void CheckServiceConfigResultLocked(const char* service_config_json, EXPECT_EQ(service_config_json, args->expected_service_config_string); } if (args->expected_service_config_error.empty()) { - EXPECT_TRUE(service_config_error.ok()); + EXPECT_TRUE(service_config_error.ok()) + << "Actual error: " << service_config_error.ToString(); } else { EXPECT_THAT(service_config_error.ToString(), testing::HasSubstr(args->expected_service_config_error)); diff --git a/test/cpp/naming/resolver_component_tests_runner.py b/test/cpp/naming/resolver_component_tests_runner.py index e9f6768155a..33118701d1a 100755 --- a/test/cpp/naming/resolver_component_tests_runner.py +++ b/test/cpp/naming/resolver_component_tests_runner.py @@ -541,7 +541,7 @@ current_test_subprocess = subprocess.Popen([ '--do_ordered_address_comparison', 'False', '--expected_addrs', '1.2.3.4:443,False', '--expected_chosen_service_config', '', - '--expected_service_config_error', 'field:clientLanguage error:should be of type array', + '--expected_service_config_error', 'clientLanguage error:is not an array', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', @@ -559,7 +559,7 @@ current_test_subprocess = subprocess.Popen([ '--do_ordered_address_comparison', 'False', '--expected_addrs', '1.2.3.4:443,False', '--expected_chosen_service_config', '', - '--expected_service_config_error', 'field:percentage error:should be of type number', + '--expected_service_config_error', 'percentage error:failed to parse number', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', diff --git a/test/cpp/naming/resolver_test_record_groups.yaml b/test/cpp/naming/resolver_test_record_groups.yaml index 7ff3418e4a7..d459e529c2b 100644 --- a/test/cpp/naming/resolver_test_record_groups.yaml +++ b/test/cpp/naming/resolver_test_record_groups.yaml @@ -403,7 +403,7 @@ resolver_component_tests: - {address: '1.2.3.4:443', is_balancer: false} do_ordered_address_comparison: false expected_chosen_service_config: null - expected_service_config_error: 'field:clientLanguage error:should be of type array' + expected_service_config_error: 'clientLanguage error:is not an array' expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true @@ -419,7 +419,7 @@ resolver_component_tests: - {address: '1.2.3.4:443', is_balancer: false} do_ordered_address_comparison: false expected_chosen_service_config: null - expected_service_config_error: 'field:percentage error:should be of type number' + expected_service_config_error: 'percentage error:failed to parse number' expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true @@ -429,7 +429,7 @@ resolver_component_tests: ipv4-svc_cfg_bad_percentage: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-svc_cfg_bad_percentage: - - {TTL: '2100', data: 'grpc_config=[{"percentage":"0","serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"percentage":"arst","serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index db20c4ee877..85ca6b7b8b8 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1151,6 +1151,7 @@ src/core/ext/filters/client_channel/local_subchannel_pool.cc \ src/core/ext/filters/client_channel/local_subchannel_pool.h \ src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \ +src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \ @@ -1158,7 +1159,14 @@ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ +src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc \ +src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h \ +src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc \ +src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h \ +src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc \ +src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ +src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h \ src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index c05169714cb..3a07ccb7e81 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -959,6 +959,7 @@ src/core/ext/filters/client_channel/resolver/README.md \ src/core/ext/filters/client_channel/resolver/binder/README.md \ src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \ +src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.h \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \ @@ -966,8 +967,15 @@ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ +src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.cc \ +src/core/ext/filters/client_channel/resolver/dns/dns_resolver_plugin.h \ +src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc \ +src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h \ +src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc \ +src/core/ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h \ src/core/ext/filters/client_channel/resolver/dns/native/README.md \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ +src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h \ src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \