XdsClient: move resource type parsing out of XdsApi (#28151)

* introduce XdsResourceType API and change Listener parsing to use it

* converted RouteConfig parsing

* convert cluster and endpoint parsing

* cleanup

* clang-format

* attempt to work around compiler problems

* move XdsResourceType to its own file, and move endpoint code out of XdsApi

* move cluster parsing to its own file

* move route config parsing to its own file

* move listener parsing to its own file

* clang-format

* minor cleanup

* remove comment

* add missing virtual dtor
pull/28165/head
Mark D. Roth 3 years ago committed by GitHub
parent e21505858f
commit cbe2855866
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      BUILD
  2. 5
      CMakeLists.txt
  3. 10
      Makefile
  4. 12
      build_autogenerated.yaml
  5. 5
      config.m4
  6. 5
      config.w32
  7. 14
      gRPC-C++.podspec
  8. 19
      gRPC-Core.podspec
  9. 12
      grpc.gemspec
  10. 5
      grpc.gyp
  11. 12
      package.xml
  12. 19
      src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
  13. 14
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
  14. 30
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
  15. 51
      src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
  16. 62
      src/core/ext/xds/upb_utils.h
  17. 3102
      src/core/ext/xds/xds_api.cc
  18. 539
      src/core/ext/xds/xds_api.h
  19. 8
      src/core/ext/xds/xds_client.cc
  20. 16
      src/core/ext/xds/xds_client.h
  21. 442
      src/core/ext/xds/xds_cluster.cc
  22. 101
      src/core/ext/xds/xds_cluster.h
  23. 388
      src/core/ext/xds/xds_common_types.cc
  24. 110
      src/core/ext/xds/xds_common_types.h
  25. 352
      src/core/ext/xds/xds_endpoint.cc
  26. 132
      src/core/ext/xds/xds_endpoint.h
  27. 1012
      src/core/ext/xds/xds_listener.cc
  28. 210
      src/core/ext/xds/xds_listener.h
  29. 77
      src/core/ext/xds/xds_resource_type.h
  30. 982
      src/core/ext/xds/xds_route_config.cc
  31. 211
      src/core/ext/xds/xds_route_config.h
  32. 16
      src/core/ext/xds/xds_routing.cc
  33. 10
      src/core/ext/xds/xds_routing.h
  34. 117
      src/core/ext/xds/xds_server_config_fetcher.cc
  35. 5
      src/python/grpcio/grpc_core_dependencies.py
  36. 12
      tools/doxygen/Doxyfile.c++.internal
  37. 12
      tools/doxygen/Doxyfile.core.internal

13
BUILD

@ -2599,8 +2599,13 @@ grpc_cc_library(
"src/core/ext/xds/xds_certificate_provider.cc",
"src/core/ext/xds/xds_client.cc",
"src/core/ext/xds/xds_client_stats.cc",
"src/core/ext/xds/xds_cluster.cc",
"src/core/ext/xds/xds_common_types.cc",
"src/core/ext/xds/xds_endpoint.cc",
"src/core/ext/xds/xds_http_fault_filter.cc",
"src/core/ext/xds/xds_http_filters.cc",
"src/core/ext/xds/xds_listener.cc",
"src/core/ext/xds/xds_route_config.cc",
"src/core/ext/xds/xds_routing.cc",
"src/core/lib/security/credentials/xds/xds_credentials.cc",
],
@ -2609,19 +2614,27 @@ grpc_cc_library(
"src/core/ext/xds/certificate_provider_registry.h",
"src/core/ext/xds/certificate_provider_store.h",
"src/core/ext/xds/file_watcher_certificate_provider_factory.h",
"src/core/ext/xds/upb_utils.h",
"src/core/ext/xds/xds_api.h",
"src/core/ext/xds/xds_bootstrap.h",
"src/core/ext/xds/xds_certificate_provider.h",
"src/core/ext/xds/xds_channel_args.h",
"src/core/ext/xds/xds_client.h",
"src/core/ext/xds/xds_client_stats.h",
"src/core/ext/xds/xds_cluster.h",
"src/core/ext/xds/xds_common_types.h",
"src/core/ext/xds/xds_endpoint.h",
"src/core/ext/xds/xds_http_fault_filter.h",
"src/core/ext/xds/xds_http_filters.h",
"src/core/ext/xds/xds_listener.h",
"src/core/ext/xds/xds_resource_type.h",
"src/core/ext/xds/xds_route_config.h",
"src/core/ext/xds/xds_routing.h",
"src/core/lib/security/credentials/xds/xds_credentials.h",
],
external_deps = [
"absl/functional:bind_front",
"absl/memory",
"absl/status:statusor",
"absl/strings",
"absl/strings:str_format",

5
CMakeLists.txt generated

@ -1850,8 +1850,13 @@ add_library(grpc
src/core/ext/xds/xds_channel_stack_modifier.cc
src/core/ext/xds/xds_client.cc
src/core/ext/xds/xds_client_stats.cc
src/core/ext/xds/xds_cluster.cc
src/core/ext/xds/xds_common_types.cc
src/core/ext/xds/xds_endpoint.cc
src/core/ext/xds/xds_http_fault_filter.cc
src/core/ext/xds/xds_http_filters.cc
src/core/ext/xds/xds_listener.cc
src/core/ext/xds/xds_route_config.cc
src/core/ext/xds/xds_routing.cc
src/core/ext/xds/xds_server_config_fetcher.cc
src/core/lib/address_utils/parse_address.cc

10
Makefile generated

@ -1348,8 +1348,13 @@ LIBGRPC_SRC = \
src/core/ext/xds/xds_channel_stack_modifier.cc \
src/core/ext/xds/xds_client.cc \
src/core/ext/xds/xds_client_stats.cc \
src/core/ext/xds/xds_cluster.cc \
src/core/ext/xds/xds_common_types.cc \
src/core/ext/xds/xds_endpoint.cc \
src/core/ext/xds/xds_http_fault_filter.cc \
src/core/ext/xds/xds_http_filters.cc \
src/core/ext/xds/xds_listener.cc \
src/core/ext/xds/xds_route_config.cc \
src/core/ext/xds/xds_routing.cc \
src/core/ext/xds/xds_server_config_fetcher.cc \
src/core/lib/address_utils/parse_address.cc \
@ -2951,8 +2956,13 @@ src/core/ext/xds/xds_certificate_provider.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_channel_stack_modifier.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_client.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_client_stats.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_cluster.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_common_types.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_endpoint.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_http_fault_filter.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_http_filters.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_listener.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_route_config.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_routing.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_server_config_fetcher.cc: $(OPENSSL_DEP)
src/core/lib/http/httpcli_security_connector.cc: $(OPENSSL_DEP)

@ -715,6 +715,7 @@ libs:
- src/core/ext/xds/certificate_provider_registry.h
- src/core/ext/xds/certificate_provider_store.h
- src/core/ext/xds/file_watcher_certificate_provider_factory.h
- src/core/ext/xds/upb_utils.h
- src/core/ext/xds/xds_api.h
- src/core/ext/xds/xds_bootstrap.h
- src/core/ext/xds/xds_certificate_provider.h
@ -722,8 +723,14 @@ libs:
- src/core/ext/xds/xds_channel_stack_modifier.h
- src/core/ext/xds/xds_client.h
- src/core/ext/xds/xds_client_stats.h
- src/core/ext/xds/xds_cluster.h
- src/core/ext/xds/xds_common_types.h
- src/core/ext/xds/xds_endpoint.h
- src/core/ext/xds/xds_http_fault_filter.h
- src/core/ext/xds/xds_http_filters.h
- src/core/ext/xds/xds_listener.h
- src/core/ext/xds/xds_resource_type.h
- src/core/ext/xds/xds_route_config.h
- src/core/ext/xds/xds_routing.h
- src/core/lib/address_utils/parse_address.h
- src/core/lib/address_utils/sockaddr_utils.h
@ -1306,8 +1313,13 @@ libs:
- src/core/ext/xds/xds_channel_stack_modifier.cc
- src/core/ext/xds/xds_client.cc
- src/core/ext/xds/xds_client_stats.cc
- src/core/ext/xds/xds_cluster.cc
- src/core/ext/xds/xds_common_types.cc
- src/core/ext/xds/xds_endpoint.cc
- src/core/ext/xds/xds_http_fault_filter.cc
- src/core/ext/xds/xds_http_filters.cc
- src/core/ext/xds/xds_listener.cc
- src/core/ext/xds/xds_route_config.cc
- src/core/ext/xds/xds_routing.cc
- src/core/ext/xds/xds_server_config_fetcher.cc
- src/core/lib/address_utils/parse_address.cc

5
config.m4 generated

@ -365,8 +365,13 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/xds/xds_channel_stack_modifier.cc \
src/core/ext/xds/xds_client.cc \
src/core/ext/xds/xds_client_stats.cc \
src/core/ext/xds/xds_cluster.cc \
src/core/ext/xds/xds_common_types.cc \
src/core/ext/xds/xds_endpoint.cc \
src/core/ext/xds/xds_http_fault_filter.cc \
src/core/ext/xds/xds_http_filters.cc \
src/core/ext/xds/xds_listener.cc \
src/core/ext/xds/xds_route_config.cc \
src/core/ext/xds/xds_routing.cc \
src/core/ext/xds/xds_server_config_fetcher.cc \
src/core/lib/address_utils/parse_address.cc \

5
config.w32 generated

@ -331,8 +331,13 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\xds\\xds_channel_stack_modifier.cc " +
"src\\core\\ext\\xds\\xds_client.cc " +
"src\\core\\ext\\xds\\xds_client_stats.cc " +
"src\\core\\ext\\xds\\xds_cluster.cc " +
"src\\core\\ext\\xds\\xds_common_types.cc " +
"src\\core\\ext\\xds\\xds_endpoint.cc " +
"src\\core\\ext\\xds\\xds_http_fault_filter.cc " +
"src\\core\\ext\\xds\\xds_http_filters.cc " +
"src\\core\\ext\\xds\\xds_listener.cc " +
"src\\core\\ext\\xds\\xds_route_config.cc " +
"src\\core\\ext\\xds\\xds_routing.cc " +
"src\\core\\ext\\xds\\xds_server_config_fetcher.cc " +
"src\\core\\lib\\address_utils\\parse_address.cc " +

14
gRPC-C++.podspec generated

@ -550,6 +550,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
'src/core/ext/xds/file_watcher_certificate_provider_factory.h',
'src/core/ext/xds/upb_utils.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_certificate_provider.h',
@ -557,8 +558,14 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_channel_stack_modifier.h',
'src/core/ext/xds/xds_client.h',
'src/core/ext/xds/xds_client_stats.h',
'src/core/ext/xds/xds_cluster.h',
'src/core/ext/xds/xds_common_types.h',
'src/core/ext/xds/xds_endpoint.h',
'src/core/ext/xds/xds_http_fault_filter.h',
'src/core/ext/xds/xds_http_filters.h',
'src/core/ext/xds/xds_listener.h',
'src/core/ext/xds/xds_resource_type.h',
'src/core/ext/xds/xds_route_config.h',
'src/core/ext/xds/xds_routing.h',
'src/core/lib/address_utils/parse_address.h',
'src/core/lib/address_utils/sockaddr_utils.h',
@ -1266,6 +1273,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
'src/core/ext/xds/file_watcher_certificate_provider_factory.h',
'src/core/ext/xds/upb_utils.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_certificate_provider.h',
@ -1273,8 +1281,14 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_channel_stack_modifier.h',
'src/core/ext/xds/xds_client.h',
'src/core/ext/xds/xds_client_stats.h',
'src/core/ext/xds/xds_cluster.h',
'src/core/ext/xds/xds_common_types.h',
'src/core/ext/xds/xds_endpoint.h',
'src/core/ext/xds/xds_http_fault_filter.h',
'src/core/ext/xds/xds_http_filters.h',
'src/core/ext/xds/xds_listener.h',
'src/core/ext/xds/xds_resource_type.h',
'src/core/ext/xds/xds_route_config.h',
'src/core/ext/xds/xds_routing.h',
'src/core/lib/address_utils/parse_address.h',
'src/core/lib/address_utils/sockaddr_utils.h',

19
gRPC-Core.podspec generated

@ -808,6 +808,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/certificate_provider_store.h',
'src/core/ext/xds/file_watcher_certificate_provider_factory.cc',
'src/core/ext/xds/file_watcher_certificate_provider_factory.h',
'src/core/ext/xds/upb_utils.h',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.cc',
@ -821,10 +822,21 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_client.h',
'src/core/ext/xds/xds_client_stats.cc',
'src/core/ext/xds/xds_client_stats.h',
'src/core/ext/xds/xds_cluster.cc',
'src/core/ext/xds/xds_cluster.h',
'src/core/ext/xds/xds_common_types.cc',
'src/core/ext/xds/xds_common_types.h',
'src/core/ext/xds/xds_endpoint.cc',
'src/core/ext/xds/xds_endpoint.h',
'src/core/ext/xds/xds_http_fault_filter.cc',
'src/core/ext/xds/xds_http_fault_filter.h',
'src/core/ext/xds/xds_http_filters.cc',
'src/core/ext/xds/xds_http_filters.h',
'src/core/ext/xds/xds_listener.cc',
'src/core/ext/xds/xds_listener.h',
'src/core/ext/xds/xds_resource_type.h',
'src/core/ext/xds/xds_route_config.cc',
'src/core/ext/xds/xds_route_config.h',
'src/core/ext/xds/xds_routing.cc',
'src/core/ext/xds/xds_routing.h',
'src/core/ext/xds/xds_server_config_fetcher.cc',
@ -1797,6 +1809,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
'src/core/ext/xds/file_watcher_certificate_provider_factory.h',
'src/core/ext/xds/upb_utils.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_certificate_provider.h',
@ -1804,8 +1817,14 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_channel_stack_modifier.h',
'src/core/ext/xds/xds_client.h',
'src/core/ext/xds/xds_client_stats.h',
'src/core/ext/xds/xds_cluster.h',
'src/core/ext/xds/xds_common_types.h',
'src/core/ext/xds/xds_endpoint.h',
'src/core/ext/xds/xds_http_fault_filter.h',
'src/core/ext/xds/xds_http_filters.h',
'src/core/ext/xds/xds_listener.h',
'src/core/ext/xds/xds_resource_type.h',
'src/core/ext/xds/xds_route_config.h',
'src/core/ext/xds/xds_routing.h',
'src/core/lib/address_utils/parse_address.h',
'src/core/lib/address_utils/sockaddr_utils.h',

12
grpc.gemspec generated

@ -727,6 +727,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/xds/certificate_provider_store.h )
s.files += %w( src/core/ext/xds/file_watcher_certificate_provider_factory.cc )
s.files += %w( src/core/ext/xds/file_watcher_certificate_provider_factory.h )
s.files += %w( src/core/ext/xds/upb_utils.h )
s.files += %w( src/core/ext/xds/xds_api.cc )
s.files += %w( src/core/ext/xds/xds_api.h )
s.files += %w( src/core/ext/xds/xds_bootstrap.cc )
@ -740,10 +741,21 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/xds/xds_client.h )
s.files += %w( src/core/ext/xds/xds_client_stats.cc )
s.files += %w( src/core/ext/xds/xds_client_stats.h )
s.files += %w( src/core/ext/xds/xds_cluster.cc )
s.files += %w( src/core/ext/xds/xds_cluster.h )
s.files += %w( src/core/ext/xds/xds_common_types.cc )
s.files += %w( src/core/ext/xds/xds_common_types.h )
s.files += %w( src/core/ext/xds/xds_endpoint.cc )
s.files += %w( src/core/ext/xds/xds_endpoint.h )
s.files += %w( src/core/ext/xds/xds_http_fault_filter.cc )
s.files += %w( src/core/ext/xds/xds_http_fault_filter.h )
s.files += %w( src/core/ext/xds/xds_http_filters.cc )
s.files += %w( src/core/ext/xds/xds_http_filters.h )
s.files += %w( src/core/ext/xds/xds_listener.cc )
s.files += %w( src/core/ext/xds/xds_listener.h )
s.files += %w( src/core/ext/xds/xds_resource_type.h )
s.files += %w( src/core/ext/xds/xds_route_config.cc )
s.files += %w( src/core/ext/xds/xds_route_config.h )
s.files += %w( src/core/ext/xds/xds_routing.cc )
s.files += %w( src/core/ext/xds/xds_routing.h )
s.files += %w( src/core/ext/xds/xds_server_config_fetcher.cc )

5
grpc.gyp generated

@ -803,8 +803,13 @@
'src/core/ext/xds/xds_channel_stack_modifier.cc',
'src/core/ext/xds/xds_client.cc',
'src/core/ext/xds/xds_client_stats.cc',
'src/core/ext/xds/xds_cluster.cc',
'src/core/ext/xds/xds_common_types.cc',
'src/core/ext/xds/xds_endpoint.cc',
'src/core/ext/xds/xds_http_fault_filter.cc',
'src/core/ext/xds/xds_http_filters.cc',
'src/core/ext/xds/xds_listener.cc',
'src/core/ext/xds/xds_route_config.cc',
'src/core/ext/xds/xds_routing.cc',
'src/core/ext/xds/xds_server_config_fetcher.cc',
'src/core/lib/address_utils/parse_address.cc',

12
package.xml generated

@ -707,6 +707,7 @@
<file baseinstalldir="/" name="src/core/ext/xds/certificate_provider_store.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/file_watcher_certificate_provider_factory.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/file_watcher_certificate_provider_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/upb_utils.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_api.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_bootstrap.cc" role="src" />
@ -720,10 +721,21 @@
<file baseinstalldir="/" name="src/core/ext/xds/xds_client.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_client_stats.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_client_stats.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_cluster.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_cluster.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_common_types.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_common_types.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_endpoint.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_http_fault_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_http_fault_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_http_filters.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_http_filters.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_listener.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_listener.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_resource_type.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_route_config.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_route_config.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_routing.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_routing.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_server_config_fetcher.cc" role="src" />

@ -71,7 +71,7 @@ class CdsLb : public LoadBalancingPolicy {
ClusterWatcher(RefCountedPtr<CdsLb> parent, std::string name)
: parent_(std::move(parent)), name_(std::move(name)) {}
void OnClusterChanged(XdsApi::CdsUpdate cluster_data) override {
void OnClusterChanged(XdsClusterResource cluster_data) override {
Ref().release(); // Ref held by lambda
parent_->work_serializer()->Run(
// TODO(roth): When we move to C++14, capture cluster_data with
@ -111,7 +111,7 @@ class CdsLb : public LoadBalancingPolicy {
// Not owned, so do not dereference.
ClusterWatcher* watcher = nullptr;
// Most recent update obtained from this watcher.
absl::optional<XdsApi::CdsUpdate> update;
absl::optional<XdsClusterResource> update;
};
// Delegating helper to be passed to child policy.
@ -139,12 +139,12 @@ class CdsLb : public LoadBalancingPolicy {
const std::string& name, Json::Array* discovery_mechanisms,
std::set<std::string>* clusters_needed);
void OnClusterChanged(const std::string& name,
XdsApi::CdsUpdate cluster_data);
XdsClusterResource cluster_data);
void OnError(const std::string& name, grpc_error_handle error);
void OnResourceDoesNotExist(const std::string& name);
grpc_error_handle UpdateXdsCertificateProvider(
const std::string& cluster_name, const XdsApi::CdsUpdate& cluster_data);
const std::string& cluster_name, const XdsClusterResource& cluster_data);
void CancelClusterDataWatch(absl::string_view cluster_name,
XdsClient::ClusterWatcherInterface* watcher,
@ -332,7 +332,8 @@ bool CdsLb::GenerateDiscoveryMechanismForCluster(
// Don't have the update we need yet.
if (!state.update.has_value()) return false;
// For AGGREGATE clusters, recursively expand to child clusters.
if (state.update->cluster_type == XdsApi::CdsUpdate::ClusterType::AGGREGATE) {
if (state.update->cluster_type ==
XdsClusterResource::ClusterType::AGGREGATE) {
bool missing_cluster = false;
for (const std::string& child_name :
state.update->prioritized_cluster_names) {
@ -348,13 +349,13 @@ bool CdsLb::GenerateDiscoveryMechanismForCluster(
{"max_concurrent_requests", state.update->max_concurrent_requests},
};
switch (state.update->cluster_type) {
case XdsApi::CdsUpdate::ClusterType::EDS:
case XdsClusterResource::ClusterType::EDS:
mechanism["type"] = "EDS";
if (!state.update->eds_service_name.empty()) {
mechanism["edsServiceName"] = state.update->eds_service_name;
}
break;
case XdsApi::CdsUpdate::ClusterType::LOGICAL_DNS:
case XdsClusterResource::ClusterType::LOGICAL_DNS:
mechanism["type"] = "LOGICAL_DNS";
mechanism["dnsHostname"] = state.update->dns_hostname;
break;
@ -371,7 +372,7 @@ bool CdsLb::GenerateDiscoveryMechanismForCluster(
}
void CdsLb::OnClusterChanged(const std::string& name,
XdsApi::CdsUpdate cluster_data) {
XdsClusterResource cluster_data) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
gpr_log(
GPR_INFO,
@ -509,7 +510,7 @@ void CdsLb::OnResourceDoesNotExist(const std::string& name) {
}
grpc_error_handle CdsLb::UpdateXdsCertificateProvider(
const std::string& cluster_name, const XdsApi::CdsUpdate& cluster_data) {
const std::string& cluster_name, const XdsClusterResource& cluster_data) {
// Early out if channel is not configured to use xds security.
grpc_channel_credentials* channel_credentials =
grpc_channel_credentials_find_in_args(args_);

@ -120,7 +120,7 @@ class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config {
std::string cluster_name, std::string eds_service_name,
absl::optional<std::string> lrs_load_reporting_server_name,
uint32_t max_concurrent_requests,
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config)
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config)
: child_policy_(std::move(child_policy)),
cluster_name_(std::move(cluster_name)),
eds_service_name_(std::move(eds_service_name)),
@ -140,7 +140,7 @@ class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config {
return lrs_load_reporting_server_name_;
};
uint32_t max_concurrent_requests() const { return max_concurrent_requests_; }
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config() const {
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config() const {
return drop_config_;
}
@ -150,7 +150,7 @@ class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config {
std::string eds_service_name_;
absl::optional<std::string> lrs_load_reporting_server_name_;
uint32_t max_concurrent_requests_;
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config_;
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config_;
};
// xDS Cluster Impl LB policy.
@ -205,7 +205,7 @@ class XdsClusterImplLb : public LoadBalancingPolicy {
RefCountedPtr<CircuitBreakerCallCounterMap::CallCounter> call_counter_;
uint32_t max_concurrent_requests_;
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config_;
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config_;
RefCountedPtr<XdsClusterDropStats> drop_stats_;
RefCountedPtr<RefCountedPicker> picker_;
};
@ -736,7 +736,7 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
}
}
// Drop config.
auto drop_config = MakeRefCounted<XdsApi::EdsUpdate::DropConfig>();
auto drop_config = MakeRefCounted<XdsEndpointResource::DropConfig>();
it = json.object_value().find("dropCategories");
if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@ -762,7 +762,7 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
private:
static std::vector<grpc_error_handle> ParseDropCategories(
const Json& json, XdsApi::EdsUpdate::DropConfig* drop_config) {
const Json& json, XdsEndpointResource::DropConfig* drop_config) {
std::vector<grpc_error_handle> error_list;
if (json.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@ -786,7 +786,7 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
}
static std::vector<grpc_error_handle> ParseDropCategory(
const Json& json, XdsApi::EdsUpdate::DropConfig* drop_config) {
const Json& json, XdsEndpointResource::DropConfig* drop_config) {
std::vector<grpc_error_handle> error_list;
if (json.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(

@ -175,7 +175,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
~EndpointWatcher() override {
discovery_mechanism_.reset(DEBUG_LOCATION, "EndpointWatcher");
}
void OnEndpointChanged(XdsApi::EdsUpdate update) override {
void OnEndpointChanged(XdsEndpointResource update) override {
Ref().release(); // ref held by callback
discovery_mechanism_->parent()->work_serializer()->Run(
// TODO(yashykt): When we move to C++14, capture update with
@ -209,7 +209,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
// Code accessing protected methods of `DiscoveryMechanism` need to be
// in methods of this class rather than in lambdas to work around an MSVC
// bug.
void OnEndpointChangedHelper(XdsApi::EdsUpdate update) {
void OnEndpointChangedHelper(XdsEndpointResource update) {
discovery_mechanism_->parent()->OnEndpointChanged(
discovery_mechanism_->index(), std::move(update));
}
@ -292,10 +292,10 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
// (The sum of this across all discovery mechanisms should always equal
// the number of priorities in priority_list_.)
uint32_t num_priorities = 0;
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config;
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config;
// Populated only when an update has been delivered by the mechanism
// but has not yet been applied to the LB policy's combined priority_list_.
absl::optional<XdsApi::EdsUpdate::PriorityList> pending_priority_list;
absl::optional<XdsEndpointResource::PriorityList> pending_priority_list;
};
class Helper : public ChannelControlHelper {
@ -328,13 +328,13 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
void ShutdownLocked() override;
void OnEndpointChanged(size_t index, XdsApi::EdsUpdate update);
void OnEndpointChanged(size_t index, XdsEndpointResource update);
void OnError(size_t index, grpc_error_handle error);
void OnResourceDoesNotExist(size_t index);
void MaybeDestroyChildPolicyLocked();
void UpdatePriorityList(XdsApi::EdsUpdate::PriorityList priority_list);
void UpdatePriorityList(XdsEndpointResource::PriorityList priority_list);
void UpdateChildPolicyLocked();
OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
const grpc_channel_args* args);
@ -361,7 +361,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
std::vector<DiscoveryMechanismEntry> discovery_mechanisms_;
// The latest data from the endpoint watcher.
XdsApi::EdsUpdate::PriorityList priority_list_;
XdsEndpointResource::PriorityList priority_list_;
// State used to retain child policy names for priority policy.
std::vector<size_t /*child_number*/> priority_child_numbers_;
@ -498,12 +498,12 @@ void XdsClusterResolverLb::LogicalDNSDiscoveryMechanism::Orphan() {
void XdsClusterResolverLb::LogicalDNSDiscoveryMechanism::ResolverResultHandler::
ReturnResult(Resolver::Result result) {
// convert result to eds update
XdsApi::EdsUpdate update;
XdsApi::EdsUpdate::Priority::Locality locality;
XdsEndpointResource update;
XdsEndpointResource::Priority::Locality locality;
locality.name = MakeRefCounted<XdsLocalityName>("", "", "");
locality.lb_weight = 1;
locality.endpoints = std::move(result.addresses);
XdsApi::EdsUpdate::Priority priority;
XdsEndpointResource::Priority priority;
priority.localities.emplace(locality.name.get(), std::move(locality));
update.priorities.emplace_back(std::move(priority));
discovery_mechanism_->parent()->OnEndpointChanged(
@ -630,7 +630,7 @@ void XdsClusterResolverLb::ExitIdleLocked() {
}
void XdsClusterResolverLb::OnEndpointChanged(size_t index,
XdsApi::EdsUpdate update) {
XdsEndpointResource update) {
if (shutting_down_) return;
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_cluster_resolver_trace)) {
gpr_log(GPR_INFO,
@ -660,7 +660,7 @@ void XdsClusterResolverLb::OnEndpointChanged(size_t index,
if (!mechanism.first_update_received) return;
}
// Construct new priority list.
XdsApi::EdsUpdate::PriorityList priority_list;
XdsEndpointResource::PriorityList priority_list;
size_t priority_index = 0;
for (DiscoveryMechanismEntry& mechanism : discovery_mechanisms_) {
// If the mechanism has a pending update, use that.
@ -694,7 +694,7 @@ void XdsClusterResolverLb::OnError(size_t index, grpc_error_handle error) {
if (!discovery_mechanisms_[index].first_update_received) {
// Call OnEndpointChanged with an empty update just like
// OnResourceDoesNotExist.
OnEndpointChanged(index, XdsApi::EdsUpdate());
OnEndpointChanged(index, XdsEndpointResource());
}
}
@ -705,7 +705,7 @@ void XdsClusterResolverLb::OnResourceDoesNotExist(size_t index) {
this, index);
if (shutting_down_) return;
// Call OnEndpointChanged with an empty update.
OnEndpointChanged(index, XdsApi::EdsUpdate());
OnEndpointChanged(index, XdsEndpointResource());
}
//
@ -713,7 +713,7 @@ void XdsClusterResolverLb::OnResourceDoesNotExist(size_t index) {
//
void XdsClusterResolverLb::UpdatePriorityList(
XdsApi::EdsUpdate::PriorityList priority_list) {
XdsEndpointResource::PriorityList priority_list) {
// Build some maps from locality to child number and the reverse from
// the old data in priority_list_ and priority_child_numbers_.
std::map<XdsLocalityName*, size_t /*child_number*/, XdsLocalityName::Less>

@ -83,7 +83,7 @@ class XdsResolver : public Resolver {
public:
explicit ListenerWatcher(RefCountedPtr<XdsResolver> resolver)
: resolver_(std::move(resolver)) {}
void OnListenerChanged(XdsApi::LdsUpdate listener) override {
void OnListenerChanged(XdsListenerResource listener) override {
Ref().release(); // ref held by lambda
resolver_->work_serializer_->Run(
// TODO(yashykt): When we move to C++14, capture listener with
@ -121,7 +121,7 @@ class XdsResolver : public Resolver {
public:
explicit RouteConfigWatcher(RefCountedPtr<XdsResolver> resolver)
: resolver_(std::move(resolver)) {}
void OnRouteConfigChanged(XdsApi::RdsUpdate route_config) override {
void OnRouteConfigChanged(XdsRouteConfigResource route_config) override {
Ref().release(); // ref held by lambda
resolver_->work_serializer_->Run(
// TODO(yashykt): When we move to C++14, capture route_config with
@ -250,7 +250,7 @@ class XdsResolver : public Resolver {
bool operator==(const ClusterWeightState& other) const;
};
XdsApi::Route route;
XdsRouteConfigResource::Route route;
RefCountedPtr<ServiceConfig> method_config;
absl::InlinedVector<ClusterWeightState, 2> weighted_cluster_state;
@ -262,8 +262,9 @@ class XdsResolver : public Resolver {
void MaybeAddCluster(const std::string& name);
grpc_error_handle CreateMethodConfig(
const XdsApi::Route& route,
const XdsApi::Route::RouteAction::ClusterWeight* cluster_weight,
const XdsRouteConfigResource::Route& route,
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
cluster_weight,
RefCountedPtr<ServiceConfig>* method_config);
RefCountedPtr<XdsResolver> resolver_;
@ -272,8 +273,8 @@ class XdsResolver : public Resolver {
std::vector<const grpc_channel_filter*> filters_;
};
void OnListenerUpdate(XdsApi::LdsUpdate listener);
void OnRouteConfigUpdate(XdsApi::RdsUpdate rds_update);
void OnListenerUpdate(XdsListenerResource listener);
void OnRouteConfigUpdate(XdsRouteConfigResource rds_update);
void OnError(grpc_error_handle error);
void OnResourceDoesNotExist();
@ -294,11 +295,11 @@ class XdsResolver : public Resolver {
// This will not contain the RouteConfiguration, even if it comes with the
// LDS response; instead, the relevant VirtualHost from the
// RouteConfiguration will be saved in current_virtual_host_.
XdsApi::LdsUpdate current_listener_;
XdsListenerResource current_listener_;
std::string route_config_name_;
XdsClient::RouteConfigWatcherInterface* route_config_watcher_ = nullptr;
XdsApi::RdsUpdate::VirtualHost current_virtual_host_;
XdsRouteConfigResource::VirtualHost current_virtual_host_;
ClusterState::ClusterStateMap cluster_state_map_;
};
@ -336,7 +337,7 @@ class XdsResolver::XdsConfigSelector::RouteListIterator
size_t Size() const override { return route_table_->size(); }
const XdsApi::Route::Matchers& GetMatchersForRoute(
const XdsRouteConfigResource::Route::Matchers& GetMatchersForRoute(
size_t index) const override {
return (*route_table_)[index].route.matchers;
}
@ -375,7 +376,8 @@ XdsResolver::XdsConfigSelector::XdsConfigSelector(
auto& route_entry = route_table_.back();
route_entry.route = route;
auto* route_action =
absl::get_if<XdsApi::Route::RouteAction>(&route_entry.route.action);
absl::get_if<XdsRouteConfigResource::Route::RouteAction>(
&route_entry.route.action);
if (route_action != nullptr) {
// If the route doesn't specify a timeout, set its timeout to the global
// one.
@ -431,12 +433,13 @@ XdsResolver::XdsConfigSelector::~XdsConfigSelector() {
}
grpc_error_handle XdsResolver::XdsConfigSelector::CreateMethodConfig(
const XdsApi::Route& route,
const XdsApi::Route::RouteAction::ClusterWeight* cluster_weight,
const XdsRouteConfigResource::Route& route,
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
cluster_weight,
RefCountedPtr<ServiceConfig>* method_config) {
std::vector<std::string> fields;
const auto& route_action =
absl::get<XdsApi::Route::RouteAction>(route.action);
absl::get<XdsRouteConfigResource::Route::RouteAction>(route.action);
// Set retry policy if any.
if (route_action.retry_policy.has_value() &&
!route_action.retry_policy->retry_on.Empty()) {
@ -536,9 +539,10 @@ void XdsResolver::XdsConfigSelector::MaybeAddCluster(const std::string& name) {
}
absl::optional<uint64_t> HeaderHashHelper(
const XdsApi::Route::RouteAction::HashPolicy& policy,
const XdsRouteConfigResource::Route::RouteAction::HashPolicy& policy,
grpc_metadata_batch* initial_metadata) {
GPR_ASSERT(policy.type == XdsApi::Route::RouteAction::HashPolicy::HEADER);
GPR_ASSERT(policy.type ==
XdsRouteConfigResource::Route::RouteAction::HashPolicy::HEADER);
std::string value_buffer;
absl::optional<absl::string_view> header_value = XdsRouting::GetHeaderValue(
initial_metadata, policy.header_name, &value_buffer);
@ -568,7 +572,8 @@ ConfigSelector::CallConfig XdsResolver::XdsConfigSelector::GetCallConfig(
auto& entry = route_table_[*route_index];
// Found a route match
const auto* route_action =
absl::get_if<XdsApi::Route::RouteAction>(&entry.route.action);
absl::get_if<XdsRouteConfigResource::Route::RouteAction>(
&entry.route.action);
if (route_action == nullptr) {
CallConfig call_config;
call_config.error =
@ -615,10 +620,10 @@ ConfigSelector::CallConfig XdsResolver::XdsConfigSelector::GetCallConfig(
for (const auto& hash_policy : route_action->hash_policies) {
absl::optional<uint64_t> new_hash;
switch (hash_policy.type) {
case XdsApi::Route::RouteAction::HashPolicy::HEADER:
case XdsRouteConfigResource::Route::RouteAction::HashPolicy::HEADER:
new_hash = HeaderHashHelper(hash_policy, args.initial_metadata);
break;
case XdsApi::Route::RouteAction::HashPolicy::CHANNEL_ID:
case XdsRouteConfigResource::Route::RouteAction::HashPolicy::CHANNEL_ID:
new_hash =
static_cast<uint64_t>(reinterpret_cast<uintptr_t>(resolver_.get()));
break;
@ -706,7 +711,7 @@ void XdsResolver::ShutdownLocked() {
}
}
void XdsResolver::OnListenerUpdate(XdsApi::LdsUpdate listener) {
void XdsResolver::OnListenerUpdate(XdsListenerResource listener) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
gpr_log(GPR_INFO, "[xds_resolver %p] received updated listener data", this);
}
@ -748,7 +753,7 @@ namespace {
class VirtualHostListIterator : public XdsRouting::VirtualHostListIterator {
public:
explicit VirtualHostListIterator(
const std::vector<XdsApi::RdsUpdate::VirtualHost>* virtual_hosts)
const std::vector<XdsRouteConfigResource::VirtualHost>* virtual_hosts)
: virtual_hosts_(virtual_hosts) {}
size_t Size() const override { return virtual_hosts_->size(); }
@ -759,11 +764,11 @@ class VirtualHostListIterator : public XdsRouting::VirtualHostListIterator {
}
private:
const std::vector<XdsApi::RdsUpdate::VirtualHost>* virtual_hosts_;
const std::vector<XdsRouteConfigResource::VirtualHost>* virtual_hosts_;
};
} // namespace
void XdsResolver::OnRouteConfigUpdate(XdsApi::RdsUpdate rds_update) {
void XdsResolver::OnRouteConfigUpdate(XdsRouteConfigResource rds_update) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
gpr_log(GPR_INFO, "[xds_resolver %p] received updated route config", this);
}

@ -0,0 +1,62 @@
//
// Copyright 2018 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_CORE_EXT_XDS_UPB_UTILS_H
#define GRPC_CORE_EXT_XDS_UPB_UTILS_H
#include <grpc/support/port_platform.h>
#include <string>
#include "absl/strings/string_view.h"
#include "upb/text_encode.h"
#include "upb/upb.h"
#include "upb/upb.hpp"
#include "src/core/ext/xds/certificate_provider_store.h"
#include "src/core/lib/debug/trace.h"
namespace grpc_core {
class XdsClient;
struct XdsEncodingContext {
XdsClient* client; // Used only for logging. Unsafe for dereferencing.
TraceFlag* tracer;
upb_symtab* symtab;
upb_arena* arena;
bool use_v3;
const CertificateProviderStore::PluginDefinitionMap*
certificate_provider_definition_map;
};
// Works for both std::string and absl::string_view.
template <typename T>
inline upb_strview StdStringToUpbString(const T& str) {
return upb_strview_make(str.data(), str.size());
}
inline absl::string_view UpbStringToAbsl(const upb_strview& str) {
return absl::string_view(str.data, str.size);
}
inline std::string UpbStringToStdString(const upb_strview& str) {
return std::string(str.data, str.size);
}
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_UPB_UTILS_H

File diff suppressed because it is too large Load Diff

@ -1,20 +1,18 @@
/*
*
* Copyright 2018 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.
*
*/
//
// Copyright 2018 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_CORE_EXT_XDS_XDS_API_H
#define GRPC_CORE_EXT_XDS_XDS_API_H
@ -37,14 +35,16 @@
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/ext/xds/xds_bootstrap.h"
#include "src/core/ext/xds/xds_client_stats.h"
#include "src/core/ext/xds/xds_cluster.h"
#include "src/core/ext/xds/xds_endpoint.h"
#include "src/core/ext/xds/xds_http_filters.h"
#include "src/core/ext/xds/xds_listener.h"
#include "src/core/ext/xds/xds_route_config.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/matchers/matchers.h"
namespace grpc_core {
bool XdsRbacEnabled();
class XdsClient;
class XdsApi {
@ -54,362 +54,6 @@ class XdsApi {
static const char* kCdsTypeUrl;
static const char* kEdsTypeUrl;
struct Duration {
Duration() {}
int64_t seconds = 0;
int32_t nanos = 0;
bool operator==(const Duration& other) const {
return seconds == other.seconds && nanos == other.nanos;
}
std::string ToString() const {
return absl::StrFormat("Duration seconds: %ld, nanos %d", seconds, nanos);
}
};
using TypedPerFilterConfig =
std::map<std::string, XdsHttpFilterImpl::FilterConfig>;
struct RetryPolicy {
internal::StatusCodeSet retry_on;
uint32_t num_retries;
struct RetryBackOff {
Duration base_interval;
Duration max_interval;
bool operator==(const RetryBackOff& other) const {
return base_interval == other.base_interval &&
max_interval == other.max_interval;
}
std::string ToString() const;
};
RetryBackOff retry_back_off;
bool operator==(const RetryPolicy& other) const {
return (retry_on == other.retry_on && num_retries == other.num_retries &&
retry_back_off == other.retry_back_off);
}
std::string ToString() const;
};
// TODO(donnadionne): When we can use absl::variant<>, consider using that
// for: PathMatcher, HeaderMatcher, cluster_name and weighted_clusters
struct Route {
// Matchers for this route.
struct Matchers {
StringMatcher path_matcher;
std::vector<HeaderMatcher> header_matchers;
absl::optional<uint32_t> fraction_per_million;
bool operator==(const Matchers& other) const {
return path_matcher == other.path_matcher &&
header_matchers == other.header_matchers &&
fraction_per_million == other.fraction_per_million;
}
std::string ToString() const;
};
Matchers matchers;
struct UnknownAction {
bool operator==(const UnknownAction& /* other */) const { return true; }
};
struct RouteAction {
struct HashPolicy {
enum Type { HEADER, CHANNEL_ID };
Type type;
bool terminal = false;
// Fields used for type HEADER.
std::string header_name;
std::unique_ptr<RE2> regex = nullptr;
std::string regex_substitution;
HashPolicy() {}
// Copyable.
HashPolicy(const HashPolicy& other);
HashPolicy& operator=(const HashPolicy& other);
// Moveable.
HashPolicy(HashPolicy&& other) noexcept;
HashPolicy& operator=(HashPolicy&& other) noexcept;
bool operator==(const HashPolicy& other) const;
std::string ToString() const;
};
struct ClusterWeight {
std::string name;
uint32_t weight;
TypedPerFilterConfig typed_per_filter_config;
bool operator==(const ClusterWeight& other) const {
return name == other.name && weight == other.weight &&
typed_per_filter_config == other.typed_per_filter_config;
}
std::string ToString() const;
};
std::vector<HashPolicy> hash_policies;
absl::optional<RetryPolicy> retry_policy;
// Action for this route.
// TODO(roth): When we can use absl::variant<>, consider using that
// here, to enforce the fact that only one of the two fields can be set.
std::string cluster_name;
std::vector<ClusterWeight> weighted_clusters;
// Storing the timeout duration from route action:
// RouteAction.max_stream_duration.grpc_timeout_header_max or
// RouteAction.max_stream_duration.max_stream_duration if the former is
// not set.
absl::optional<Duration> max_stream_duration;
bool operator==(const RouteAction& other) const {
return hash_policies == other.hash_policies &&
retry_policy == other.retry_policy &&
cluster_name == other.cluster_name &&
weighted_clusters == other.weighted_clusters &&
max_stream_duration == other.max_stream_duration;
}
std::string ToString() const;
};
struct NonForwardingAction {
bool operator==(const NonForwardingAction& /* other */) const {
return true;
}
};
absl::variant<UnknownAction, RouteAction, NonForwardingAction> action;
TypedPerFilterConfig typed_per_filter_config;
bool operator==(const Route& other) const {
return matchers == other.matchers && action == other.action &&
typed_per_filter_config == other.typed_per_filter_config;
}
std::string ToString() const;
};
struct RdsUpdate {
struct VirtualHost {
std::vector<std::string> domains;
std::vector<Route> routes;
TypedPerFilterConfig typed_per_filter_config;
bool operator==(const VirtualHost& other) const {
return domains == other.domains && routes == other.routes &&
typed_per_filter_config == other.typed_per_filter_config;
}
};
std::vector<VirtualHost> virtual_hosts;
bool operator==(const RdsUpdate& other) const {
return virtual_hosts == other.virtual_hosts;
}
std::string ToString() const;
};
struct CommonTlsContext {
struct CertificateProviderPluginInstance {
std::string instance_name;
std::string certificate_name;
bool operator==(const CertificateProviderPluginInstance& other) const {
return instance_name == other.instance_name &&
certificate_name == other.certificate_name;
}
std::string ToString() const;
bool Empty() const;
};
struct CertificateValidationContext {
CertificateProviderPluginInstance ca_certificate_provider_instance;
std::vector<StringMatcher> match_subject_alt_names;
bool operator==(const CertificateValidationContext& other) const {
return ca_certificate_provider_instance ==
other.ca_certificate_provider_instance &&
match_subject_alt_names == other.match_subject_alt_names;
}
std::string ToString() const;
bool Empty() const;
};
CertificateValidationContext certificate_validation_context;
CertificateProviderPluginInstance tls_certificate_provider_instance;
bool operator==(const CommonTlsContext& other) const {
return certificate_validation_context ==
other.certificate_validation_context &&
tls_certificate_provider_instance ==
other.tls_certificate_provider_instance;
}
std::string ToString() const;
bool Empty() const;
};
struct DownstreamTlsContext {
CommonTlsContext common_tls_context;
bool require_client_certificate = false;
bool operator==(const DownstreamTlsContext& other) const {
return common_tls_context == other.common_tls_context &&
require_client_certificate == other.require_client_certificate;
}
std::string ToString() const;
bool Empty() const;
};
// TODO(roth): When we can use absl::variant<>, consider using that
// here, to enforce the fact that only one of the two fields can be set.
struct LdsUpdate {
enum class ListenerType {
kTcpListener = 0,
kHttpApiListener,
} type;
struct HttpConnectionManager {
// The name to use in the RDS request.
std::string route_config_name;
// Storing the Http Connection Manager Common Http Protocol Option
// max_stream_duration
Duration http_max_stream_duration;
// The RouteConfiguration to use for this listener.
// Present only if it is inlined in the LDS response.
absl::optional<RdsUpdate> rds_update;
struct HttpFilter {
std::string name;
XdsHttpFilterImpl::FilterConfig config;
bool operator==(const HttpFilter& other) const {
return name == other.name && config == other.config;
}
std::string ToString() const;
};
std::vector<HttpFilter> http_filters;
bool operator==(const HttpConnectionManager& other) const {
return route_config_name == other.route_config_name &&
http_max_stream_duration == other.http_max_stream_duration &&
rds_update == other.rds_update &&
http_filters == other.http_filters;
}
std::string ToString() const;
};
// Populated for type=kHttpApiListener.
HttpConnectionManager http_connection_manager;
// Populated for type=kTcpListener.
// host:port listening_address set when type is kTcpListener
std::string address;
struct FilterChainData {
DownstreamTlsContext downstream_tls_context;
// This is in principle the filter list.
// We currently require exactly one filter, which is the HCM.
HttpConnectionManager http_connection_manager;
bool operator==(const FilterChainData& other) const {
return downstream_tls_context == other.downstream_tls_context &&
http_connection_manager == other.http_connection_manager;
}
std::string ToString() const;
};
// A multi-level map used to determine which filter chain to use for a given
// incoming connection. Determining the right filter chain for a given
// connection checks the following properties, in order:
// - destination port (never matched, so not present in map)
// - destination IP address
// - server name (never matched, so not present in map)
// - transport protocol (allows only "raw_buffer" or unset, prefers the
// former, so only one of those two types is present in map)
// - application protocol (never matched, so not present in map)
// - connection source type (any, local or external)
// - source IP address
// - source port
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/listener/v3/listener_components.proto#config-listener-v3-filterchainmatch
// for more details
struct FilterChainMap {
struct FilterChainDataSharedPtr {
std::shared_ptr<FilterChainData> data;
bool operator==(const FilterChainDataSharedPtr& other) const {
return *data == *other.data;
}
};
struct CidrRange {
grpc_resolved_address address;
uint32_t prefix_len;
bool operator==(const CidrRange& other) const {
return memcmp(&address, &other.address, sizeof(address)) == 0 &&
prefix_len == other.prefix_len;
}
std::string ToString() const;
};
using SourcePortsMap = std::map<uint16_t, FilterChainDataSharedPtr>;
struct SourceIp {
absl::optional<CidrRange> prefix_range;
SourcePortsMap ports_map;
bool operator==(const SourceIp& other) const {
return prefix_range == other.prefix_range &&
ports_map == other.ports_map;
}
};
using SourceIpVector = std::vector<SourceIp>;
enum class ConnectionSourceType {
kAny = 0,
kSameIpOrLoopback,
kExternal
};
using ConnectionSourceTypesArray = std::array<SourceIpVector, 3>;
struct DestinationIp {
absl::optional<CidrRange> prefix_range;
// We always fail match on server name, so those filter chains are not
// included here.
ConnectionSourceTypesArray source_types_array;
bool operator==(const DestinationIp& other) const {
return prefix_range == other.prefix_range &&
source_types_array == other.source_types_array;
}
};
// We always fail match on destination ports map
using DestinationIpVector = std::vector<DestinationIp>;
DestinationIpVector destination_ip_vector;
bool operator==(const FilterChainMap& other) const {
return destination_ip_vector == other.destination_ip_vector;
}
std::string ToString() const;
} filter_chain_map;
absl::optional<FilterChainData> default_filter_chain;
bool operator==(const LdsUpdate& other) const {
return http_connection_manager == other.http_connection_manager &&
address == other.address &&
filter_chain_map == other.filter_chain_map &&
default_filter_chain == other.default_filter_chain;
}
std::string ToString() const;
};
struct ResourceName {
std::string authority;
std::string id;
@ -422,162 +66,27 @@ class XdsApi {
};
struct LdsResourceData {
LdsUpdate resource;
XdsListenerResource resource;
std::string serialized_proto;
};
using LdsUpdateMap = std::map<ResourceName, LdsResourceData>;
struct RdsResourceData {
RdsUpdate resource;
XdsRouteConfigResource resource;
std::string serialized_proto;
};
using RdsUpdateMap = std::map<ResourceName, RdsResourceData>;
struct CdsUpdate {
enum ClusterType { EDS, LOGICAL_DNS, AGGREGATE };
ClusterType cluster_type;
// For cluster type EDS.
// The name to use in the EDS request.
// If empty, the cluster name will be used.
std::string eds_service_name;
// For cluster type LOGICAL_DNS.
// The hostname to lookup in DNS.
std::string dns_hostname;
// For cluster type AGGREGATE.
// The prioritized list of cluster names.
std::vector<std::string> prioritized_cluster_names;
// Tls Context used by clients
CommonTlsContext common_tls_context;
// The LRS server to use for load reporting.
// If not set, load reporting will be disabled.
// If set to the empty string, will use the same server we obtained the CDS
// data from.
absl::optional<std::string> lrs_load_reporting_server_name;
// The LB policy to use (e.g., "ROUND_ROBIN" or "RING_HASH").
std::string lb_policy;
// Used for RING_HASH LB policy only.
uint64_t min_ring_size = 1024;
uint64_t max_ring_size = 8388608;
// Maximum number of outstanding requests can be made to the upstream
// cluster.
uint32_t max_concurrent_requests = 1024;
bool operator==(const CdsUpdate& other) const {
return cluster_type == other.cluster_type &&
eds_service_name == other.eds_service_name &&
dns_hostname == other.dns_hostname &&
prioritized_cluster_names == other.prioritized_cluster_names &&
common_tls_context == other.common_tls_context &&
lrs_load_reporting_server_name ==
other.lrs_load_reporting_server_name &&
lb_policy == other.lb_policy &&
min_ring_size == other.min_ring_size &&
max_ring_size == other.max_ring_size &&
max_concurrent_requests == other.max_concurrent_requests;
}
std::string ToString() const;
};
struct CdsResourceData {
CdsUpdate resource;
XdsClusterResource resource;
std::string serialized_proto;
};
using CdsUpdateMap = std::map<ResourceName, CdsResourceData>;
struct EdsUpdate {
struct Priority {
struct Locality {
RefCountedPtr<XdsLocalityName> name;
uint32_t lb_weight;
ServerAddressList endpoints;
bool operator==(const Locality& other) const {
return *name == *other.name && lb_weight == other.lb_weight &&
endpoints == other.endpoints;
}
bool operator!=(const Locality& other) const {
return !(*this == other);
}
std::string ToString() const;
};
std::map<XdsLocalityName*, Locality, XdsLocalityName::Less> localities;
bool operator==(const Priority& other) const;
std::string ToString() const;
};
using PriorityList = absl::InlinedVector<Priority, 2>;
// There are two phases of accessing this class's content:
// 1. to initialize in the control plane combiner;
// 2. to use in the data plane combiner.
// So no additional synchronization is needed.
class DropConfig : public RefCounted<DropConfig> {
public:
struct DropCategory {
bool operator==(const DropCategory& other) const {
return name == other.name &&
parts_per_million == other.parts_per_million;
}
std::string name;
const uint32_t parts_per_million;
};
using DropCategoryList = absl::InlinedVector<DropCategory, 2>;
void AddCategory(std::string name, uint32_t parts_per_million) {
drop_category_list_.emplace_back(
DropCategory{std::move(name), parts_per_million});
if (parts_per_million == 1000000) drop_all_ = true;
}
// The only method invoked from outside the WorkSerializer (used in
// the data plane).
bool ShouldDrop(const std::string** category_name) const;
const DropCategoryList& drop_category_list() const {
return drop_category_list_;
}
bool drop_all() const { return drop_all_; }
bool operator==(const DropConfig& other) const {
return drop_category_list_ == other.drop_category_list_;
}
bool operator!=(const DropConfig& other) const {
return !(*this == other);
}
std::string ToString() const;
private:
DropCategoryList drop_category_list_;
bool drop_all_ = false;
};
PriorityList priorities;
RefCountedPtr<DropConfig> drop_config;
bool operator==(const EdsUpdate& other) const {
return priorities == other.priorities &&
*drop_config == *other.drop_config;
}
std::string ToString() const;
};
struct EdsResourceData {
EdsUpdate resource;
XdsEndpointResource resource;
std::string serialized_proto;
};
using EdsUpdateMap = std::map<ResourceName, EdsResourceData>;
struct ClusterLoadReport {
@ -743,4 +252,4 @@ class XdsApi {
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_XDS_XDS_API_H */
#endif // GRPC_CORE_EXT_XDS_XDS_API_H

@ -994,7 +994,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdateLocked(
auto& lds_state = state_map_[XdsApi::kLdsTypeUrl];
for (auto& p : lds_update_map) {
const XdsApi::ResourceName& name = p.first;
XdsApi::LdsUpdate& lds_update = p.second.resource;
XdsListenerResource& lds_update = p.second.resource;
auto it = lds_state.subscribed_resources.find(name.authority);
if (it != lds_state.subscribed_resources.end()) {
auto res_it = it->second.find(name.id);
@ -1094,7 +1094,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdateLocked(
auto& rds_state = state_map_[XdsApi::kRdsTypeUrl];
for (auto& p : rds_update_map) {
const XdsApi::ResourceName& name = p.first;
XdsApi::RdsUpdate& rds_update = p.second.resource;
XdsRouteConfigResource& rds_update = p.second.resource;
auto it = rds_state.subscribed_resources.find(name.authority);
if (it != rds_state.subscribed_resources.end()) {
auto res_it = it->second.find(name.id);
@ -1151,7 +1151,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdateLocked(
auto& cds_state = state_map_[XdsApi::kCdsTypeUrl];
for (auto& p : cds_update_map) {
const XdsApi::ResourceName& name = p.first;
XdsApi::CdsUpdate& cds_update = p.second.resource;
XdsClusterResource& cds_update = p.second.resource;
auto it = cds_state.subscribed_resources.find(name.authority);
if (it != cds_state.subscribed_resources.end()) {
auto res_it = it->second.find(name.id);
@ -1245,7 +1245,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdateLocked(
auto& eds_state = state_map_[XdsApi::kEdsTypeUrl];
for (auto& p : eds_update_map) {
const XdsApi::ResourceName& name = p.first;
XdsApi::EdsUpdate& eds_update = p.second.resource;
XdsEndpointResource& eds_update = p.second.resource;
auto it = eds_state.subscribed_resources.find(name.authority);
if (it != eds_state.subscribed_resources.end()) {
auto res_it = it->second.find(name.id);

@ -46,7 +46,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
// Listener data watcher interface. Implemented by callers.
class ListenerWatcherInterface : public RefCounted<ListenerWatcherInterface> {
public:
virtual void OnListenerChanged(XdsApi::LdsUpdate listener)
virtual void OnListenerChanged(XdsListenerResource listener)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&work_serializer_) = 0;
virtual void OnError(grpc_error_handle error)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&work_serializer_) = 0;
@ -58,7 +58,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
class RouteConfigWatcherInterface
: public RefCounted<RouteConfigWatcherInterface> {
public:
virtual void OnRouteConfigChanged(XdsApi::RdsUpdate route_config)
virtual void OnRouteConfigChanged(XdsRouteConfigResource route_config)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&work_serializer_) = 0;
virtual void OnError(grpc_error_handle error)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&work_serializer_) = 0;
@ -69,7 +69,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
// Cluster data watcher interface. Implemented by callers.
class ClusterWatcherInterface : public RefCounted<ClusterWatcherInterface> {
public:
virtual void OnClusterChanged(XdsApi::CdsUpdate cluster_data)
virtual void OnClusterChanged(XdsClusterResource cluster_data)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&work_serializer_) = 0;
virtual void OnError(grpc_error_handle error)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&work_serializer_) = 0;
@ -80,7 +80,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
// Endpoint data watcher interface. Implemented by callers.
class EndpointWatcherInterface : public RefCounted<EndpointWatcherInterface> {
public:
virtual void OnEndpointChanged(XdsApi::EdsUpdate update)
virtual void OnEndpointChanged(XdsEndpointResource update)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&work_serializer_) = 0;
virtual void OnError(grpc_error_handle error)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&work_serializer_) = 0;
@ -268,7 +268,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
std::map<ListenerWatcherInterface*, RefCountedPtr<ListenerWatcherInterface>>
watchers;
// The latest data seen from LDS.
absl::optional<XdsApi::LdsUpdate> update;
absl::optional<XdsListenerResource> update;
XdsApi::ResourceMetadata meta;
};
@ -277,7 +277,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
RefCountedPtr<RouteConfigWatcherInterface>>
watchers;
// The latest data seen from RDS.
absl::optional<XdsApi::RdsUpdate> update;
absl::optional<XdsRouteConfigResource> update;
XdsApi::ResourceMetadata meta;
};
@ -285,7 +285,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
std::map<ClusterWatcherInterface*, RefCountedPtr<ClusterWatcherInterface>>
watchers;
// The latest data seen from CDS.
absl::optional<XdsApi::CdsUpdate> update;
absl::optional<XdsClusterResource> update;
XdsApi::ResourceMetadata meta;
};
@ -293,7 +293,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
std::map<EndpointWatcherInterface*, RefCountedPtr<EndpointWatcherInterface>>
watchers;
// The latest data seen from EDS.
absl::optional<XdsApi::EdsUpdate> update;
absl::optional<XdsEndpointResource> update;
XdsApi::ResourceMetadata meta;
};

@ -0,0 +1,442 @@
//
// Copyright 2018 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 <grpc/support/port_platform.h>
#include "src/core/ext/xds/xds_cluster.h"
#include "absl/container/inlined_vector.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "envoy/config/cluster/v3/circuit_breaker.upb.h"
#include "envoy/config/cluster/v3/cluster.upb.h"
#include "envoy/config/cluster/v3/cluster.upbdefs.h"
#include "envoy/config/core/v3/address.upb.h"
#include "envoy/config/core/v3/base.upb.h"
#include "envoy/config/core/v3/config_source.upb.h"
#include "envoy/config/endpoint/v3/endpoint.upb.h"
#include "envoy/config/endpoint/v3/endpoint_components.upb.h"
#include "envoy/extensions/clusters/aggregate/v3/cluster.upb.h"
#include "google/protobuf/any.upb.h"
#include "google/protobuf/wrappers.upb.h"
#include <grpc/support/alloc.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/host_port.h"
namespace grpc_core {
//
// XdsClusterResource
//
std::string XdsClusterResource::ToString() const {
absl::InlinedVector<std::string, 8> contents;
switch (cluster_type) {
case EDS:
contents.push_back("cluster_type=EDS");
if (!eds_service_name.empty()) {
contents.push_back(
absl::StrFormat("eds_service_name=%s", eds_service_name));
}
break;
case LOGICAL_DNS:
contents.push_back("cluster_type=LOGICAL_DNS");
contents.push_back(absl::StrFormat("dns_hostname=%s", dns_hostname));
break;
case AGGREGATE:
contents.push_back("cluster_type=AGGREGATE");
contents.push_back(
absl::StrFormat("prioritized_cluster_names=[%s]",
absl::StrJoin(prioritized_cluster_names, ", ")));
}
if (!common_tls_context.Empty()) {
contents.push_back(absl::StrFormat("common_tls_context=%s",
common_tls_context.ToString()));
}
if (lrs_load_reporting_server_name.has_value()) {
contents.push_back(absl::StrFormat("lrs_load_reporting_server_name=%s",
lrs_load_reporting_server_name.value()));
}
contents.push_back(absl::StrCat("lb_policy=", lb_policy));
if (lb_policy == "RING_HASH") {
contents.push_back(absl::StrCat("min_ring_size=", min_ring_size));
contents.push_back(absl::StrCat("max_ring_size=", max_ring_size));
}
contents.push_back(
absl::StrFormat("max_concurrent_requests=%d", max_concurrent_requests));
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
//
// XdsClusterResourceType
//
namespace {
grpc_error_handle UpstreamTlsContextParse(
const XdsEncodingContext& context,
const envoy_config_core_v3_TransportSocket* transport_socket,
CommonTlsContext* common_tls_context) {
// Record Upstream tls context
absl::string_view name = UpbStringToAbsl(
envoy_config_core_v3_TransportSocket_name(transport_socket));
if (name != "envoy.transport_sockets.tls") {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("Unrecognized transport socket: ", name));
}
auto* typed_config =
envoy_config_core_v3_TransportSocket_typed_config(transport_socket);
if (typed_config != nullptr) {
const upb_strview encoded_upstream_tls_context =
google_protobuf_Any_value(typed_config);
auto* upstream_tls_context =
envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_parse(
encoded_upstream_tls_context.data,
encoded_upstream_tls_context.size, context.arena);
if (upstream_tls_context == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Can't decode upstream tls context.");
}
auto* common_tls_context_proto =
envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_common_tls_context(
upstream_tls_context);
if (common_tls_context_proto != nullptr) {
grpc_error_handle error = CommonTlsContext::Parse(
context, common_tls_context_proto, common_tls_context);
if (error != GRPC_ERROR_NONE) {
return grpc_error_add_child(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Error parsing UpstreamTlsContext"),
error);
}
}
}
if (common_tls_context->certificate_validation_context
.ca_certificate_provider_instance.instance_name.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"UpstreamTlsContext: TLS configuration provided but no "
"ca_certificate_provider_instance found.");
}
return GRPC_ERROR_NONE;
}
grpc_error_handle CdsLogicalDnsParse(
const envoy_config_cluster_v3_Cluster* cluster,
XdsClusterResource* cds_update) {
const auto* load_assignment =
envoy_config_cluster_v3_Cluster_load_assignment(cluster);
if (load_assignment == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"load_assignment not present for LOGICAL_DNS cluster");
}
size_t num_localities;
const auto* const* localities =
envoy_config_endpoint_v3_ClusterLoadAssignment_endpoints(load_assignment,
&num_localities);
if (num_localities != 1) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("load_assignment for LOGICAL_DNS cluster must have "
"exactly one locality, found ",
num_localities));
}
size_t num_endpoints;
const auto* const* endpoints =
envoy_config_endpoint_v3_LocalityLbEndpoints_lb_endpoints(localities[0],
&num_endpoints);
if (num_endpoints != 1) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("locality for LOGICAL_DNS cluster must have "
"exactly one endpoint, found ",
num_endpoints));
}
const auto* endpoint =
envoy_config_endpoint_v3_LbEndpoint_endpoint(endpoints[0]);
if (endpoint == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"LbEndpoint endpoint field not set");
}
const auto* address = envoy_config_endpoint_v3_Endpoint_address(endpoint);
if (address == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Endpoint address field not set");
}
const auto* socket_address =
envoy_config_core_v3_Address_socket_address(address);
if (socket_address == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Address socket_address field not set");
}
if (envoy_config_core_v3_SocketAddress_resolver_name(socket_address).size !=
0) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"LOGICAL_DNS clusters must NOT have a custom resolver name set");
}
absl::string_view address_str = UpbStringToAbsl(
envoy_config_core_v3_SocketAddress_address(socket_address));
if (address_str.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"SocketAddress address field not set");
}
if (!envoy_config_core_v3_SocketAddress_has_port_value(socket_address)) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"SocketAddress port_value field not set");
}
cds_update->dns_hostname = JoinHostPort(
address_str,
envoy_config_core_v3_SocketAddress_port_value(socket_address));
return GRPC_ERROR_NONE;
}
// TODO(donnadionne): Check to see if cluster types aggregate_cluster and
// logical_dns are enabled, this will be
// removed once the cluster types are fully integration-tested and enabled by
// default.
bool XdsAggregateAndLogicalDnsClusterEnabled() {
char* value = gpr_getenv(
"GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
bool parsed_value;
bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
gpr_free(value);
return parse_succeeded && parsed_value;
}
grpc_error_handle CdsResourceParse(
const XdsEncodingContext& context,
const envoy_config_cluster_v3_Cluster* cluster, bool /*is_v2*/,
XdsClusterResource* cds_update) {
std::vector<grpc_error_handle> errors;
// Check the cluster_discovery_type.
if (!envoy_config_cluster_v3_Cluster_has_type(cluster) &&
!envoy_config_cluster_v3_Cluster_has_cluster_type(cluster)) {
errors.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("DiscoveryType not found."));
} else if (envoy_config_cluster_v3_Cluster_type(cluster) ==
envoy_config_cluster_v3_Cluster_EDS) {
cds_update->cluster_type = XdsClusterResource::ClusterType::EDS;
// Check the EDS config source.
const envoy_config_cluster_v3_Cluster_EdsClusterConfig* eds_cluster_config =
envoy_config_cluster_v3_Cluster_eds_cluster_config(cluster);
const envoy_config_core_v3_ConfigSource* eds_config =
envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_config(
eds_cluster_config);
if (!envoy_config_core_v3_ConfigSource_has_ads(eds_config)) {
errors.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("EDS ConfigSource is not ADS."));
}
// Record EDS service_name (if any).
upb_strview service_name =
envoy_config_cluster_v3_Cluster_EdsClusterConfig_service_name(
eds_cluster_config);
if (service_name.size != 0) {
cds_update->eds_service_name = UpbStringToStdString(service_name);
}
} else if (!XdsAggregateAndLogicalDnsClusterEnabled()) {
errors.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("DiscoveryType is not valid."));
} else if (envoy_config_cluster_v3_Cluster_type(cluster) ==
envoy_config_cluster_v3_Cluster_LOGICAL_DNS) {
cds_update->cluster_type = XdsClusterResource::ClusterType::LOGICAL_DNS;
grpc_error_handle error = CdsLogicalDnsParse(cluster, cds_update);
if (error != GRPC_ERROR_NONE) errors.push_back(error);
} else {
if (!envoy_config_cluster_v3_Cluster_has_cluster_type(cluster)) {
errors.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("DiscoveryType is not valid."));
} else {
const envoy_config_cluster_v3_Cluster_CustomClusterType*
custom_cluster_type =
envoy_config_cluster_v3_Cluster_cluster_type(cluster);
upb_strview type_name =
envoy_config_cluster_v3_Cluster_CustomClusterType_name(
custom_cluster_type);
if (UpbStringToAbsl(type_name) != "envoy.clusters.aggregate") {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"DiscoveryType is not valid."));
} else {
cds_update->cluster_type = XdsClusterResource::ClusterType::AGGREGATE;
// Retrieve aggregate clusters.
const google_protobuf_Any* typed_config =
envoy_config_cluster_v3_Cluster_CustomClusterType_typed_config(
custom_cluster_type);
const upb_strview aggregate_cluster_config_upb_strview =
google_protobuf_Any_value(typed_config);
const envoy_extensions_clusters_aggregate_v3_ClusterConfig*
aggregate_cluster_config =
envoy_extensions_clusters_aggregate_v3_ClusterConfig_parse(
aggregate_cluster_config_upb_strview.data,
aggregate_cluster_config_upb_strview.size, context.arena);
if (aggregate_cluster_config == nullptr) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Can't parse aggregate cluster."));
} else {
size_t size;
const upb_strview* clusters =
envoy_extensions_clusters_aggregate_v3_ClusterConfig_clusters(
aggregate_cluster_config, &size);
for (size_t i = 0; i < size; ++i) {
const upb_strview cluster = clusters[i];
cds_update->prioritized_cluster_names.emplace_back(
UpbStringToStdString(cluster));
}
}
}
}
}
// Check the LB policy.
if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
envoy_config_cluster_v3_Cluster_ROUND_ROBIN) {
cds_update->lb_policy = "ROUND_ROBIN";
} else if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
envoy_config_cluster_v3_Cluster_RING_HASH) {
cds_update->lb_policy = "RING_HASH";
// Record ring hash lb config
auto* ring_hash_config =
envoy_config_cluster_v3_Cluster_ring_hash_lb_config(cluster);
if (ring_hash_config != nullptr) {
const google_protobuf_UInt64Value* max_ring_size =
envoy_config_cluster_v3_Cluster_RingHashLbConfig_maximum_ring_size(
ring_hash_config);
if (max_ring_size != nullptr) {
cds_update->max_ring_size =
google_protobuf_UInt64Value_value(max_ring_size);
if (cds_update->max_ring_size > 8388608 ||
cds_update->max_ring_size == 0) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"max_ring_size is not in the range of 1 to 8388608."));
}
}
const google_protobuf_UInt64Value* min_ring_size =
envoy_config_cluster_v3_Cluster_RingHashLbConfig_minimum_ring_size(
ring_hash_config);
if (min_ring_size != nullptr) {
cds_update->min_ring_size =
google_protobuf_UInt64Value_value(min_ring_size);
if (cds_update->min_ring_size > 8388608 ||
cds_update->min_ring_size == 0) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"min_ring_size is not in the range of 1 to 8388608."));
}
if (cds_update->min_ring_size > cds_update->max_ring_size) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"min_ring_size cannot be greater than max_ring_size."));
}
}
if (envoy_config_cluster_v3_Cluster_RingHashLbConfig_hash_function(
ring_hash_config) !=
envoy_config_cluster_v3_Cluster_RingHashLbConfig_XX_HASH) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"ring hash lb config has invalid hash function."));
}
}
} else {
errors.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("LB policy is not supported."));
}
auto* transport_socket =
envoy_config_cluster_v3_Cluster_transport_socket(cluster);
if (transport_socket != nullptr) {
grpc_error_handle error = UpstreamTlsContextParse(
context, transport_socket, &cds_update->common_tls_context);
if (error != GRPC_ERROR_NONE) {
errors.push_back(
grpc_error_add_child(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Error parsing security configuration"),
error));
}
}
// Record LRS server name (if any).
const envoy_config_core_v3_ConfigSource* lrs_server =
envoy_config_cluster_v3_Cluster_lrs_server(cluster);
if (lrs_server != nullptr) {
if (!envoy_config_core_v3_ConfigSource_has_self(lrs_server)) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
": LRS ConfigSource is not self."));
}
cds_update->lrs_load_reporting_server_name.emplace("");
}
// The Cluster resource encodes the circuit breaking parameters in a list of
// Thresholds messages, where each message specifies the parameters for a
// particular RoutingPriority. we will look only at the first entry in the
// list for priority DEFAULT and default to 1024 if not found.
if (envoy_config_cluster_v3_Cluster_has_circuit_breakers(cluster)) {
const envoy_config_cluster_v3_CircuitBreakers* circuit_breakers =
envoy_config_cluster_v3_Cluster_circuit_breakers(cluster);
size_t num_thresholds;
const envoy_config_cluster_v3_CircuitBreakers_Thresholds* const*
thresholds = envoy_config_cluster_v3_CircuitBreakers_thresholds(
circuit_breakers, &num_thresholds);
for (size_t i = 0; i < num_thresholds; ++i) {
const auto* threshold = thresholds[i];
if (envoy_config_cluster_v3_CircuitBreakers_Thresholds_priority(
threshold) == envoy_config_core_v3_DEFAULT) {
const google_protobuf_UInt32Value* max_requests =
envoy_config_cluster_v3_CircuitBreakers_Thresholds_max_requests(
threshold);
if (max_requests != nullptr) {
cds_update->max_concurrent_requests =
google_protobuf_UInt32Value_value(max_requests);
}
break;
}
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing CDS resource", &errors);
}
void MaybeLogCluster(const XdsEncodingContext& context,
const envoy_config_cluster_v3_Cluster* cluster) {
if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
const upb_msgdef* msg_type =
envoy_config_cluster_v3_Cluster_getmsgdef(context.symtab);
char buf[10240];
upb_text_encode(cluster, msg_type, nullptr, 0, buf, sizeof(buf));
gpr_log(GPR_DEBUG, "[xds_client %p] Cluster: %s", context.client, buf);
}
}
} // namespace
absl::StatusOr<XdsResourceType::DecodeResult> XdsClusterResourceType::Decode(
const XdsEncodingContext& context, absl::string_view serialized_resource,
bool is_v2) const {
// Parse serialized proto.
auto* resource = envoy_config_cluster_v3_Cluster_parse(
serialized_resource.data(), serialized_resource.size(), context.arena);
if (resource == nullptr) {
return absl::InvalidArgumentError("Can't parse Listener resource.");
}
MaybeLogCluster(context, resource);
// Validate resource.
DecodeResult result;
result.name =
UpbStringToStdString(envoy_config_cluster_v3_Cluster_name(resource));
auto cluster_data = absl::make_unique<ClusterData>();
grpc_error_handle error =
CdsResourceParse(context, resource, is_v2, &cluster_data->resource);
if (error != GRPC_ERROR_NONE) {
result.resource = absl::InvalidArgumentError(grpc_error_std_string(error));
GRPC_ERROR_UNREF(error);
} else {
result.resource = std::move(cluster_data);
}
return std::move(result);
}
} // namespace grpc_core

@ -0,0 +1,101 @@
//
// Copyright 2018 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_CORE_EXT_XDS_XDS_CLUSTER_H
#define GRPC_CORE_EXT_XDS_XDS_CLUSTER_H
#include <grpc/support/port_platform.h>
#include <string>
#include <vector>
#include "absl/types/optional.h"
#include "src/core/ext/xds/xds_common_types.h"
#include "src/core/ext/xds/xds_resource_type.h"
namespace grpc_core {
struct XdsClusterResource {
enum ClusterType { EDS, LOGICAL_DNS, AGGREGATE };
ClusterType cluster_type;
// For cluster type EDS.
// The name to use in the EDS request.
// If empty, the cluster name will be used.
std::string eds_service_name;
// For cluster type LOGICAL_DNS.
// The hostname to lookup in DNS.
std::string dns_hostname;
// For cluster type AGGREGATE.
// The prioritized list of cluster names.
std::vector<std::string> prioritized_cluster_names;
// Tls Context used by clients
CommonTlsContext common_tls_context;
// The LRS server to use for load reporting.
// If not set, load reporting will be disabled.
// If set to the empty string, will use the same server we obtained the CDS
// data from.
absl::optional<std::string> lrs_load_reporting_server_name;
// The LB policy to use (e.g., "ROUND_ROBIN" or "RING_HASH").
std::string lb_policy;
// Used for RING_HASH LB policy only.
uint64_t min_ring_size = 1024;
uint64_t max_ring_size = 8388608;
// Maximum number of outstanding requests can be made to the upstream
// cluster.
uint32_t max_concurrent_requests = 1024;
bool operator==(const XdsClusterResource& other) const {
return cluster_type == other.cluster_type &&
eds_service_name == other.eds_service_name &&
dns_hostname == other.dns_hostname &&
prioritized_cluster_names == other.prioritized_cluster_names &&
common_tls_context == other.common_tls_context &&
lrs_load_reporting_server_name ==
other.lrs_load_reporting_server_name &&
lb_policy == other.lb_policy &&
min_ring_size == other.min_ring_size &&
max_ring_size == other.max_ring_size &&
max_concurrent_requests == other.max_concurrent_requests;
}
std::string ToString() const;
};
class XdsClusterResourceType : public XdsResourceType {
public:
struct ClusterData : public ResourceData {
XdsClusterResource resource;
};
absl::string_view type_url() const override {
return "envoy.config.cluster.v3.Cluster";
}
absl::string_view v2_type_url() const override {
return "envoy.api.v2.Cluster";
}
absl::StatusOr<DecodeResult> Decode(const XdsEncodingContext& context,
absl::string_view serialized_resource,
bool is_v2) const override;
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_XDS_CLUSTER_H

@ -0,0 +1,388 @@
//
// Copyright 2018 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 <grpc/support/port_platform.h>
#include "src/core/ext/xds/xds_common_types.h"
#include "absl/container/inlined_vector.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "envoy/extensions/transport_sockets/tls/v3/common.upb.h"
#include "envoy/extensions/transport_sockets/tls/v3/tls.upb.h"
#include "envoy/type/matcher/v3/regex.upb.h"
#include "envoy/type/matcher/v3/string.upb.h"
#include "google/protobuf/any.upb.h"
#include "google/protobuf/wrappers.upb.h"
#include "xds/type/v3/typed_struct.upb.h"
namespace grpc_core {
//
// CommonTlsContext::CertificateValidationContext
//
std::string CommonTlsContext::CertificateValidationContext::ToString() const {
std::vector<std::string> contents;
for (const auto& match : match_subject_alt_names) {
contents.push_back(match.ToString());
}
return absl::StrFormat("{match_subject_alt_names=[%s]}",
absl::StrJoin(contents, ", "));
}
bool CommonTlsContext::CertificateValidationContext::Empty() const {
return match_subject_alt_names.empty();
}
//
// CommonTlsContext::CertificateProviderPluginInstance
//
std::string CommonTlsContext::CertificateProviderPluginInstance::ToString()
const {
absl::InlinedVector<std::string, 2> contents;
if (!instance_name.empty()) {
contents.push_back(absl::StrFormat("instance_name=%s", instance_name));
}
if (!certificate_name.empty()) {
contents.push_back(
absl::StrFormat("certificate_name=%s", certificate_name));
}
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
bool CommonTlsContext::CertificateProviderPluginInstance::Empty() const {
return instance_name.empty() && certificate_name.empty();
}
//
// CommonTlsContext
//
std::string CommonTlsContext::ToString() const {
absl::InlinedVector<std::string, 2> contents;
if (!tls_certificate_provider_instance.Empty()) {
contents.push_back(
absl::StrFormat("tls_certificate_provider_instance=%s",
tls_certificate_provider_instance.ToString()));
}
if (!certificate_validation_context.Empty()) {
contents.push_back(
absl::StrFormat("certificate_validation_context=%s",
certificate_validation_context.ToString()));
}
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
bool CommonTlsContext::Empty() const {
return tls_certificate_provider_instance.Empty() &&
certificate_validation_context.Empty();
}
namespace {
// CertificateProviderInstance is deprecated but we are still supporting it for
// backward compatibility reasons. Note that we still parse the data into the
// same CertificateProviderPluginInstance struct since the fields are the same.
// TODO(yashykt): Remove this once we stop supporting the old way of fetching
// certificate provider instances.
grpc_error_handle CertificateProviderInstanceParse(
const XdsEncodingContext& context,
const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance*
certificate_provider_instance_proto,
CommonTlsContext::CertificateProviderPluginInstance*
certificate_provider_plugin_instance) {
*certificate_provider_plugin_instance = {
UpbStringToStdString(
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance_instance_name(
certificate_provider_instance_proto)),
UpbStringToStdString(
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance_certificate_name(
certificate_provider_instance_proto))};
if (context.certificate_provider_definition_map->find(
certificate_provider_plugin_instance->instance_name) ==
context.certificate_provider_definition_map->end()) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("Unrecognized certificate provider instance name: ",
certificate_provider_plugin_instance->instance_name));
}
return GRPC_ERROR_NONE;
}
grpc_error_handle CertificateProviderPluginInstanceParse(
const XdsEncodingContext& context,
const envoy_extensions_transport_sockets_tls_v3_CertificateProviderPluginInstance*
certificate_provider_plugin_instance_proto,
CommonTlsContext::CertificateProviderPluginInstance*
certificate_provider_plugin_instance) {
*certificate_provider_plugin_instance = {
UpbStringToStdString(
envoy_extensions_transport_sockets_tls_v3_CertificateProviderPluginInstance_instance_name(
certificate_provider_plugin_instance_proto)),
UpbStringToStdString(
envoy_extensions_transport_sockets_tls_v3_CertificateProviderPluginInstance_certificate_name(
certificate_provider_plugin_instance_proto))};
if (context.certificate_provider_definition_map->find(
certificate_provider_plugin_instance->instance_name) ==
context.certificate_provider_definition_map->end()) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("Unrecognized certificate provider instance name: ",
certificate_provider_plugin_instance->instance_name));
}
return GRPC_ERROR_NONE;
}
grpc_error_handle CertificateValidationContextParse(
const XdsEncodingContext& context,
const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext*
certificate_validation_context_proto,
CommonTlsContext::CertificateValidationContext*
certificate_validation_context) {
std::vector<grpc_error_handle> errors;
size_t len = 0;
auto* subject_alt_names_matchers =
envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_match_subject_alt_names(
certificate_validation_context_proto, &len);
for (size_t i = 0; i < len; ++i) {
StringMatcher::Type type;
std::string matcher;
if (envoy_type_matcher_v3_StringMatcher_has_exact(
subject_alt_names_matchers[i])) {
type = StringMatcher::Type::kExact;
matcher = UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_exact(
subject_alt_names_matchers[i]));
} else if (envoy_type_matcher_v3_StringMatcher_has_prefix(
subject_alt_names_matchers[i])) {
type = StringMatcher::Type::kPrefix;
matcher = UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_prefix(
subject_alt_names_matchers[i]));
} else if (envoy_type_matcher_v3_StringMatcher_has_suffix(
subject_alt_names_matchers[i])) {
type = StringMatcher::Type::kSuffix;
matcher = UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_suffix(
subject_alt_names_matchers[i]));
} else if (envoy_type_matcher_v3_StringMatcher_has_contains(
subject_alt_names_matchers[i])) {
type = StringMatcher::Type::kContains;
matcher =
UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_contains(
subject_alt_names_matchers[i]));
} else if (envoy_type_matcher_v3_StringMatcher_has_safe_regex(
subject_alt_names_matchers[i])) {
type = StringMatcher::Type::kSafeRegex;
auto* regex_matcher = envoy_type_matcher_v3_StringMatcher_safe_regex(
subject_alt_names_matchers[i]);
matcher = UpbStringToStdString(
envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
} else {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Invalid StringMatcher specified"));
continue;
}
bool ignore_case = envoy_type_matcher_v3_StringMatcher_ignore_case(
subject_alt_names_matchers[i]);
absl::StatusOr<StringMatcher> string_matcher =
StringMatcher::Create(type, matcher,
/*case_sensitive=*/!ignore_case);
if (!string_matcher.ok()) {
errors.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("string matcher: ", string_matcher.status().message())));
continue;
}
if (type == StringMatcher::Type::kSafeRegex && ignore_case) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"StringMatcher: ignore_case has no effect for SAFE_REGEX."));
continue;
}
certificate_validation_context->match_subject_alt_names.push_back(
std::move(string_matcher.value()));
}
auto* ca_certificate_provider_instance =
envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_ca_certificate_provider_instance(
certificate_validation_context_proto);
if (ca_certificate_provider_instance != nullptr) {
grpc_error_handle error = CertificateProviderPluginInstanceParse(
context, ca_certificate_provider_instance,
&certificate_validation_context->ca_certificate_provider_instance);
if (error != GRPC_ERROR_NONE) errors.push_back(error);
}
if (envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_verify_certificate_spki(
certificate_validation_context_proto, nullptr) != nullptr) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"CertificateValidationContext: verify_certificate_spki "
"unsupported"));
}
if (envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_verify_certificate_hash(
certificate_validation_context_proto, nullptr) != nullptr) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"CertificateValidationContext: verify_certificate_hash "
"unsupported"));
}
auto* require_signed_certificate_timestamp =
envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_require_signed_certificate_timestamp(
certificate_validation_context_proto);
if (require_signed_certificate_timestamp != nullptr &&
google_protobuf_BoolValue_value(require_signed_certificate_timestamp)) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"CertificateValidationContext: "
"require_signed_certificate_timestamp unsupported"));
}
if (envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_has_crl(
certificate_validation_context_proto)) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"CertificateValidationContext: crl unsupported"));
}
if (envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_has_custom_validator_config(
certificate_validation_context_proto)) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"CertificateValidationContext: custom_validator_config "
"unsupported"));
}
return GRPC_ERROR_CREATE_FROM_VECTOR(
"Error parsing CertificateValidationContext", &errors);
}
} // namespace
grpc_error_handle CommonTlsContext::Parse(
const XdsEncodingContext& context,
const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
common_tls_context_proto,
CommonTlsContext* common_tls_context) {
std::vector<grpc_error_handle> errors;
// The validation context is derived from the oneof in
// 'validation_context_type'. 'validation_context_sds_secret_config' is not
// supported.
auto* combined_validation_context =
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_combined_validation_context(
common_tls_context_proto);
if (combined_validation_context != nullptr) {
auto* default_validation_context =
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CombinedCertificateValidationContext_default_validation_context(
combined_validation_context);
if (default_validation_context != nullptr) {
grpc_error_handle error = CertificateValidationContextParse(
context, default_validation_context,
&common_tls_context->certificate_validation_context);
if (error != GRPC_ERROR_NONE) errors.push_back(error);
}
// If after parsing default_validation_context,
// common_tls_context->certificate_validation_context.ca_certificate_provider_instance
// is empty, fall back onto
// 'validation_context_certificate_provider_instance' inside
// 'combined_validation_context'. Note that this way of fetching root
// certificates is deprecated and will be removed in the future.
// TODO(yashykt): Remove this once it's no longer needed.
auto* validation_context_certificate_provider_instance =
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CombinedCertificateValidationContext_validation_context_certificate_provider_instance(
combined_validation_context);
if (common_tls_context->certificate_validation_context
.ca_certificate_provider_instance.Empty() &&
validation_context_certificate_provider_instance != nullptr) {
grpc_error_handle error = CertificateProviderInstanceParse(
context, validation_context_certificate_provider_instance,
&common_tls_context->certificate_validation_context
.ca_certificate_provider_instance);
if (error != GRPC_ERROR_NONE) errors.push_back(error);
}
} else {
auto* validation_context =
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_validation_context(
common_tls_context_proto);
if (validation_context != nullptr) {
grpc_error_handle error = CertificateValidationContextParse(
context, validation_context,
&common_tls_context->certificate_validation_context);
if (error != GRPC_ERROR_NONE) errors.push_back(error);
} else if (
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_has_validation_context_sds_secret_config(
common_tls_context_proto)) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"validation_context_sds_secret_config unsupported"));
}
}
auto* tls_certificate_provider_instance =
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_tls_certificate_provider_instance(
common_tls_context_proto);
if (tls_certificate_provider_instance != nullptr) {
grpc_error_handle error = CertificateProviderPluginInstanceParse(
context, tls_certificate_provider_instance,
&common_tls_context->tls_certificate_provider_instance);
if (error != GRPC_ERROR_NONE) errors.push_back(error);
} else {
// Fall back onto 'tls_certificate_certificate_provider_instance'. Note that
// this way of fetching identity certificates is deprecated and will be
// removed in the future.
// TODO(yashykt): Remove this once it's no longer needed.
auto* tls_certificate_certificate_provider_instance =
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_tls_certificate_certificate_provider_instance(
common_tls_context_proto);
if (tls_certificate_certificate_provider_instance != nullptr) {
grpc_error_handle error = CertificateProviderInstanceParse(
context, tls_certificate_certificate_provider_instance,
&common_tls_context->tls_certificate_provider_instance);
if (error != GRPC_ERROR_NONE) errors.push_back(error);
} else {
if (envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_has_tls_certificates(
common_tls_context_proto)) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"tls_certificates unsupported"));
}
if (envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_has_tls_certificate_sds_secret_configs(
common_tls_context_proto)) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"tls_certificate_sds_secret_configs unsupported"));
}
}
}
if (envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_has_tls_params(
common_tls_context_proto)) {
errors.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("tls_params unsupported"));
}
if (envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_has_custom_handshaker(
common_tls_context_proto)) {
errors.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("custom_handshaker unsupported"));
}
return GRPC_ERROR_CREATE_FROM_VECTOR("Error parsing CommonTlsContext",
&errors);
}
grpc_error_handle ExtractHttpFilterTypeName(const XdsEncodingContext& context,
const google_protobuf_Any* any,
absl::string_view* filter_type) {
*filter_type = UpbStringToAbsl(google_protobuf_Any_type_url(any));
if (*filter_type == "type.googleapis.com/xds.type.v3.TypedStruct" ||
*filter_type == "type.googleapis.com/udpa.type.v1.TypedStruct") {
upb_strview any_value = google_protobuf_Any_value(any);
const auto* typed_struct = xds_type_v3_TypedStruct_parse(
any_value.data, any_value.size, context.arena);
if (typed_struct == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"could not parse TypedStruct from filter config");
}
*filter_type =
UpbStringToAbsl(xds_type_v3_TypedStruct_type_url(typed_struct));
}
*filter_type = absl::StripPrefix(*filter_type, "type.googleapis.com/");
return GRPC_ERROR_NONE;
}
} // namespace grpc_core

@ -0,0 +1,110 @@
//
// Copyright 2018 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_CORE_EXT_XDS_XDS_COMMON_TYPES_H
#define GRPC_CORE_EXT_XDS_XDS_COMMON_TYPES_H
#include <grpc/support/port_platform.h>
#include <string>
#include <vector>
#include "absl/strings/str_format.h"
#include "envoy/extensions/transport_sockets/tls/v3/tls.upb.h"
#include "google/protobuf/any.upb.h"
#include "google/protobuf/duration.upb.h"
#include "src/core/ext/xds/upb_utils.h"
#include "src/core/lib/matchers/matchers.h"
namespace grpc_core {
struct Duration {
int64_t seconds = 0;
int32_t nanos = 0;
Duration() = default;
bool operator==(const Duration& other) const {
return seconds == other.seconds && nanos == other.nanos;
}
std::string ToString() const {
return absl::StrFormat("Duration seconds: %ld, nanos %d", seconds, nanos);
}
static Duration Parse(const google_protobuf_Duration* proto_duration) {
Duration duration;
duration.seconds = google_protobuf_Duration_seconds(proto_duration);
duration.nanos = google_protobuf_Duration_nanos(proto_duration);
return duration;
}
};
struct CommonTlsContext {
struct CertificateProviderPluginInstance {
std::string instance_name;
std::string certificate_name;
bool operator==(const CertificateProviderPluginInstance& other) const {
return instance_name == other.instance_name &&
certificate_name == other.certificate_name;
}
std::string ToString() const;
bool Empty() const;
};
struct CertificateValidationContext {
CertificateProviderPluginInstance ca_certificate_provider_instance;
std::vector<StringMatcher> match_subject_alt_names;
bool operator==(const CertificateValidationContext& other) const {
return ca_certificate_provider_instance ==
other.ca_certificate_provider_instance &&
match_subject_alt_names == other.match_subject_alt_names;
}
std::string ToString() const;
bool Empty() const;
};
CertificateValidationContext certificate_validation_context;
CertificateProviderPluginInstance tls_certificate_provider_instance;
bool operator==(const CommonTlsContext& other) const {
return certificate_validation_context ==
other.certificate_validation_context &&
tls_certificate_provider_instance ==
other.tls_certificate_provider_instance;
}
std::string ToString() const;
bool Empty() const;
static grpc_error_handle Parse(
const XdsEncodingContext& context,
const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
common_tls_context_proto,
CommonTlsContext* common_tls_context);
};
grpc_error_handle ExtractHttpFilterTypeName(const XdsEncodingContext& context,
const google_protobuf_Any* any,
absl::string_view* filter_type);
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_XDS_COMMON_TYPES_H

@ -0,0 +1,352 @@
//
// Copyright 2018 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 <grpc/support/port_platform.h>
#include "src/core/ext/xds/xds_endpoint.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "envoy/config/core/v3/address.upb.h"
#include "envoy/config/core/v3/base.upb.h"
#include "envoy/config/core/v3/health_check.upb.h"
#include "envoy/config/endpoint/v3/endpoint.upb.h"
#include "envoy/config/endpoint/v3/endpoint.upbdefs.h"
#include "envoy/config/endpoint/v3/endpoint_components.upb.h"
#include "envoy/type/v3/percent.upb.h"
#include "google/protobuf/wrappers.upb.h"
#include "upb/text_encode.h"
#include "upb/upb.h"
#include "upb/upb.hpp"
#include "src/core/ext/xds/upb_utils.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
namespace grpc_core {
//
// XdsEndpointResource
//
std::string XdsEndpointResource::Priority::Locality::ToString() const {
std::vector<std::string> endpoint_strings;
for (const ServerAddress& endpoint : endpoints) {
endpoint_strings.emplace_back(endpoint.ToString());
}
return absl::StrCat("{name=", name->AsHumanReadableString(),
", lb_weight=", lb_weight, ", endpoints=[",
absl::StrJoin(endpoint_strings, ", "), "]}");
}
bool XdsEndpointResource::Priority::operator==(const Priority& other) const {
if (localities.size() != other.localities.size()) return false;
auto it1 = localities.begin();
auto it2 = other.localities.begin();
while (it1 != localities.end()) {
if (*it1->first != *it2->first) return false;
if (it1->second != it2->second) return false;
++it1;
++it2;
}
return true;
}
std::string XdsEndpointResource::Priority::ToString() const {
std::vector<std::string> locality_strings;
for (const auto& p : localities) {
locality_strings.emplace_back(p.second.ToString());
}
return absl::StrCat("[", absl::StrJoin(locality_strings, ", "), "]");
}
bool XdsEndpointResource::DropConfig::ShouldDrop(
const std::string** category_name) const {
for (size_t i = 0; i < drop_category_list_.size(); ++i) {
const auto& drop_category = drop_category_list_[i];
// Generate a random number in [0, 1000000).
const uint32_t random = static_cast<uint32_t>(rand()) % 1000000;
if (random < drop_category.parts_per_million) {
*category_name = &drop_category.name;
return true;
}
}
return false;
}
std::string XdsEndpointResource::DropConfig::ToString() const {
std::vector<std::string> category_strings;
for (const DropCategory& category : drop_category_list_) {
category_strings.emplace_back(
absl::StrCat(category.name, "=", category.parts_per_million));
}
return absl::StrCat("{[", absl::StrJoin(category_strings, ", "),
"], drop_all=", drop_all_, "}");
}
std::string XdsEndpointResource::ToString() const {
std::vector<std::string> priority_strings;
for (size_t i = 0; i < priorities.size(); ++i) {
const Priority& priority = priorities[i];
priority_strings.emplace_back(
absl::StrCat("priority ", i, ": ", priority.ToString()));
}
return absl::StrCat("priorities=[", absl::StrJoin(priority_strings, ", "),
"], drop_config=", drop_config->ToString());
}
//
// XdsEndpointResourceType
//
namespace {
void MaybeLogClusterLoadAssignment(
const XdsEncodingContext& context,
const envoy_config_endpoint_v3_ClusterLoadAssignment* cla) {
if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
const upb_msgdef* msg_type =
envoy_config_endpoint_v3_ClusterLoadAssignment_getmsgdef(
context.symtab);
char buf[10240];
upb_text_encode(cla, msg_type, nullptr, 0, buf, sizeof(buf));
gpr_log(GPR_DEBUG, "[xds_client %p] ClusterLoadAssignment: %s",
context.client, buf);
}
}
grpc_error_handle ServerAddressParseAndAppend(
const envoy_config_endpoint_v3_LbEndpoint* lb_endpoint,
ServerAddressList* list) {
// If health_status is not HEALTHY or UNKNOWN, skip this endpoint.
const int32_t health_status =
envoy_config_endpoint_v3_LbEndpoint_health_status(lb_endpoint);
if (health_status != envoy_config_core_v3_UNKNOWN &&
health_status != envoy_config_core_v3_HEALTHY) {
return GRPC_ERROR_NONE;
}
// Find the ip:port.
const envoy_config_endpoint_v3_Endpoint* endpoint =
envoy_config_endpoint_v3_LbEndpoint_endpoint(lb_endpoint);
const envoy_config_core_v3_Address* address =
envoy_config_endpoint_v3_Endpoint_address(endpoint);
const envoy_config_core_v3_SocketAddress* socket_address =
envoy_config_core_v3_Address_socket_address(address);
std::string address_str = UpbStringToStdString(
envoy_config_core_v3_SocketAddress_address(socket_address));
uint32_t port = envoy_config_core_v3_SocketAddress_port_value(socket_address);
if (GPR_UNLIKELY(port >> 16) != 0) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid port.");
}
// Find load_balancing_weight for the endpoint.
const google_protobuf_UInt32Value* load_balancing_weight =
envoy_config_endpoint_v3_LbEndpoint_load_balancing_weight(lb_endpoint);
const int32_t weight =
load_balancing_weight != nullptr
? google_protobuf_UInt32Value_value(load_balancing_weight)
: 500;
if (weight == 0) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Invalid endpoint weight of 0.");
}
// Populate grpc_resolved_address.
grpc_resolved_address addr;
grpc_error_handle error =
grpc_string_to_sockaddr(&addr, address_str.c_str(), port);
if (error != GRPC_ERROR_NONE) return error;
// Append the address to the list.
std::map<const char*, std::unique_ptr<ServerAddress::AttributeInterface>>
attributes;
attributes[ServerAddressWeightAttribute::kServerAddressWeightAttributeKey] =
absl::make_unique<ServerAddressWeightAttribute>(weight);
list->emplace_back(addr, nullptr, std::move(attributes));
return GRPC_ERROR_NONE;
}
grpc_error_handle LocalityParse(
const envoy_config_endpoint_v3_LocalityLbEndpoints* locality_lb_endpoints,
XdsEndpointResource::Priority::Locality* output_locality,
size_t* priority) {
// Parse LB weight.
const google_protobuf_UInt32Value* lb_weight =
envoy_config_endpoint_v3_LocalityLbEndpoints_load_balancing_weight(
locality_lb_endpoints);
// If LB weight is not specified, it means this locality is assigned no load.
// TODO(juanlishen): When we support CDS to configure the inter-locality
// policy, we should change the LB weight handling.
output_locality->lb_weight =
lb_weight != nullptr ? google_protobuf_UInt32Value_value(lb_weight) : 0;
if (output_locality->lb_weight == 0) return GRPC_ERROR_NONE;
// Parse locality name.
const envoy_config_core_v3_Locality* locality =
envoy_config_endpoint_v3_LocalityLbEndpoints_locality(
locality_lb_endpoints);
if (locality == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty locality.");
}
std::string region =
UpbStringToStdString(envoy_config_core_v3_Locality_region(locality));
std::string zone =
UpbStringToStdString(envoy_config_core_v3_Locality_region(locality));
std::string sub_zone =
UpbStringToStdString(envoy_config_core_v3_Locality_sub_zone(locality));
output_locality->name = MakeRefCounted<XdsLocalityName>(
std::move(region), std::move(zone), std::move(sub_zone));
// Parse the addresses.
size_t size;
const envoy_config_endpoint_v3_LbEndpoint* const* lb_endpoints =
envoy_config_endpoint_v3_LocalityLbEndpoints_lb_endpoints(
locality_lb_endpoints, &size);
for (size_t i = 0; i < size; ++i) {
grpc_error_handle error = ServerAddressParseAndAppend(
lb_endpoints[i], &output_locality->endpoints);
if (error != GRPC_ERROR_NONE) return error;
}
// Parse the priority.
*priority = envoy_config_endpoint_v3_LocalityLbEndpoints_priority(
locality_lb_endpoints);
return GRPC_ERROR_NONE;
}
grpc_error_handle DropParseAndAppend(
const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload*
drop_overload,
XdsEndpointResource::DropConfig* drop_config) {
// Get the category.
std::string category = UpbStringToStdString(
envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload_category(
drop_overload));
if (category.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty drop category name");
}
// Get the drop rate (per million).
const envoy_type_v3_FractionalPercent* drop_percentage =
envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload_drop_percentage(
drop_overload);
uint32_t numerator =
envoy_type_v3_FractionalPercent_numerator(drop_percentage);
const auto denominator =
static_cast<envoy_type_v3_FractionalPercent_DenominatorType>(
envoy_type_v3_FractionalPercent_denominator(drop_percentage));
// Normalize to million.
switch (denominator) {
case envoy_type_v3_FractionalPercent_HUNDRED:
numerator *= 10000;
break;
case envoy_type_v3_FractionalPercent_TEN_THOUSAND:
numerator *= 100;
break;
case envoy_type_v3_FractionalPercent_MILLION:
break;
default:
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unknown denominator type");
}
// Cap numerator to 1000000.
numerator = std::min(numerator, 1000000u);
drop_config->AddCategory(std::move(category), numerator);
return GRPC_ERROR_NONE;
}
grpc_error_handle EdsResourceParse(
const XdsEncodingContext& /*context*/,
const envoy_config_endpoint_v3_ClusterLoadAssignment*
cluster_load_assignment,
bool /*is_v2*/, XdsEndpointResource* eds_update) {
std::vector<grpc_error_handle> errors;
// Get the endpoints.
size_t locality_size;
const envoy_config_endpoint_v3_LocalityLbEndpoints* const* endpoints =
envoy_config_endpoint_v3_ClusterLoadAssignment_endpoints(
cluster_load_assignment, &locality_size);
for (size_t j = 0; j < locality_size; ++j) {
size_t priority;
XdsEndpointResource::Priority::Locality locality;
grpc_error_handle error = LocalityParse(endpoints[j], &locality, &priority);
if (error != GRPC_ERROR_NONE) {
errors.push_back(error);
continue;
}
// Filter out locality with weight 0.
if (locality.lb_weight == 0) continue;
// Make sure prorities is big enough. Note that they might not
// arrive in priority order.
while (eds_update->priorities.size() < priority + 1) {
eds_update->priorities.emplace_back();
}
eds_update->priorities[priority].localities.emplace(locality.name.get(),
std::move(locality));
}
for (const auto& priority : eds_update->priorities) {
if (priority.localities.empty()) {
errors.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("sparse priority list"));
}
}
// Get the drop config.
eds_update->drop_config = MakeRefCounted<XdsEndpointResource::DropConfig>();
const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy* policy =
envoy_config_endpoint_v3_ClusterLoadAssignment_policy(
cluster_load_assignment);
if (policy != nullptr) {
size_t drop_size;
const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload* const*
drop_overload =
envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_drop_overloads(
policy, &drop_size);
for (size_t j = 0; j < drop_size; ++j) {
grpc_error_handle error =
DropParseAndAppend(drop_overload[j], eds_update->drop_config.get());
if (error != GRPC_ERROR_NONE) {
errors.push_back(
grpc_error_add_child(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"drop config validation error"),
error));
}
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing EDS resource", &errors);
}
} // namespace
absl::StatusOr<XdsResourceType::DecodeResult> XdsEndpointResourceType::Decode(
const XdsEncodingContext& context, absl::string_view serialized_resource,
bool is_v2) const {
// Parse serialized proto.
auto* resource = envoy_config_endpoint_v3_ClusterLoadAssignment_parse(
serialized_resource.data(), serialized_resource.size(), context.arena);
if (resource == nullptr) {
return absl::InvalidArgumentError("Can't parse Listener resource.");
}
MaybeLogClusterLoadAssignment(context, resource);
// Validate resource.
DecodeResult result;
result.name = UpbStringToStdString(
envoy_config_endpoint_v3_ClusterLoadAssignment_cluster_name(resource));
auto endpoint_data = absl::make_unique<EndpointData>();
grpc_error_handle error =
EdsResourceParse(context, resource, is_v2, &endpoint_data->resource);
if (error != GRPC_ERROR_NONE) {
result.resource = absl::InvalidArgumentError(grpc_error_std_string(error));
GRPC_ERROR_UNREF(error);
} else {
result.resource = std::move(endpoint_data);
}
return std::move(result);
}
} // namespace grpc_core

@ -0,0 +1,132 @@
//
// Copyright 2018 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_CORE_EXT_XDS_XDS_ENDPOINT_H
#define GRPC_CORE_EXT_XDS_XDS_ENDPOINT_H
#include <grpc/support/port_platform.h>
#include <map>
#include <set>
#include <string>
#include "absl/container/inlined_vector.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/ext/xds/xds_client_stats.h"
#include "src/core/ext/xds/xds_resource_type.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
namespace grpc_core {
struct XdsEndpointResource {
struct Priority {
struct Locality {
RefCountedPtr<XdsLocalityName> name;
uint32_t lb_weight;
ServerAddressList endpoints;
bool operator==(const Locality& other) const {
return *name == *other.name && lb_weight == other.lb_weight &&
endpoints == other.endpoints;
}
bool operator!=(const Locality& other) const { return !(*this == other); }
std::string ToString() const;
};
std::map<XdsLocalityName*, Locality, XdsLocalityName::Less> localities;
bool operator==(const Priority& other) const;
std::string ToString() const;
};
using PriorityList = absl::InlinedVector<Priority, 2>;
// There are two phases of accessing this class's content:
// 1. to initialize in the control plane combiner;
// 2. to use in the data plane combiner.
// So no additional synchronization is needed.
class DropConfig : public RefCounted<DropConfig> {
public:
struct DropCategory {
bool operator==(const DropCategory& other) const {
return name == other.name &&
parts_per_million == other.parts_per_million;
}
std::string name;
const uint32_t parts_per_million;
};
using DropCategoryList = absl::InlinedVector<DropCategory, 2>;
void AddCategory(std::string name, uint32_t parts_per_million) {
drop_category_list_.emplace_back(
DropCategory{std::move(name), parts_per_million});
if (parts_per_million == 1000000) drop_all_ = true;
}
// The only method invoked from outside the WorkSerializer (used in
// the data plane).
bool ShouldDrop(const std::string** category_name) const;
const DropCategoryList& drop_category_list() const {
return drop_category_list_;
}
bool drop_all() const { return drop_all_; }
bool operator==(const DropConfig& other) const {
return drop_category_list_ == other.drop_category_list_;
}
bool operator!=(const DropConfig& other) const { return !(*this == other); }
std::string ToString() const;
private:
DropCategoryList drop_category_list_;
bool drop_all_ = false;
};
PriorityList priorities;
RefCountedPtr<DropConfig> drop_config;
bool operator==(const XdsEndpointResource& other) const {
return priorities == other.priorities && *drop_config == *other.drop_config;
}
std::string ToString() const;
};
class XdsEndpointResourceType : public XdsResourceType {
public:
struct EndpointData : public ResourceData {
XdsEndpointResource resource;
};
absl::string_view type_url() const override {
return "envoy.config.endpoint.v3.ClusterLoadAssignment";
}
absl::string_view v2_type_url() const override {
return "envoy.api.v2.ClusterLoadAssignment";
}
absl::StatusOr<DecodeResult> Decode(const XdsEncodingContext& context,
absl::string_view serialized_resource,
bool is_v2) const override;
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_XDS_ENDPOINT_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,210 @@
//
// Copyright 2018 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_CORE_EXT_XDS_XDS_LISTENER_H
#define GRPC_CORE_EXT_XDS_XDS_LISTENER_H
#include <grpc/support/port_platform.h>
#include <array>
#include <map>
#include <string>
#include <vector>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "src/core/ext/xds/xds_common_types.h"
#include "src/core/ext/xds/xds_http_filters.h"
#include "src/core/ext/xds/xds_route_config.h"
namespace grpc_core {
// TODO(roth): When we can use absl::variant<>, consider using that
// here, to enforce the fact that only one of the two fields can be set.
struct XdsListenerResource {
struct DownstreamTlsContext {
CommonTlsContext common_tls_context;
bool require_client_certificate = false;
bool operator==(const DownstreamTlsContext& other) const {
return common_tls_context == other.common_tls_context &&
require_client_certificate == other.require_client_certificate;
}
std::string ToString() const;
bool Empty() const;
};
enum class ListenerType {
kTcpListener = 0,
kHttpApiListener,
} type;
struct HttpConnectionManager {
// The name to use in the RDS request.
std::string route_config_name;
// Storing the Http Connection Manager Common Http Protocol Option
// max_stream_duration
Duration http_max_stream_duration;
// The RouteConfiguration to use for this listener.
// Present only if it is inlined in the LDS response.
absl::optional<XdsRouteConfigResource> rds_update;
struct HttpFilter {
std::string name;
XdsHttpFilterImpl::FilterConfig config;
bool operator==(const HttpFilter& other) const {
return name == other.name && config == other.config;
}
std::string ToString() const;
};
std::vector<HttpFilter> http_filters;
bool operator==(const HttpConnectionManager& other) const {
return route_config_name == other.route_config_name &&
http_max_stream_duration == other.http_max_stream_duration &&
rds_update == other.rds_update &&
http_filters == other.http_filters;
}
std::string ToString() const;
};
// Populated for type=kHttpApiListener.
HttpConnectionManager http_connection_manager;
// Populated for type=kTcpListener.
// host:port listening_address set when type is kTcpListener
std::string address;
struct FilterChainData {
DownstreamTlsContext downstream_tls_context;
// This is in principle the filter list.
// We currently require exactly one filter, which is the HCM.
HttpConnectionManager http_connection_manager;
bool operator==(const FilterChainData& other) const {
return downstream_tls_context == other.downstream_tls_context &&
http_connection_manager == other.http_connection_manager;
}
std::string ToString() const;
};
// A multi-level map used to determine which filter chain to use for a given
// incoming connection. Determining the right filter chain for a given
// connection checks the following properties, in order:
// - destination port (never matched, so not present in map)
// - destination IP address
// - server name (never matched, so not present in map)
// - transport protocol (allows only "raw_buffer" or unset, prefers the
// former, so only one of those two types is present in map)
// - application protocol (never matched, so not present in map)
// - connection source type (any, local or external)
// - source IP address
// - source port
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/listener/v3/listener_components.proto#config-listener-v3-filterchainmatch
// for more details
struct FilterChainMap {
struct FilterChainDataSharedPtr {
std::shared_ptr<FilterChainData> data;
bool operator==(const FilterChainDataSharedPtr& other) const {
return *data == *other.data;
}
};
struct CidrRange {
grpc_resolved_address address;
uint32_t prefix_len;
bool operator==(const CidrRange& other) const {
return memcmp(&address, &other.address, sizeof(address)) == 0 &&
prefix_len == other.prefix_len;
}
std::string ToString() const;
};
using SourcePortsMap = std::map<uint16_t, FilterChainDataSharedPtr>;
struct SourceIp {
absl::optional<CidrRange> prefix_range;
SourcePortsMap ports_map;
bool operator==(const SourceIp& other) const {
return prefix_range == other.prefix_range &&
ports_map == other.ports_map;
}
};
using SourceIpVector = std::vector<SourceIp>;
enum class ConnectionSourceType { kAny = 0, kSameIpOrLoopback, kExternal };
using ConnectionSourceTypesArray = std::array<SourceIpVector, 3>;
struct DestinationIp {
absl::optional<CidrRange> prefix_range;
// We always fail match on server name, so those filter chains are not
// included here.
ConnectionSourceTypesArray source_types_array;
bool operator==(const DestinationIp& other) const {
return prefix_range == other.prefix_range &&
source_types_array == other.source_types_array;
}
};
// We always fail match on destination ports map
using DestinationIpVector = std::vector<DestinationIp>;
DestinationIpVector destination_ip_vector;
bool operator==(const FilterChainMap& other) const {
return destination_ip_vector == other.destination_ip_vector;
}
std::string ToString() const;
} filter_chain_map;
absl::optional<FilterChainData> default_filter_chain;
bool operator==(const XdsListenerResource& other) const {
return http_connection_manager == other.http_connection_manager &&
address == other.address &&
filter_chain_map == other.filter_chain_map &&
default_filter_chain == other.default_filter_chain;
}
std::string ToString() const;
};
class XdsListenerResourceType : public XdsResourceType {
public:
struct ListenerData : public ResourceData {
XdsListenerResource resource;
};
absl::string_view type_url() const override {
return "envoy.config.listener.v3.Listener";
}
absl::string_view v2_type_url() const override {
return "envoy.api.v2.Listener";
}
absl::StatusOr<DecodeResult> Decode(const XdsEncodingContext& context,
absl::string_view serialized_resource,
bool is_v2) const override;
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_XDS_LISTENER_H

@ -0,0 +1,77 @@
//
// Copyright 2021 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 <grpc/support/port_platform.h>
#include <memory>
#include <string>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "src/core/ext/xds/upb_utils.h"
#ifndef GRPC_CORE_EXT_XDS_XDS_RESOURCE_TYPE_H
#define GRPC_CORE_EXT_XDS_XDS_RESOURCE_TYPE_H
namespace grpc_core {
class XdsResourceType {
public:
// A base type for resource data.
// Subclasses will extend this, and their DecodeResults will be
// downcastable to their extended type.
struct ResourceData {
virtual ~ResourceData() = default;
};
// Result returned by Decode().
struct DecodeResult {
std::string name;
absl::StatusOr<std::unique_ptr<ResourceData>> resource;
};
virtual ~XdsResourceType() = default;
// Returns v3 resource type.
virtual absl::string_view type_url() const = 0;
// Returns v2 resource type.
virtual absl::string_view v2_type_url() const = 0;
// Decodes and validates a serialized resource proto.
// If the resource fails protobuf deserialization, returns non-OK status.
// If the deserialized resource fails validation, returns a DecodeResult
// whose resource field is set to a non-OK status.
// Otherwise, returns a DecodeResult with a valid resource.
virtual absl::StatusOr<DecodeResult> Decode(
const XdsEncodingContext& context, absl::string_view serialized_resource,
bool is_v2) const = 0;
// Convenient method for checking if a resource type matches this type.
bool IsType(absl::string_view resource_type, bool* is_v2) const {
if (resource_type == type_url()) return true;
if (resource_type == v2_type_url()) {
if (is_v2 != nullptr) *is_v2 = true;
return true;
}
return false;
}
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_XDS_RESOURCE_TYPE_H

@ -0,0 +1,982 @@
//
// Copyright 2018 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 <grpc/support/port_platform.h>
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "envoy/config/core/v3/base.upb.h"
#include "envoy/config/route/v3/route.upb.h"
#include "envoy/config/route/v3/route.upbdefs.h"
#include "envoy/config/route/v3/route_components.upb.h"
#include "envoy/config/route/v3/route_components.upbdefs.h"
#include "envoy/type/matcher/v3/regex.upb.h"
#include "envoy/type/matcher/v3/string.upb.h"
#include "envoy/type/v3/percent.upb.h"
#include "envoy/type/v3/range.upb.h"
#include "google/protobuf/any.upb.h"
#include "google/protobuf/wrappers.upb.h"
#include "upb/text_encode.h"
#include "upb/upb.h"
#include "upb/upb.hpp"
#include "src/core/ext/xds/upb_utils.h"
#include "src/core/ext/xds/xds_api.h"
#include "src/core/ext/xds/xds_common_types.h"
#include "src/core/ext/xds/xds_resource_type.h"
#include "src/core/ext/xds/xds_routing.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/error.h"
namespace grpc_core {
// TODO(yashykt): Remove once RBAC is no longer experimental
bool XdsRbacEnabled() {
char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_RBAC");
bool parsed_value;
bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
gpr_free(value);
return parse_succeeded && parsed_value;
}
//
// XdsRouteConfigResource::RetryPolicy
//
std::string XdsRouteConfigResource::RetryPolicy::RetryBackOff::ToString()
const {
std::vector<std::string> contents;
contents.push_back(
absl::StrCat("RetryBackOff Base: ", base_interval.ToString()));
contents.push_back(
absl::StrCat("RetryBackOff max: ", max_interval.ToString()));
return absl::StrJoin(contents, ",");
}
std::string XdsRouteConfigResource::RetryPolicy::ToString() const {
std::vector<std::string> contents;
contents.push_back(absl::StrFormat("num_retries=%d", num_retries));
contents.push_back(retry_back_off.ToString());
return absl::StrCat("{", absl::StrJoin(contents, ","), "}");
}
//
// XdsRouteConfigResource::Route::Matchers
//
std::string XdsRouteConfigResource::Route::Matchers::ToString() const {
std::vector<std::string> contents;
contents.push_back(
absl::StrFormat("PathMatcher{%s}", path_matcher.ToString()));
for (const HeaderMatcher& header_matcher : header_matchers) {
contents.push_back(header_matcher.ToString());
}
if (fraction_per_million.has_value()) {
contents.push_back(absl::StrFormat("Fraction Per Million %d",
fraction_per_million.value()));
}
return absl::StrJoin(contents, "\n");
}
//
// XdsRouteConfigResource::Route::RouteAction::HashPolicy
//
XdsRouteConfigResource::Route::RouteAction::HashPolicy::HashPolicy(
const HashPolicy& other)
: type(other.type),
header_name(other.header_name),
regex_substitution(other.regex_substitution) {
if (other.regex != nullptr) {
regex =
absl::make_unique<RE2>(other.regex->pattern(), other.regex->options());
}
}
XdsRouteConfigResource::Route::RouteAction::HashPolicy&
XdsRouteConfigResource::Route::RouteAction::HashPolicy::operator=(
const HashPolicy& other) {
type = other.type;
header_name = other.header_name;
if (other.regex != nullptr) {
regex =
absl::make_unique<RE2>(other.regex->pattern(), other.regex->options());
}
regex_substitution = other.regex_substitution;
return *this;
}
XdsRouteConfigResource::Route::RouteAction::HashPolicy::HashPolicy(
HashPolicy&& other) noexcept
: type(other.type),
header_name(std::move(other.header_name)),
regex(std::move(other.regex)),
regex_substitution(std::move(other.regex_substitution)) {}
XdsRouteConfigResource::Route::RouteAction::HashPolicy&
XdsRouteConfigResource::Route::RouteAction::HashPolicy::operator=(
HashPolicy&& other) noexcept {
type = other.type;
header_name = std::move(other.header_name);
regex = std::move(other.regex);
regex_substitution = std::move(other.regex_substitution);
return *this;
}
bool XdsRouteConfigResource::Route::RouteAction::HashPolicy::HashPolicy::
operator==(const HashPolicy& other) const {
if (type != other.type) return false;
if (type == Type::HEADER) {
if (regex == nullptr) {
if (other.regex != nullptr) return false;
} else {
if (other.regex == nullptr) return false;
return header_name == other.header_name &&
regex->pattern() == other.regex->pattern() &&
regex_substitution == other.regex_substitution;
}
}
return true;
}
std::string XdsRouteConfigResource::Route::RouteAction::HashPolicy::ToString()
const {
std::vector<std::string> contents;
switch (type) {
case Type::HEADER:
contents.push_back("type=HEADER");
break;
case Type::CHANNEL_ID:
contents.push_back("type=CHANNEL_ID");
break;
}
contents.push_back(
absl::StrFormat("terminal=%s", terminal ? "true" : "false"));
if (type == Type::HEADER) {
contents.push_back(absl::StrFormat(
"Header %s:/%s/%s", header_name,
(regex == nullptr) ? "" : regex->pattern(), regex_substitution));
}
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
//
// XdsRouteConfigResource::Route::RouteAction::ClusterWeight
//
std::string
XdsRouteConfigResource::Route::RouteAction::ClusterWeight::ToString() const {
std::vector<std::string> contents;
contents.push_back(absl::StrCat("cluster=", name));
contents.push_back(absl::StrCat("weight=", weight));
if (!typed_per_filter_config.empty()) {
std::vector<std::string> parts;
for (const auto& p : typed_per_filter_config) {
const std::string& key = p.first;
const auto& config = p.second;
parts.push_back(absl::StrCat(key, "=", config.ToString()));
}
contents.push_back(absl::StrCat("typed_per_filter_config={",
absl::StrJoin(parts, ", "), "}"));
}
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
//
// XdsRouteConfigResource::Route::RouteAction
//
std::string XdsRouteConfigResource::Route::RouteAction::ToString() const {
std::vector<std::string> contents;
for (const HashPolicy& hash_policy : hash_policies) {
contents.push_back(absl::StrCat("hash_policy=", hash_policy.ToString()));
}
if (retry_policy.has_value()) {
contents.push_back(absl::StrCat("retry_policy=", retry_policy->ToString()));
}
if (!cluster_name.empty()) {
contents.push_back(absl::StrFormat("Cluster name: %s", cluster_name));
}
for (const ClusterWeight& cluster_weight : weighted_clusters) {
contents.push_back(cluster_weight.ToString());
}
if (max_stream_duration.has_value()) {
contents.push_back(max_stream_duration->ToString());
}
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
//
// XdsRouteConfigResource::Route
//
std::string XdsRouteConfigResource::Route::ToString() const {
std::vector<std::string> contents;
contents.push_back(matchers.ToString());
auto* route_action =
absl::get_if<XdsRouteConfigResource::Route::RouteAction>(&action);
if (route_action != nullptr) {
contents.push_back(absl::StrCat("route=", route_action->ToString()));
} else if (absl::holds_alternative<
XdsRouteConfigResource::Route::NonForwardingAction>(action)) {
contents.push_back("non_forwarding_action={}");
} else {
contents.push_back("unknown_action={}");
}
if (!typed_per_filter_config.empty()) {
contents.push_back("typed_per_filter_config={");
for (const auto& p : typed_per_filter_config) {
const std::string& name = p.first;
const auto& config = p.second;
contents.push_back(absl::StrCat(" ", name, "=", config.ToString()));
}
contents.push_back("}");
}
return absl::StrJoin(contents, "\n");
}
//
// XdsRouteConfigResource
//
std::string XdsRouteConfigResource::ToString() const {
std::vector<std::string> vhosts;
for (const VirtualHost& vhost : virtual_hosts) {
vhosts.push_back(
absl::StrCat("vhost={\n"
" domains=[",
absl::StrJoin(vhost.domains, ", "),
"]\n"
" routes=[\n"));
for (const XdsRouteConfigResource::Route& route : vhost.routes) {
vhosts.push_back(" {\n");
vhosts.push_back(route.ToString());
vhosts.push_back("\n }\n");
}
vhosts.push_back(" ]\n");
vhosts.push_back(" typed_per_filter_config={\n");
for (const auto& p : vhost.typed_per_filter_config) {
const std::string& name = p.first;
const auto& config = p.second;
vhosts.push_back(
absl::StrCat(" ", name, "=", config.ToString(), "\n"));
}
vhosts.push_back(" }\n");
vhosts.push_back("]\n");
}
return absl::StrJoin(vhosts, "");
}
namespace {
grpc_error_handle RoutePathMatchParse(
const envoy_config_route_v3_RouteMatch* match,
XdsRouteConfigResource::Route* route, bool* ignore_route) {
auto* case_sensitive_ptr =
envoy_config_route_v3_RouteMatch_case_sensitive(match);
bool case_sensitive = true;
if (case_sensitive_ptr != nullptr) {
case_sensitive = google_protobuf_BoolValue_value(case_sensitive_ptr);
}
StringMatcher::Type type;
std::string match_string;
if (envoy_config_route_v3_RouteMatch_has_prefix(match)) {
absl::string_view prefix =
UpbStringToAbsl(envoy_config_route_v3_RouteMatch_prefix(match));
// Empty prefix "" is accepted.
if (!prefix.empty()) {
// Prefix "/" is accepted.
if (prefix[0] != '/') {
// Prefix which does not start with a / will never match anything, so
// ignore this route.
*ignore_route = true;
return GRPC_ERROR_NONE;
}
std::vector<absl::string_view> prefix_elements =
absl::StrSplit(prefix.substr(1), absl::MaxSplits('/', 2));
if (prefix_elements.size() > 2) {
// Prefix cannot have more than 2 slashes.
*ignore_route = true;
return GRPC_ERROR_NONE;
} else if (prefix_elements.size() == 2 && prefix_elements[0].empty()) {
// Prefix contains empty string between the 2 slashes
*ignore_route = true;
return GRPC_ERROR_NONE;
}
}
type = StringMatcher::Type::kPrefix;
match_string = std::string(prefix);
} else if (envoy_config_route_v3_RouteMatch_has_path(match)) {
absl::string_view path =
UpbStringToAbsl(envoy_config_route_v3_RouteMatch_path(match));
if (path.empty()) {
// Path that is empty will never match anything, so ignore this route.
*ignore_route = true;
return GRPC_ERROR_NONE;
}
if (path[0] != '/') {
// Path which does not start with a / will never match anything, so
// ignore this route.
*ignore_route = true;
return GRPC_ERROR_NONE;
}
std::vector<absl::string_view> path_elements =
absl::StrSplit(path.substr(1), absl::MaxSplits('/', 2));
if (path_elements.size() != 2) {
// Path not in the required format of /service/method will never match
// anything, so ignore this route.
*ignore_route = true;
return GRPC_ERROR_NONE;
} else if (path_elements[0].empty()) {
// Path contains empty service name will never match anything, so ignore
// this route.
*ignore_route = true;
return GRPC_ERROR_NONE;
} else if (path_elements[1].empty()) {
// Path contains empty method name will never match anything, so ignore
// this route.
*ignore_route = true;
return GRPC_ERROR_NONE;
}
type = StringMatcher::Type::kExact;
match_string = std::string(path);
} else if (envoy_config_route_v3_RouteMatch_has_safe_regex(match)) {
const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
envoy_config_route_v3_RouteMatch_safe_regex(match);
GPR_ASSERT(regex_matcher != nullptr);
type = StringMatcher::Type::kSafeRegex;
match_string = UpbStringToStdString(
envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
} else {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Invalid route path specifier specified.");
}
absl::StatusOr<StringMatcher> string_matcher =
StringMatcher::Create(type, match_string, case_sensitive);
if (!string_matcher.ok()) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("path matcher: ", string_matcher.status().message()));
}
route->matchers.path_matcher = std::move(string_matcher.value());
return GRPC_ERROR_NONE;
}
grpc_error_handle RouteHeaderMatchersParse(
const envoy_config_route_v3_RouteMatch* match,
XdsRouteConfigResource::Route* route) {
size_t size;
const envoy_config_route_v3_HeaderMatcher* const* headers =
envoy_config_route_v3_RouteMatch_headers(match, &size);
for (size_t i = 0; i < size; ++i) {
const envoy_config_route_v3_HeaderMatcher* header = headers[i];
const std::string name =
UpbStringToStdString(envoy_config_route_v3_HeaderMatcher_name(header));
HeaderMatcher::Type type;
std::string match_string;
int64_t range_start = 0;
int64_t range_end = 0;
bool present_match = false;
if (envoy_config_route_v3_HeaderMatcher_has_exact_match(header)) {
type = HeaderMatcher::Type::kExact;
match_string = UpbStringToStdString(
envoy_config_route_v3_HeaderMatcher_exact_match(header));
} else if (envoy_config_route_v3_HeaderMatcher_has_safe_regex_match(
header)) {
const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
envoy_config_route_v3_HeaderMatcher_safe_regex_match(header);
GPR_ASSERT(regex_matcher != nullptr);
type = HeaderMatcher::Type::kSafeRegex;
match_string = UpbStringToStdString(
envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
} else if (envoy_config_route_v3_HeaderMatcher_has_range_match(header)) {
type = HeaderMatcher::Type::kRange;
const envoy_type_v3_Int64Range* range_matcher =
envoy_config_route_v3_HeaderMatcher_range_match(header);
range_start = envoy_type_v3_Int64Range_start(range_matcher);
range_end = envoy_type_v3_Int64Range_end(range_matcher);
} else if (envoy_config_route_v3_HeaderMatcher_has_present_match(header)) {
type = HeaderMatcher::Type::kPresent;
present_match = envoy_config_route_v3_HeaderMatcher_present_match(header);
} else if (envoy_config_route_v3_HeaderMatcher_has_prefix_match(header)) {
type = HeaderMatcher::Type::kPrefix;
match_string = UpbStringToStdString(
envoy_config_route_v3_HeaderMatcher_prefix_match(header));
} else if (envoy_config_route_v3_HeaderMatcher_has_suffix_match(header)) {
type = HeaderMatcher::Type::kSuffix;
match_string = UpbStringToStdString(
envoy_config_route_v3_HeaderMatcher_suffix_match(header));
} else if (envoy_config_route_v3_HeaderMatcher_has_contains_match(header)) {
type = HeaderMatcher::Type::kContains;
match_string = UpbStringToStdString(
envoy_config_route_v3_HeaderMatcher_contains_match(header));
} else {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Invalid route header matcher specified.");
}
bool invert_match =
envoy_config_route_v3_HeaderMatcher_invert_match(header);
absl::StatusOr<HeaderMatcher> header_matcher =
HeaderMatcher::Create(name, type, match_string, range_start, range_end,
present_match, invert_match);
if (!header_matcher.ok()) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("header matcher: ", header_matcher.status().message()));
}
route->matchers.header_matchers.emplace_back(
std::move(header_matcher.value()));
}
return GRPC_ERROR_NONE;
}
grpc_error_handle RouteRuntimeFractionParse(
const envoy_config_route_v3_RouteMatch* match,
XdsRouteConfigResource::Route* route) {
const envoy_config_core_v3_RuntimeFractionalPercent* runtime_fraction =
envoy_config_route_v3_RouteMatch_runtime_fraction(match);
if (runtime_fraction != nullptr) {
const envoy_type_v3_FractionalPercent* fraction =
envoy_config_core_v3_RuntimeFractionalPercent_default_value(
runtime_fraction);
if (fraction != nullptr) {
uint32_t numerator = envoy_type_v3_FractionalPercent_numerator(fraction);
const auto denominator =
static_cast<envoy_type_v3_FractionalPercent_DenominatorType>(
envoy_type_v3_FractionalPercent_denominator(fraction));
// Normalize to million.
switch (denominator) {
case envoy_type_v3_FractionalPercent_HUNDRED:
numerator *= 10000;
break;
case envoy_type_v3_FractionalPercent_TEN_THOUSAND:
numerator *= 100;
break;
case envoy_type_v3_FractionalPercent_MILLION:
break;
default:
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Unknown denominator type");
}
route->matchers.fraction_per_million = numerator;
}
}
return GRPC_ERROR_NONE;
}
template <typename ParentType, typename EntryType>
grpc_error_handle ParseTypedPerFilterConfig(
const XdsEncodingContext& context, const ParentType* parent,
const EntryType* (*entry_func)(const ParentType*, size_t*),
upb_strview (*key_func)(const EntryType*),
const google_protobuf_Any* (*value_func)(const EntryType*),
XdsRouteConfigResource::TypedPerFilterConfig* typed_per_filter_config) {
size_t filter_it = UPB_MAP_BEGIN;
while (true) {
const auto* filter_entry = entry_func(parent, &filter_it);
if (filter_entry == nullptr) break;
absl::string_view key = UpbStringToAbsl(key_func(filter_entry));
if (key.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("empty filter name in map");
}
const google_protobuf_Any* any = value_func(filter_entry);
GPR_ASSERT(any != nullptr);
absl::string_view filter_type =
UpbStringToAbsl(google_protobuf_Any_type_url(any));
if (filter_type.empty()) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("no filter config specified for filter name ", key));
}
bool is_optional = false;
if (filter_type ==
"type.googleapis.com/envoy.config.route.v3.FilterConfig") {
upb_strview any_value = google_protobuf_Any_value(any);
const auto* filter_config = envoy_config_route_v3_FilterConfig_parse(
any_value.data, any_value.size, context.arena);
if (filter_config == nullptr) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("could not parse FilterConfig wrapper for ", key));
}
is_optional =
envoy_config_route_v3_FilterConfig_is_optional(filter_config);
any = envoy_config_route_v3_FilterConfig_config(filter_config);
if (any == nullptr) {
if (is_optional) continue;
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("no filter config specified for filter name ", key));
}
}
grpc_error_handle error =
ExtractHttpFilterTypeName(context, any, &filter_type);
if (error != GRPC_ERROR_NONE) return error;
const XdsHttpFilterImpl* filter_impl =
XdsHttpFilterRegistry::GetFilterForType(filter_type);
if (filter_impl == nullptr) {
if (is_optional) continue;
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("no filter registered for config type ", filter_type));
}
absl::StatusOr<XdsHttpFilterImpl::FilterConfig> filter_config =
filter_impl->GenerateFilterConfigOverride(
google_protobuf_Any_value(any), context.arena);
if (!filter_config.ok()) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"filter config for type ", filter_type,
" failed to parse: ", filter_config.status().ToString()));
}
(*typed_per_filter_config)[std::string(key)] = std::move(*filter_config);
}
return GRPC_ERROR_NONE;
}
grpc_error_handle RetryPolicyParse(
const XdsEncodingContext& context,
const envoy_config_route_v3_RetryPolicy* retry_policy,
absl::optional<XdsRouteConfigResource::RetryPolicy>* retry) {
std::vector<grpc_error_handle> errors;
XdsRouteConfigResource::RetryPolicy retry_to_return;
auto retry_on = UpbStringToStdString(
envoy_config_route_v3_RetryPolicy_retry_on(retry_policy));
std::vector<absl::string_view> codes = absl::StrSplit(retry_on, ',');
for (const auto& code : codes) {
if (code == "cancelled") {
retry_to_return.retry_on.Add(GRPC_STATUS_CANCELLED);
} else if (code == "deadline-exceeded") {
retry_to_return.retry_on.Add(GRPC_STATUS_DEADLINE_EXCEEDED);
} else if (code == "internal") {
retry_to_return.retry_on.Add(GRPC_STATUS_INTERNAL);
} else if (code == "resource-exhausted") {
retry_to_return.retry_on.Add(GRPC_STATUS_RESOURCE_EXHAUSTED);
} else if (code == "unavailable") {
retry_to_return.retry_on.Add(GRPC_STATUS_UNAVAILABLE);
} else {
if (GRPC_TRACE_FLAG_ENABLED(*context.tracer)) {
gpr_log(GPR_INFO, "Unsupported retry_on policy %s.",
std::string(code).c_str());
}
}
}
const google_protobuf_UInt32Value* num_retries =
envoy_config_route_v3_RetryPolicy_num_retries(retry_policy);
if (num_retries != nullptr) {
uint32_t num_retries_value = google_protobuf_UInt32Value_value(num_retries);
if (num_retries_value == 0) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"RouteAction RetryPolicy num_retries set to invalid value 0."));
} else {
retry_to_return.num_retries = num_retries_value;
}
} else {
retry_to_return.num_retries = 1;
}
const envoy_config_route_v3_RetryPolicy_RetryBackOff* backoff =
envoy_config_route_v3_RetryPolicy_retry_back_off(retry_policy);
if (backoff != nullptr) {
const google_protobuf_Duration* base_interval =
envoy_config_route_v3_RetryPolicy_RetryBackOff_base_interval(backoff);
if (base_interval == nullptr) {
errors.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"RouteAction RetryPolicy RetryBackoff missing base interval."));
} else {
retry_to_return.retry_back_off.base_interval =
Duration::Parse(base_interval);
}
const google_protobuf_Duration* max_interval =
envoy_config_route_v3_RetryPolicy_RetryBackOff_max_interval(backoff);
Duration max;
if (max_interval != nullptr) {
max = Duration::Parse(max_interval);
} else {
// if max interval is not set, it is 10x the base, if the value in nanos
// can yield another second, adjust the value in seconds accordingly.
max.seconds = retry_to_return.retry_back_off.base_interval.seconds * 10;
max.nanos = retry_to_return.retry_back_off.base_interval.nanos * 10;
if (max.nanos > 1000000000) {
max.seconds += max.nanos / 1000000000;
max.nanos = max.nanos % 1000000000;
}
}
retry_to_return.retry_back_off.max_interval = max;
} else {
retry_to_return.retry_back_off.base_interval.seconds = 0;
retry_to_return.retry_back_off.base_interval.nanos = 25000000;
retry_to_return.retry_back_off.max_interval.seconds = 0;
retry_to_return.retry_back_off.max_interval.nanos = 250000000;
}
if (errors.empty()) {
*retry = retry_to_return;
return GRPC_ERROR_NONE;
} else {
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing retry policy",
&errors);
}
}
grpc_error_handle RouteActionParse(
const XdsEncodingContext& context,
const envoy_config_route_v3_Route* route_msg,
XdsRouteConfigResource::Route::RouteAction* route, bool* ignore_route) {
const envoy_config_route_v3_RouteAction* route_action =
envoy_config_route_v3_Route_route(route_msg);
// Get the cluster or weighted_clusters in the RouteAction.
if (envoy_config_route_v3_RouteAction_has_cluster(route_action)) {
route->cluster_name = UpbStringToStdString(
envoy_config_route_v3_RouteAction_cluster(route_action));
if (route->cluster_name.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"RouteAction cluster contains empty cluster name.");
}
} else if (envoy_config_route_v3_RouteAction_has_weighted_clusters(
route_action)) {
const envoy_config_route_v3_WeightedCluster* weighted_cluster =
envoy_config_route_v3_RouteAction_weighted_clusters(route_action);
uint32_t total_weight = 100;
const google_protobuf_UInt32Value* weight =
envoy_config_route_v3_WeightedCluster_total_weight(weighted_cluster);
if (weight != nullptr) {
total_weight = google_protobuf_UInt32Value_value(weight);
}
size_t clusters_size;
const envoy_config_route_v3_WeightedCluster_ClusterWeight* const* clusters =
envoy_config_route_v3_WeightedCluster_clusters(weighted_cluster,
&clusters_size);
uint32_t sum_of_weights = 0;
for (size_t j = 0; j < clusters_size; ++j) {
const envoy_config_route_v3_WeightedCluster_ClusterWeight*
cluster_weight = clusters[j];
XdsRouteConfigResource::Route::RouteAction::ClusterWeight cluster;
cluster.name = UpbStringToStdString(
envoy_config_route_v3_WeightedCluster_ClusterWeight_name(
cluster_weight));
if (cluster.name.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"RouteAction weighted_cluster cluster contains empty cluster "
"name.");
}
const google_protobuf_UInt32Value* weight =
envoy_config_route_v3_WeightedCluster_ClusterWeight_weight(
cluster_weight);
if (weight == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"RouteAction weighted_cluster cluster missing weight");
}
cluster.weight = google_protobuf_UInt32Value_value(weight);
if (cluster.weight == 0) continue;
sum_of_weights += cluster.weight;
if (context.use_v3) {
grpc_error_handle error = ParseTypedPerFilterConfig<
envoy_config_route_v3_WeightedCluster_ClusterWeight,
envoy_config_route_v3_WeightedCluster_ClusterWeight_TypedPerFilterConfigEntry>(
context, cluster_weight,
envoy_config_route_v3_WeightedCluster_ClusterWeight_typed_per_filter_config_next,
envoy_config_route_v3_WeightedCluster_ClusterWeight_TypedPerFilterConfigEntry_key,
envoy_config_route_v3_WeightedCluster_ClusterWeight_TypedPerFilterConfigEntry_value,
&cluster.typed_per_filter_config);
if (error != GRPC_ERROR_NONE) return error;
}
route->weighted_clusters.emplace_back(std::move(cluster));
}
if (total_weight != sum_of_weights) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"RouteAction weighted_cluster has incorrect total weight");
}
if (route->weighted_clusters.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"RouteAction weighted_cluster has no valid clusters specified.");
}
} else {
// No cluster or weighted_clusters found in RouteAction, ignore this route.
*ignore_route = true;
}
if (!*ignore_route) {
const envoy_config_route_v3_RouteAction_MaxStreamDuration*
max_stream_duration =
envoy_config_route_v3_RouteAction_max_stream_duration(route_action);
if (max_stream_duration != nullptr) {
const google_protobuf_Duration* duration =
envoy_config_route_v3_RouteAction_MaxStreamDuration_grpc_timeout_header_max(
max_stream_duration);
if (duration == nullptr) {
duration =
envoy_config_route_v3_RouteAction_MaxStreamDuration_max_stream_duration(
max_stream_duration);
}
if (duration != nullptr) {
route->max_stream_duration = Duration::Parse(duration);
}
}
}
// Get HashPolicy from RouteAction
size_t size = 0;
const envoy_config_route_v3_RouteAction_HashPolicy* const* hash_policies =
envoy_config_route_v3_RouteAction_hash_policy(route_action, &size);
for (size_t i = 0; i < size; ++i) {
const envoy_config_route_v3_RouteAction_HashPolicy* hash_policy =
hash_policies[i];
XdsRouteConfigResource::Route::RouteAction::HashPolicy policy;
policy.terminal =
envoy_config_route_v3_RouteAction_HashPolicy_terminal(hash_policy);
const envoy_config_route_v3_RouteAction_HashPolicy_Header* header;
const envoy_config_route_v3_RouteAction_HashPolicy_FilterState*
filter_state;
if ((header = envoy_config_route_v3_RouteAction_HashPolicy_header(
hash_policy)) != nullptr) {
policy.type =
XdsRouteConfigResource::Route::RouteAction::HashPolicy::Type::HEADER;
policy.header_name = UpbStringToStdString(
envoy_config_route_v3_RouteAction_HashPolicy_Header_header_name(
header));
const struct envoy_type_matcher_v3_RegexMatchAndSubstitute*
regex_rewrite =
envoy_config_route_v3_RouteAction_HashPolicy_Header_regex_rewrite(
header);
if (regex_rewrite != nullptr) {
const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
envoy_type_matcher_v3_RegexMatchAndSubstitute_pattern(
regex_rewrite);
if (regex_matcher == nullptr) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but RegexMatcher pattern is "
"missing");
continue;
}
RE2::Options options;
policy.regex = absl::make_unique<RE2>(
UpbStringToStdString(
envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher)),
options);
if (!policy.regex->ok()) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but RegexMatcher pattern does not "
"compile");
continue;
}
policy.regex_substitution = UpbStringToStdString(
envoy_type_matcher_v3_RegexMatchAndSubstitute_substitution(
regex_rewrite));
}
} else if ((filter_state =
envoy_config_route_v3_RouteAction_HashPolicy_filter_state(
hash_policy)) != nullptr) {
std::string key = UpbStringToStdString(
envoy_config_route_v3_RouteAction_HashPolicy_FilterState_key(
filter_state));
if (key == "io.grpc.channel_id") {
policy.type = XdsRouteConfigResource::Route::RouteAction::HashPolicy::
Type::CHANNEL_ID;
} else {
gpr_log(GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier "
"FilterState but "
"key is not io.grpc.channel_id.");
continue;
}
} else {
gpr_log(GPR_DEBUG,
"RouteAction HashPolicy contains unsupported policy specifier.");
continue;
}
route->hash_policies.emplace_back(std::move(policy));
}
// Get retry policy
const envoy_config_route_v3_RetryPolicy* retry_policy =
envoy_config_route_v3_RouteAction_retry_policy(route_action);
if (retry_policy != nullptr) {
absl::optional<XdsRouteConfigResource::RetryPolicy> retry;
grpc_error_handle error = RetryPolicyParse(context, retry_policy, &retry);
if (error != GRPC_ERROR_NONE) return error;
route->retry_policy = retry;
}
return GRPC_ERROR_NONE;
}
} // namespace
grpc_error_handle XdsRouteConfigResource::Parse(
const XdsEncodingContext& context,
const envoy_config_route_v3_RouteConfiguration* route_config,
XdsRouteConfigResource* rds_update) {
// Get the virtual hosts.
size_t num_virtual_hosts;
const envoy_config_route_v3_VirtualHost* const* virtual_hosts =
envoy_config_route_v3_RouteConfiguration_virtual_hosts(
route_config, &num_virtual_hosts);
for (size_t i = 0; i < num_virtual_hosts; ++i) {
rds_update->virtual_hosts.emplace_back();
XdsRouteConfigResource::VirtualHost& vhost =
rds_update->virtual_hosts.back();
// Parse domains.
size_t domain_size;
upb_strview const* domains = envoy_config_route_v3_VirtualHost_domains(
virtual_hosts[i], &domain_size);
for (size_t j = 0; j < domain_size; ++j) {
std::string domain_pattern = UpbStringToStdString(domains[j]);
if (!XdsRouting::IsValidDomainPattern(domain_pattern)) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("Invalid domain pattern \"", domain_pattern, "\"."));
}
vhost.domains.emplace_back(std::move(domain_pattern));
}
if (vhost.domains.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("VirtualHost has no domains");
}
// Parse typed_per_filter_config.
if (context.use_v3) {
grpc_error_handle error = ParseTypedPerFilterConfig<
envoy_config_route_v3_VirtualHost,
envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry>(
context, virtual_hosts[i],
envoy_config_route_v3_VirtualHost_typed_per_filter_config_next,
envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry_key,
envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry_value,
&vhost.typed_per_filter_config);
if (error != GRPC_ERROR_NONE) return error;
}
// Parse retry policy.
absl::optional<XdsRouteConfigResource::RetryPolicy>
virtual_host_retry_policy;
const envoy_config_route_v3_RetryPolicy* retry_policy =
envoy_config_route_v3_VirtualHost_retry_policy(virtual_hosts[i]);
if (retry_policy != nullptr) {
grpc_error_handle error =
RetryPolicyParse(context, retry_policy, &virtual_host_retry_policy);
if (error != GRPC_ERROR_NONE) return error;
}
// Parse routes.
size_t num_routes;
const envoy_config_route_v3_Route* const* routes =
envoy_config_route_v3_VirtualHost_routes(virtual_hosts[i], &num_routes);
if (num_routes < 1) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"No route found in the virtual host.");
}
// Loop over the whole list of routes
for (size_t j = 0; j < num_routes; ++j) {
const envoy_config_route_v3_RouteMatch* match =
envoy_config_route_v3_Route_match(routes[j]);
if (match == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Match can't be null.");
}
size_t query_parameters_size;
static_cast<void>(envoy_config_route_v3_RouteMatch_query_parameters(
match, &query_parameters_size));
if (query_parameters_size > 0) {
continue;
}
XdsRouteConfigResource::Route route;
bool ignore_route = false;
grpc_error_handle error =
RoutePathMatchParse(match, &route, &ignore_route);
if (error != GRPC_ERROR_NONE) return error;
if (ignore_route) continue;
error = RouteHeaderMatchersParse(match, &route);
if (error != GRPC_ERROR_NONE) return error;
error = RouteRuntimeFractionParse(match, &route);
if (error != GRPC_ERROR_NONE) return error;
if (envoy_config_route_v3_Route_has_route(routes[j])) {
route.action.emplace<XdsRouteConfigResource::Route::RouteAction>();
auto& route_action =
absl::get<XdsRouteConfigResource::Route::RouteAction>(route.action);
error =
RouteActionParse(context, routes[j], &route_action, &ignore_route);
if (error != GRPC_ERROR_NONE) return error;
if (ignore_route) continue;
if (route_action.retry_policy == absl::nullopt &&
retry_policy != nullptr) {
route_action.retry_policy = virtual_host_retry_policy;
}
} else if (envoy_config_route_v3_Route_has_non_forwarding_action(
routes[j])) {
route.action
.emplace<XdsRouteConfigResource::Route::NonForwardingAction>();
}
if (context.use_v3) {
grpc_error_handle error = ParseTypedPerFilterConfig<
envoy_config_route_v3_Route,
envoy_config_route_v3_Route_TypedPerFilterConfigEntry>(
context, routes[j],
envoy_config_route_v3_Route_typed_per_filter_config_next,
envoy_config_route_v3_Route_TypedPerFilterConfigEntry_key,
envoy_config_route_v3_Route_TypedPerFilterConfigEntry_value,
&route.typed_per_filter_config);
if (error != GRPC_ERROR_NONE) return error;
}
vhost.routes.emplace_back(std::move(route));
}
if (vhost.routes.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No valid routes specified.");
}
}
return GRPC_ERROR_NONE;
}
//
// XdsRouteConfigResourceType
//
namespace {
void MaybeLogRouteConfiguration(
const XdsEncodingContext& context,
const envoy_config_route_v3_RouteConfiguration* route_config) {
if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
const upb_msgdef* msg_type =
envoy_config_route_v3_RouteConfiguration_getmsgdef(context.symtab);
char buf[10240];
upb_text_encode(route_config, msg_type, nullptr, 0, buf, sizeof(buf));
gpr_log(GPR_DEBUG, "[xds_client %p] RouteConfiguration: %s", context.client,
buf);
}
}
} // namespace
absl::StatusOr<XdsResourceType::DecodeResult>
XdsRouteConfigResourceType::Decode(const XdsEncodingContext& context,
absl::string_view serialized_resource,
bool /*is_v2*/) const {
// Parse serialized proto.
auto* resource = envoy_config_route_v3_RouteConfiguration_parse(
serialized_resource.data(), serialized_resource.size(), context.arena);
if (resource == nullptr) {
return absl::InvalidArgumentError("Can't parse Listener resource.");
}
MaybeLogRouteConfiguration(context, resource);
// Validate resource.
DecodeResult result;
result.name = UpbStringToStdString(
envoy_config_route_v3_RouteConfiguration_name(resource));
auto route_config_data = absl::make_unique<RouteConfigData>();
grpc_error_handle error = XdsRouteConfigResource::Parse(
context, resource, &route_config_data->resource);
if (error != GRPC_ERROR_NONE) {
result.resource = absl::InvalidArgumentError(grpc_error_std_string(error));
GRPC_ERROR_UNREF(error);
} else {
result.resource = std::move(route_config_data);
}
return std::move(result);
}
} // namespace grpc_core

@ -0,0 +1,211 @@
//
// Copyright 2018 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_CORE_EXT_XDS_XDS_ROUTE_CONFIG_H
#define GRPC_CORE_EXT_XDS_XDS_ROUTE_CONFIG_H
#include <grpc/support/port_platform.h>
#include <map>
#include <string>
#include <vector>
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include "envoy/config/route/v3/route.upb.h"
#include "re2/re2.h"
#include "src/core/ext/xds/xds_common_types.h"
#include "src/core/ext/xds/xds_http_filters.h"
#include "src/core/ext/xds/xds_resource_type.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/matchers/matchers.h"
namespace grpc_core {
bool XdsRbacEnabled();
struct XdsRouteConfigResource {
using TypedPerFilterConfig =
std::map<std::string, XdsHttpFilterImpl::FilterConfig>;
struct RetryPolicy {
internal::StatusCodeSet retry_on;
uint32_t num_retries;
struct RetryBackOff {
Duration base_interval;
Duration max_interval;
bool operator==(const RetryBackOff& other) const {
return base_interval == other.base_interval &&
max_interval == other.max_interval;
}
std::string ToString() const;
};
RetryBackOff retry_back_off;
bool operator==(const RetryPolicy& other) const {
return (retry_on == other.retry_on && num_retries == other.num_retries &&
retry_back_off == other.retry_back_off);
}
std::string ToString() const;
};
// TODO(donnadionne): When we can use absl::variant<>, consider using that
// for: PathMatcher, HeaderMatcher, cluster_name and weighted_clusters
struct Route {
// Matchers for this route.
struct Matchers {
StringMatcher path_matcher;
std::vector<HeaderMatcher> header_matchers;
absl::optional<uint32_t> fraction_per_million;
bool operator==(const Matchers& other) const {
return path_matcher == other.path_matcher &&
header_matchers == other.header_matchers &&
fraction_per_million == other.fraction_per_million;
}
std::string ToString() const;
};
Matchers matchers;
struct UnknownAction {
bool operator==(const UnknownAction& /* other */) const { return true; }
};
struct RouteAction {
struct HashPolicy {
enum Type { HEADER, CHANNEL_ID };
Type type;
bool terminal = false;
// Fields used for type HEADER.
std::string header_name;
std::unique_ptr<RE2> regex = nullptr;
std::string regex_substitution;
HashPolicy() {}
// Copyable.
HashPolicy(const HashPolicy& other);
HashPolicy& operator=(const HashPolicy& other);
// Moveable.
HashPolicy(HashPolicy&& other) noexcept;
HashPolicy& operator=(HashPolicy&& other) noexcept;
bool operator==(const HashPolicy& other) const;
std::string ToString() const;
};
struct ClusterWeight {
std::string name;
uint32_t weight;
TypedPerFilterConfig typed_per_filter_config;
bool operator==(const ClusterWeight& other) const {
return name == other.name && weight == other.weight &&
typed_per_filter_config == other.typed_per_filter_config;
}
std::string ToString() const;
};
std::vector<HashPolicy> hash_policies;
absl::optional<RetryPolicy> retry_policy;
// Action for this route.
// TODO(roth): When we can use absl::variant<>, consider using that
// here, to enforce the fact that only one of the two fields can be set.
std::string cluster_name;
std::vector<ClusterWeight> weighted_clusters;
// Storing the timeout duration from route action:
// RouteAction.max_stream_duration.grpc_timeout_header_max or
// RouteAction.max_stream_duration.max_stream_duration if the former is
// not set.
absl::optional<Duration> max_stream_duration;
bool operator==(const RouteAction& other) const {
return hash_policies == other.hash_policies &&
retry_policy == other.retry_policy &&
cluster_name == other.cluster_name &&
weighted_clusters == other.weighted_clusters &&
max_stream_duration == other.max_stream_duration;
}
std::string ToString() const;
};
struct NonForwardingAction {
bool operator==(const NonForwardingAction& /* other */) const {
return true;
}
};
absl::variant<UnknownAction, RouteAction, NonForwardingAction> action;
TypedPerFilterConfig typed_per_filter_config;
bool operator==(const Route& other) const {
return matchers == other.matchers && action == other.action &&
typed_per_filter_config == other.typed_per_filter_config;
}
std::string ToString() const;
};
struct VirtualHost {
std::vector<std::string> domains;
std::vector<Route> routes;
TypedPerFilterConfig typed_per_filter_config;
bool operator==(const VirtualHost& other) const {
return domains == other.domains && routes == other.routes &&
typed_per_filter_config == other.typed_per_filter_config;
}
};
std::vector<VirtualHost> virtual_hosts;
bool operator==(const XdsRouteConfigResource& other) const {
return virtual_hosts == other.virtual_hosts;
}
std::string ToString() const;
static grpc_error_handle Parse(
const XdsEncodingContext& context,
const envoy_config_route_v3_RouteConfiguration* route_config,
XdsRouteConfigResource* rds_update);
};
class XdsRouteConfigResourceType : public XdsResourceType {
public:
struct RouteConfigData : public ResourceData {
XdsRouteConfigResource resource;
};
absl::string_view type_url() const override {
return "envoy.config.route.v3.RouteConfiguration";
}
absl::string_view v2_type_url() const override {
return "envoy.api.v2.RouteConfiguration";
}
absl::StatusOr<DecodeResult> Decode(const XdsEncodingContext& context,
absl::string_view serialized_resource,
bool /*is_v2*/) const override;
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_XDS_ROUTE_CONFIG_H

@ -147,7 +147,7 @@ absl::optional<size_t> XdsRouting::GetRouteForRequest(
const RouteListIterator& route_list_iterator, absl::string_view path,
grpc_metadata_batch* initial_metadata) {
for (size_t i = 0; i < route_list_iterator.Size(); ++i) {
const XdsApi::Route::Matchers& matchers =
const XdsRouteConfigResource::Route::Matchers& matchers =
route_list_iterator.GetMatchersForRoute(i);
if (matchers.path_matcher.Match(path) &&
HeadersMatch(matchers.header_matchers, initial_metadata) &&
@ -182,8 +182,10 @@ namespace {
const XdsHttpFilterImpl::FilterConfig* FindFilterConfigOverride(
const std::string& instance_name,
const XdsApi::RdsUpdate::VirtualHost& vhost, const XdsApi::Route& route,
const XdsApi::Route::RouteAction::ClusterWeight* cluster_weight) {
const XdsRouteConfigResource::VirtualHost& vhost,
const XdsRouteConfigResource::Route& route,
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
cluster_weight) {
// Check ClusterWeight, if any.
if (cluster_weight != nullptr) {
auto it = cluster_weight->typed_per_filter_config.find(instance_name);
@ -203,10 +205,12 @@ const XdsHttpFilterImpl::FilterConfig* FindFilterConfigOverride(
XdsRouting::GeneratePerHttpFilterConfigsResult
XdsRouting::GeneratePerHTTPFilterConfigs(
const std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>&
const std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>&
http_filters,
const XdsApi::RdsUpdate::VirtualHost& vhost, const XdsApi::Route& route,
const XdsApi::Route::RouteAction::ClusterWeight* cluster_weight,
const XdsRouteConfigResource::VirtualHost& vhost,
const XdsRouteConfigResource::Route& route,
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
cluster_weight,
grpc_channel_args* args) {
GeneratePerHttpFilterConfigsResult result;
result.args = args;

@ -51,7 +51,7 @@ class XdsRouting {
// Number of routes.
virtual size_t Size() const = 0;
// Returns the matchers for the route at the specified index.
virtual const XdsApi::Route::Matchers& GetMatchersForRoute(
virtual const XdsRouteConfigResource::Route::Matchers& GetMatchersForRoute(
size_t index) const = 0;
};
@ -86,10 +86,12 @@ class XdsRouting {
// Generates a map of per_filter_configs. \a args is consumed.
static GeneratePerHttpFilterConfigsResult GeneratePerHTTPFilterConfigs(
const std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>&
const std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>&
http_filters,
const XdsApi::RdsUpdate::VirtualHost& vhost, const XdsApi::Route& route,
const XdsApi::Route::RouteAction::ClusterWeight* cluster_weight,
const XdsRouteConfigResource::VirtualHost& vhost,
const XdsRouteConfigResource::Route& route,
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
cluster_weight,
grpc_channel_args* args);
};

@ -94,7 +94,7 @@ class XdsServerConfigFetcher::ListenerWatcher
grpc_server_xds_status_notifier serving_status_notifier,
std::string listening_address);
void OnListenerChanged(XdsApi::LdsUpdate listener) override;
void OnListenerChanged(XdsListenerResource listener) override;
void OnError(grpc_error_handle error) override;
@ -140,10 +140,10 @@ class XdsServerConfigFetcher::ListenerWatcher
class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager
: public grpc_server_config_fetcher::ConnectionManager {
public:
FilterChainMatchManager(
RefCountedPtr<XdsClient> xds_client,
XdsApi::LdsUpdate::FilterChainMap filter_chain_map,
absl::optional<XdsApi::LdsUpdate::FilterChainData> default_filter_chain);
FilterChainMatchManager(RefCountedPtr<XdsClient> xds_client,
XdsListenerResource::FilterChainMap filter_chain_map,
absl::optional<XdsListenerResource::FilterChainData>
default_filter_chain);
absl::StatusOr<grpc_channel_args*> UpdateChannelArgsForConnection(
grpc_channel_args* args, grpc_endpoint* tcp) override;
@ -154,11 +154,11 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager
void StartRdsWatch(RefCountedPtr<ListenerWatcher> listener_watcher)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ListenerWatcher::mu_);
const XdsApi::LdsUpdate::FilterChainMap& filter_chain_map() const {
const XdsListenerResource::FilterChainMap& filter_chain_map() const {
return filter_chain_map_;
}
const absl::optional<XdsApi::LdsUpdate::FilterChainData>&
const absl::optional<XdsListenerResource::FilterChainData>&
default_filter_chain() const {
return default_filter_chain_;
}
@ -176,7 +176,7 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager
class RouteConfigWatcher;
struct RdsUpdateState {
RouteConfigWatcher* watcher;
absl::optional<absl::StatusOr<XdsApi::RdsUpdate>> rds_update;
absl::optional<absl::StatusOr<XdsRouteConfigResource>> rds_update;
};
class XdsServerConfigSelector;
@ -185,12 +185,12 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager
absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
CreateOrGetXdsCertificateProviderFromFilterChainData(
const XdsApi::LdsUpdate::FilterChainData* filter_chain);
const XdsListenerResource::FilterChainData* filter_chain);
// Helper functions invoked by RouteConfigWatcher when there are updates to
// RDS resources.
void OnRouteConfigChanged(const std::string& resource_name,
XdsApi::RdsUpdate route_config);
XdsRouteConfigResource route_config);
void OnError(const std::string& resource_name, grpc_error_handle error);
void OnResourceDoesNotExist(const std::string& resource_name);
@ -198,14 +198,14 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager
// This ref is only kept around till the FilterChainMatchManager becomes
// ready.
RefCountedPtr<ListenerWatcher> listener_watcher_;
const XdsApi::LdsUpdate::FilterChainMap filter_chain_map_;
const absl::optional<XdsApi::LdsUpdate::FilterChainData>
const XdsListenerResource::FilterChainMap filter_chain_map_;
const absl::optional<XdsListenerResource::FilterChainData>
default_filter_chain_;
Mutex mu_;
size_t rds_resources_yet_to_fetch_ ABSL_GUARDED_BY(mu_) = 0;
std::map<std::string /* resource_name */, RdsUpdateState> rds_map_
ABSL_GUARDED_BY(mu_);
std::map<const XdsApi::LdsUpdate::FilterChainData*, CertificateProviders>
std::map<const XdsListenerResource::FilterChainData*, CertificateProviders>
certificate_providers_map_ ABSL_GUARDED_BY(mu_);
};
@ -225,7 +225,7 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
: resource_name_(std::move(resource_name)),
filter_chain_match_manager_(std::move(filter_chain_match_manager)) {}
void OnRouteConfigChanged(XdsApi::RdsUpdate route_config) override {
void OnRouteConfigChanged(XdsRouteConfigResource route_config) override {
filter_chain_match_manager_->OnRouteConfigChanged(resource_name_,
std::move(route_config));
}
@ -251,8 +251,8 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
XdsServerConfigSelector : public ServerConfigSelector {
public:
static absl::StatusOr<RefCountedPtr<XdsServerConfigSelector>> Create(
XdsApi::RdsUpdate rds_update,
const std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>&
XdsRouteConfigResource rds_update,
const std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>&
http_filters);
~XdsServerConfigSelector() override = default;
@ -263,7 +263,7 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
struct Route {
// true if an action other than kNonForwardingAction is configured.
bool unsupported_action;
XdsApi::Route::Matchers matchers;
XdsRouteConfigResource::Route::Matchers matchers;
RefCountedPtr<ServiceConfig> method_config;
};
@ -274,7 +274,7 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
size_t Size() const override { return routes_->size(); }
const XdsApi::Route::Matchers& GetMatchersForRoute(
const XdsRouteConfigResource::Route::Matchers& GetMatchersForRoute(
size_t index) const override {
return (*routes_)[index].matchers;
}
@ -314,8 +314,8 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
: public ServerConfigSelectorProvider {
public:
StaticXdsServerConfigSelectorProvider(
absl::StatusOr<XdsApi::RdsUpdate> static_resource,
std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>
absl::StatusOr<XdsRouteConfigResource> static_resource,
std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>
http_filters)
: static_resource_(std::move(static_resource)),
http_filters_(std::move(http_filters)) {}
@ -335,8 +335,8 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
void CancelWatch() override { watcher_.reset(); }
private:
absl::StatusOr<XdsApi::RdsUpdate> static_resource_;
std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>
absl::StatusOr<XdsRouteConfigResource> static_resource_;
std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>
http_filters_;
std::unique_ptr<ServerConfigSelectorProvider::ServerConfigSelectorWatcher>
watcher_;
@ -350,8 +350,8 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
public:
DynamicXdsServerConfigSelectorProvider(
RefCountedPtr<XdsClient> xds_client, std::string resource_name,
absl::StatusOr<XdsApi::RdsUpdate> initial_resource,
std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>
absl::StatusOr<XdsRouteConfigResource> initial_resource,
std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>
http_filters);
absl::StatusOr<RefCountedPtr<ServerConfigSelector>> Watch(
@ -362,19 +362,19 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
private:
class RouteConfigWatcher;
void OnRouteConfigChanged(XdsApi::RdsUpdate rds_update);
void OnRouteConfigChanged(XdsRouteConfigResource rds_update);
void OnError(grpc_error_handle error);
void OnResourceDoesNotExist();
RefCountedPtr<XdsClient> xds_client_;
std::string resource_name_;
std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>
std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>
http_filters_;
RouteConfigWatcher* route_config_watcher_ = nullptr;
Mutex mu_;
std::unique_ptr<ServerConfigSelectorProvider::ServerConfigSelectorWatcher>
watcher_ ABSL_GUARDED_BY(mu_);
absl::StatusOr<XdsApi::RdsUpdate> resource_ ABSL_GUARDED_BY(mu_);
absl::StatusOr<XdsRouteConfigResource> resource_ ABSL_GUARDED_BY(mu_);
};
// A watcher implementation for updating the RDS resource used by
@ -387,7 +387,7 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
RefCountedPtr<DynamicXdsServerConfigSelectorProvider> parent)
: parent_(std::move(parent)) {}
void OnRouteConfigChanged(XdsApi::RdsUpdate route_config) override {
void OnRouteConfigChanged(XdsRouteConfigResource route_config) override {
parent_->OnRouteConfigChanged(std::move(route_config));
}
@ -458,7 +458,7 @@ XdsServerConfigFetcher::ListenerWatcher::ListenerWatcher(
listening_address_(std::move(listening_address)) {}
void XdsServerConfigFetcher::ListenerWatcher::OnListenerChanged(
XdsApi::LdsUpdate listener) {
XdsListenerResource listener) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_server_config_fetcher_trace)) {
gpr_log(GPR_INFO,
"[ListenerWatcher %p] Received LDS update from xds client %p: %s",
@ -578,8 +578,9 @@ void XdsServerConfigFetcher::ListenerWatcher::
XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
FilterChainMatchManager(
RefCountedPtr<XdsClient> xds_client,
XdsApi::LdsUpdate::FilterChainMap filter_chain_map,
absl::optional<XdsApi::LdsUpdate::FilterChainData> default_filter_chain)
XdsListenerResource::FilterChainMap filter_chain_map,
absl::optional<XdsListenerResource::FilterChainData>
default_filter_chain)
: xds_client_(std::move(xds_client)),
filter_chain_map_(std::move(filter_chain_map)),
default_filter_chain_(std::move(default_filter_chain)) {}
@ -647,7 +648,7 @@ void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
CreateOrGetXdsCertificateProviderFromFilterChainData(
const XdsApi::LdsUpdate::FilterChainData* filter_chain) {
const XdsListenerResource::FilterChainData* filter_chain) {
MutexLock lock(&mu_);
auto it = certificate_providers_map_.find(filter_chain);
if (it != certificate_providers_map_.end()) {
@ -711,7 +712,7 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
OnRouteConfigChanged(const std::string& resource_name,
XdsApi::RdsUpdate route_config) {
XdsRouteConfigResource route_config) {
RefCountedPtr<ListenerWatcher> listener_watcher;
{
MutexLock lock(&mu_);
@ -777,8 +778,8 @@ void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
}
}
const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourcePort(
const XdsApi::LdsUpdate::FilterChainMap::SourcePortsMap& source_ports_map,
const XdsListenerResource::FilterChainData* FindFilterChainDataForSourcePort(
const XdsListenerResource::FilterChainMap::SourcePortsMap& source_ports_map,
absl::string_view port_str) {
int port = 0;
if (!absl::SimpleAtoi(port_str, &port)) return nullptr;
@ -794,10 +795,10 @@ const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourcePort(
return nullptr;
}
const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourceIp(
const XdsApi::LdsUpdate::FilterChainMap::SourceIpVector& source_ip_vector,
const XdsListenerResource::FilterChainData* FindFilterChainDataForSourceIp(
const XdsListenerResource::FilterChainMap::SourceIpVector& source_ip_vector,
const grpc_resolved_address* source_ip, absl::string_view port) {
const XdsApi::LdsUpdate::FilterChainMap::SourceIp* best_match = nullptr;
const XdsListenerResource::FilterChainMap::SourceIp* best_match = nullptr;
for (const auto& entry : source_ip_vector) {
// Special case for catch-all
if (!entry.prefix_range.has_value()) {
@ -840,8 +841,8 @@ bool IsLoopbackIp(const grpc_resolved_address* address) {
return false;
}
const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourceType(
const XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceTypesArray&
const XdsListenerResource::FilterChainData* FindFilterChainDataForSourceType(
const XdsListenerResource::FilterChainMap::ConnectionSourceTypesArray&
source_types_array,
grpc_endpoint* tcp, absl::string_view destination_ip) {
auto source_uri = URI::Parse(grpc_endpoint_get_peer(tcp));
@ -865,34 +866,34 @@ const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourceType(
}
// Use kAny only if kSameIporLoopback and kExternal are empty
if (source_types_array[static_cast<int>(
XdsApi::LdsUpdate::FilterChainMap::
XdsListenerResource::FilterChainMap::
ConnectionSourceType::kSameIpOrLoopback)]
.empty() &&
source_types_array[static_cast<int>(XdsApi::LdsUpdate::FilterChainMap::
source_types_array[static_cast<int>(XdsListenerResource::FilterChainMap::
ConnectionSourceType::kExternal)]
.empty()) {
return FindFilterChainDataForSourceIp(
source_types_array[static_cast<int>(
XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::kAny)],
XdsListenerResource::FilterChainMap::ConnectionSourceType::kAny)],
&source_addr, port);
}
if (IsLoopbackIp(&source_addr) || host == destination_ip) {
return FindFilterChainDataForSourceIp(
source_types_array[static_cast<int>(
XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::
XdsListenerResource::FilterChainMap::ConnectionSourceType::
kSameIpOrLoopback)],
&source_addr, port);
} else {
return FindFilterChainDataForSourceIp(
source_types_array[static_cast<int>(
XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::
XdsListenerResource::FilterChainMap::ConnectionSourceType::
kExternal)],
&source_addr, port);
}
}
const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForDestinationIp(
const XdsApi::LdsUpdate::FilterChainMap::DestinationIpVector
const XdsListenerResource::FilterChainData* FindFilterChainDataForDestinationIp(
const XdsListenerResource::FilterChainMap::DestinationIpVector
destination_ip_vector,
grpc_endpoint* tcp) {
auto destination_uri = URI::Parse(grpc_endpoint_get_local_address(tcp));
@ -914,7 +915,8 @@ const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForDestinationIp(
GRPC_ERROR_UNREF(error);
return nullptr;
}
const XdsApi::LdsUpdate::FilterChainMap::DestinationIp* best_match = nullptr;
const XdsListenerResource::FilterChainMap::DestinationIp* best_match =
nullptr;
for (const auto& entry : destination_ip_vector) {
// Special case for catch-all
if (!entry.prefix_range.has_value()) {
@ -986,7 +988,7 @@ absl::StatusOr<grpc_channel_args*> XdsServerConfigFetcher::ListenerWatcher::
filter_chain->http_connection_manager.rds_update.value(),
filter_chain->http_connection_manager.http_filters);
} else {
absl::StatusOr<XdsApi::RdsUpdate> initial_resource;
absl::StatusOr<XdsRouteConfigResource> initial_resource;
{
MutexLock lock(&mu_);
initial_resource =
@ -1035,8 +1037,9 @@ absl::StatusOr<
FilterChainMatchManager::XdsServerConfigSelector>>
XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
XdsServerConfigSelector::Create(
XdsApi::RdsUpdate rds_update,
const std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>&
XdsRouteConfigResource rds_update,
const std::vector<
XdsListenerResource::HttpConnectionManager::HttpFilter>&
http_filters) {
auto config_selector = MakeRefCounted<XdsServerConfigSelector>();
for (auto& vhost : rds_update.virtual_hosts) {
@ -1048,8 +1051,8 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
auto& config_selector_route = virtual_host.routes.back();
config_selector_route.matchers = std::move(route.matchers);
config_selector_route.unsupported_action =
absl::get_if<XdsApi::Route::NonForwardingAction>(&route.action) ==
nullptr;
absl::get_if<XdsRouteConfigResource::Route::NonForwardingAction>(
&route.action) == nullptr;
XdsRouting::GeneratePerHttpFilterConfigsResult result =
XdsRouting::GeneratePerHTTPFilterConfigs(http_filters, vhost, route,
nullptr, nullptr);
@ -1146,8 +1149,8 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
DynamicXdsServerConfigSelectorProvider::
DynamicXdsServerConfigSelectorProvider(
RefCountedPtr<XdsClient> xds_client, std::string resource_name,
absl::StatusOr<XdsApi::RdsUpdate> initial_resource,
std::vector<XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter>
absl::StatusOr<XdsRouteConfigResource> initial_resource,
std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>
http_filters)
: xds_client_(std::move(xds_client)),
resource_name_(std::move(resource_name)),
@ -1166,7 +1169,7 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
std::unique_ptr<
ServerConfigSelectorProvider::ServerConfigSelectorWatcher>
watcher) {
absl::StatusOr<XdsApi::RdsUpdate> resource;
absl::StatusOr<XdsRouteConfigResource> resource;
{
MutexLock lock(&mu_);
GPR_ASSERT(watcher_ == nullptr);
@ -1189,7 +1192,7 @@ void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
DynamicXdsServerConfigSelectorProvider::OnRouteConfigChanged(
XdsApi::RdsUpdate rds_update) {
XdsRouteConfigResource rds_update) {
MutexLock lock(&mu_);
resource_ = std::move(rds_update);
if (watcher_ == nullptr) {

@ -340,8 +340,13 @@ CORE_SOURCE_FILES = [
'src/core/ext/xds/xds_channel_stack_modifier.cc',
'src/core/ext/xds/xds_client.cc',
'src/core/ext/xds/xds_client_stats.cc',
'src/core/ext/xds/xds_cluster.cc',
'src/core/ext/xds/xds_common_types.cc',
'src/core/ext/xds/xds_endpoint.cc',
'src/core/ext/xds/xds_http_fault_filter.cc',
'src/core/ext/xds/xds_http_filters.cc',
'src/core/ext/xds/xds_listener.cc',
'src/core/ext/xds/xds_route_config.cc',
'src/core/ext/xds/xds_routing.cc',
'src/core/ext/xds/xds_server_config_fetcher.cc',
'src/core/lib/address_utils/parse_address.cc',

@ -1706,6 +1706,7 @@ src/core/ext/xds/certificate_provider_store.cc \
src/core/ext/xds/certificate_provider_store.h \
src/core/ext/xds/file_watcher_certificate_provider_factory.cc \
src/core/ext/xds/file_watcher_certificate_provider_factory.h \
src/core/ext/xds/upb_utils.h \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_api.h \
src/core/ext/xds/xds_bootstrap.cc \
@ -1719,10 +1720,21 @@ src/core/ext/xds/xds_client.cc \
src/core/ext/xds/xds_client.h \
src/core/ext/xds/xds_client_stats.cc \
src/core/ext/xds/xds_client_stats.h \
src/core/ext/xds/xds_cluster.cc \
src/core/ext/xds/xds_cluster.h \
src/core/ext/xds/xds_common_types.cc \
src/core/ext/xds/xds_common_types.h \
src/core/ext/xds/xds_endpoint.cc \
src/core/ext/xds/xds_endpoint.h \
src/core/ext/xds/xds_http_fault_filter.cc \
src/core/ext/xds/xds_http_fault_filter.h \
src/core/ext/xds/xds_http_filters.cc \
src/core/ext/xds/xds_http_filters.h \
src/core/ext/xds/xds_listener.cc \
src/core/ext/xds/xds_listener.h \
src/core/ext/xds/xds_resource_type.h \
src/core/ext/xds/xds_route_config.cc \
src/core/ext/xds/xds_route_config.h \
src/core/ext/xds/xds_routing.cc \
src/core/ext/xds/xds_routing.h \
src/core/ext/xds/xds_server_config_fetcher.cc \

@ -1500,6 +1500,7 @@ src/core/ext/xds/certificate_provider_store.cc \
src/core/ext/xds/certificate_provider_store.h \
src/core/ext/xds/file_watcher_certificate_provider_factory.cc \
src/core/ext/xds/file_watcher_certificate_provider_factory.h \
src/core/ext/xds/upb_utils.h \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_api.h \
src/core/ext/xds/xds_bootstrap.cc \
@ -1513,10 +1514,21 @@ src/core/ext/xds/xds_client.cc \
src/core/ext/xds/xds_client.h \
src/core/ext/xds/xds_client_stats.cc \
src/core/ext/xds/xds_client_stats.h \
src/core/ext/xds/xds_cluster.cc \
src/core/ext/xds/xds_cluster.h \
src/core/ext/xds/xds_common_types.cc \
src/core/ext/xds/xds_common_types.h \
src/core/ext/xds/xds_endpoint.cc \
src/core/ext/xds/xds_endpoint.h \
src/core/ext/xds/xds_http_fault_filter.cc \
src/core/ext/xds/xds_http_fault_filter.h \
src/core/ext/xds/xds_http_filters.cc \
src/core/ext/xds/xds_http_filters.h \
src/core/ext/xds/xds_listener.cc \
src/core/ext/xds/xds_listener.h \
src/core/ext/xds/xds_resource_type.h \
src/core/ext/xds/xds_route_config.cc \
src/core/ext/xds/xds_route_config.h \
src/core/ext/xds/xds_routing.cc \
src/core/ext/xds/xds_routing.h \
src/core/ext/xds/xds_server_config_fetcher.cc \

Loading…
Cancel
Save