diff --git a/CMakeLists.txt b/CMakeLists.txt
index 05fa556d4b5..10e5589b360 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2657,18 +2657,24 @@ add_library(grpc
src/core/xds/grpc/xds_certificate_provider.cc
src/core/xds/grpc/xds_client_grpc.cc
src/core/xds/grpc/xds_cluster.cc
+ src/core/xds/grpc/xds_cluster_parser.cc
src/core/xds/grpc/xds_cluster_specifier_plugin.cc
src/core/xds/grpc/xds_common_types.cc
+ src/core/xds/grpc/xds_common_types_parser.cc
src/core/xds/grpc/xds_endpoint.cc
+ src/core/xds/grpc/xds_endpoint_parser.cc
src/core/xds/grpc/xds_health_status.cc
src/core/xds/grpc/xds_http_fault_filter.cc
- src/core/xds/grpc/xds_http_filters.cc
+ src/core/xds/grpc/xds_http_filter_registry.cc
src/core/xds/grpc/xds_http_rbac_filter.cc
src/core/xds/grpc/xds_http_stateful_session_filter.cc
src/core/xds/grpc/xds_lb_policy_registry.cc
src/core/xds/grpc/xds_listener.cc
+ src/core/xds/grpc/xds_listener_parser.cc
src/core/xds/grpc/xds_route_config.cc
+ src/core/xds/grpc/xds_route_config_parser.cc
src/core/xds/grpc/xds_routing.cc
+ src/core/xds/grpc/xds_server_grpc.cc
src/core/xds/grpc/xds_transport_grpc.cc
src/core/xds/xds_client/xds_api.cc
src/core/xds/xds_client/xds_bootstrap.cc
diff --git a/Makefile b/Makefile
index b7daf196bc9..8db5503b558 100644
--- a/Makefile
+++ b/Makefile
@@ -1491,18 +1491,24 @@ LIBGRPC_SRC = \
src/core/xds/grpc/xds_certificate_provider.cc \
src/core/xds/grpc/xds_client_grpc.cc \
src/core/xds/grpc/xds_cluster.cc \
+ src/core/xds/grpc/xds_cluster_parser.cc \
src/core/xds/grpc/xds_cluster_specifier_plugin.cc \
src/core/xds/grpc/xds_common_types.cc \
+ src/core/xds/grpc/xds_common_types_parser.cc \
src/core/xds/grpc/xds_endpoint.cc \
+ src/core/xds/grpc/xds_endpoint_parser.cc \
src/core/xds/grpc/xds_health_status.cc \
src/core/xds/grpc/xds_http_fault_filter.cc \
- src/core/xds/grpc/xds_http_filters.cc \
+ src/core/xds/grpc/xds_http_filter_registry.cc \
src/core/xds/grpc/xds_http_rbac_filter.cc \
src/core/xds/grpc/xds_http_stateful_session_filter.cc \
src/core/xds/grpc/xds_lb_policy_registry.cc \
src/core/xds/grpc/xds_listener.cc \
+ src/core/xds/grpc/xds_listener_parser.cc \
src/core/xds/grpc/xds_route_config.cc \
+ src/core/xds/grpc/xds_route_config_parser.cc \
src/core/xds/grpc/xds_routing.cc \
+ src/core/xds/grpc/xds_server_grpc.cc \
src/core/xds/grpc/xds_transport_grpc.cc \
src/core/xds/xds_client/xds_api.cc \
src/core/xds/xds_client/xds_bootstrap.cc \
diff --git a/Package.swift b/Package.swift
index 1b5e8ceccfe..ddceef95c22 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1975,18 +1975,25 @@ let package = Package(
"src/core/xds/grpc/xds_client_grpc.h",
"src/core/xds/grpc/xds_cluster.cc",
"src/core/xds/grpc/xds_cluster.h",
+ "src/core/xds/grpc/xds_cluster_parser.cc",
+ "src/core/xds/grpc/xds_cluster_parser.h",
"src/core/xds/grpc/xds_cluster_specifier_plugin.cc",
"src/core/xds/grpc/xds_cluster_specifier_plugin.h",
"src/core/xds/grpc/xds_common_types.cc",
"src/core/xds/grpc/xds_common_types.h",
+ "src/core/xds/grpc/xds_common_types_parser.cc",
+ "src/core/xds/grpc/xds_common_types_parser.h",
"src/core/xds/grpc/xds_endpoint.cc",
"src/core/xds/grpc/xds_endpoint.h",
+ "src/core/xds/grpc/xds_endpoint_parser.cc",
+ "src/core/xds/grpc/xds_endpoint_parser.h",
"src/core/xds/grpc/xds_health_status.cc",
"src/core/xds/grpc/xds_health_status.h",
"src/core/xds/grpc/xds_http_fault_filter.cc",
"src/core/xds/grpc/xds_http_fault_filter.h",
- "src/core/xds/grpc/xds_http_filters.cc",
- "src/core/xds/grpc/xds_http_filters.h",
+ "src/core/xds/grpc/xds_http_filter.h",
+ "src/core/xds/grpc/xds_http_filter_registry.cc",
+ "src/core/xds/grpc/xds_http_filter_registry.h",
"src/core/xds/grpc/xds_http_rbac_filter.cc",
"src/core/xds/grpc/xds_http_rbac_filter.h",
"src/core/xds/grpc/xds_http_stateful_session_filter.cc",
@@ -1995,10 +2002,16 @@ let package = Package(
"src/core/xds/grpc/xds_lb_policy_registry.h",
"src/core/xds/grpc/xds_listener.cc",
"src/core/xds/grpc/xds_listener.h",
+ "src/core/xds/grpc/xds_listener_parser.cc",
+ "src/core/xds/grpc/xds_listener_parser.h",
"src/core/xds/grpc/xds_route_config.cc",
"src/core/xds/grpc/xds_route_config.h",
+ "src/core/xds/grpc/xds_route_config_parser.cc",
+ "src/core/xds/grpc/xds_route_config_parser.h",
"src/core/xds/grpc/xds_routing.cc",
"src/core/xds/grpc/xds_routing.h",
+ "src/core/xds/grpc/xds_server_grpc.cc",
+ "src/core/xds/grpc/xds_server_grpc.h",
"src/core/xds/grpc/xds_transport_grpc.cc",
"src/core/xds/grpc/xds_transport_grpc.h",
"src/core/xds/xds_client/xds_api.cc",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index f90854833e9..02edb7c33f3 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -1228,18 +1228,25 @@ libs:
- src/core/xds/grpc/xds_certificate_provider.h
- src/core/xds/grpc/xds_client_grpc.h
- src/core/xds/grpc/xds_cluster.h
+ - src/core/xds/grpc/xds_cluster_parser.h
- src/core/xds/grpc/xds_cluster_specifier_plugin.h
- src/core/xds/grpc/xds_common_types.h
+ - src/core/xds/grpc/xds_common_types_parser.h
- src/core/xds/grpc/xds_endpoint.h
+ - src/core/xds/grpc/xds_endpoint_parser.h
- src/core/xds/grpc/xds_health_status.h
- src/core/xds/grpc/xds_http_fault_filter.h
- - src/core/xds/grpc/xds_http_filters.h
+ - src/core/xds/grpc/xds_http_filter.h
+ - src/core/xds/grpc/xds_http_filter_registry.h
- src/core/xds/grpc/xds_http_rbac_filter.h
- src/core/xds/grpc/xds_http_stateful_session_filter.h
- src/core/xds/grpc/xds_lb_policy_registry.h
- src/core/xds/grpc/xds_listener.h
+ - src/core/xds/grpc/xds_listener_parser.h
- src/core/xds/grpc/xds_route_config.h
+ - src/core/xds/grpc/xds_route_config_parser.h
- src/core/xds/grpc/xds_routing.h
+ - src/core/xds/grpc/xds_server_grpc.h
- src/core/xds/grpc/xds_transport_grpc.h
- src/core/xds/xds_client/xds_api.h
- src/core/xds/xds_client/xds_bootstrap.h
@@ -2033,18 +2040,24 @@ libs:
- src/core/xds/grpc/xds_certificate_provider.cc
- src/core/xds/grpc/xds_client_grpc.cc
- src/core/xds/grpc/xds_cluster.cc
+ - src/core/xds/grpc/xds_cluster_parser.cc
- src/core/xds/grpc/xds_cluster_specifier_plugin.cc
- src/core/xds/grpc/xds_common_types.cc
+ - src/core/xds/grpc/xds_common_types_parser.cc
- src/core/xds/grpc/xds_endpoint.cc
+ - src/core/xds/grpc/xds_endpoint_parser.cc
- src/core/xds/grpc/xds_health_status.cc
- src/core/xds/grpc/xds_http_fault_filter.cc
- - src/core/xds/grpc/xds_http_filters.cc
+ - src/core/xds/grpc/xds_http_filter_registry.cc
- src/core/xds/grpc/xds_http_rbac_filter.cc
- src/core/xds/grpc/xds_http_stateful_session_filter.cc
- src/core/xds/grpc/xds_lb_policy_registry.cc
- src/core/xds/grpc/xds_listener.cc
+ - src/core/xds/grpc/xds_listener_parser.cc
- src/core/xds/grpc/xds_route_config.cc
+ - src/core/xds/grpc/xds_route_config_parser.cc
- src/core/xds/grpc/xds_routing.cc
+ - src/core/xds/grpc/xds_server_grpc.cc
- src/core/xds/grpc/xds_transport_grpc.cc
- src/core/xds/xds_client/xds_api.cc
- src/core/xds/xds_client/xds_bootstrap.cc
diff --git a/config.m4 b/config.m4
index 81c63cb189c..619d9761de4 100644
--- a/config.m4
+++ b/config.m4
@@ -866,18 +866,24 @@ if test "$PHP_GRPC" != "no"; then
src/core/xds/grpc/xds_certificate_provider.cc \
src/core/xds/grpc/xds_client_grpc.cc \
src/core/xds/grpc/xds_cluster.cc \
+ src/core/xds/grpc/xds_cluster_parser.cc \
src/core/xds/grpc/xds_cluster_specifier_plugin.cc \
src/core/xds/grpc/xds_common_types.cc \
+ src/core/xds/grpc/xds_common_types_parser.cc \
src/core/xds/grpc/xds_endpoint.cc \
+ src/core/xds/grpc/xds_endpoint_parser.cc \
src/core/xds/grpc/xds_health_status.cc \
src/core/xds/grpc/xds_http_fault_filter.cc \
- src/core/xds/grpc/xds_http_filters.cc \
+ src/core/xds/grpc/xds_http_filter_registry.cc \
src/core/xds/grpc/xds_http_rbac_filter.cc \
src/core/xds/grpc/xds_http_stateful_session_filter.cc \
src/core/xds/grpc/xds_lb_policy_registry.cc \
src/core/xds/grpc/xds_listener.cc \
+ src/core/xds/grpc/xds_listener_parser.cc \
src/core/xds/grpc/xds_route_config.cc \
+ src/core/xds/grpc/xds_route_config_parser.cc \
src/core/xds/grpc/xds_routing.cc \
+ src/core/xds/grpc/xds_server_grpc.cc \
src/core/xds/grpc/xds_transport_grpc.cc \
src/core/xds/xds_client/xds_api.cc \
src/core/xds/xds_client/xds_bootstrap.cc \
diff --git a/config.w32 b/config.w32
index f45e109de2c..0384064082d 100644
--- a/config.w32
+++ b/config.w32
@@ -831,18 +831,24 @@ if (PHP_GRPC != "no") {
"src\\core\\xds\\grpc\\xds_certificate_provider.cc " +
"src\\core\\xds\\grpc\\xds_client_grpc.cc " +
"src\\core\\xds\\grpc\\xds_cluster.cc " +
+ "src\\core\\xds\\grpc\\xds_cluster_parser.cc " +
"src\\core\\xds\\grpc\\xds_cluster_specifier_plugin.cc " +
"src\\core\\xds\\grpc\\xds_common_types.cc " +
+ "src\\core\\xds\\grpc\\xds_common_types_parser.cc " +
"src\\core\\xds\\grpc\\xds_endpoint.cc " +
+ "src\\core\\xds\\grpc\\xds_endpoint_parser.cc " +
"src\\core\\xds\\grpc\\xds_health_status.cc " +
"src\\core\\xds\\grpc\\xds_http_fault_filter.cc " +
- "src\\core\\xds\\grpc\\xds_http_filters.cc " +
+ "src\\core\\xds\\grpc\\xds_http_filter_registry.cc " +
"src\\core\\xds\\grpc\\xds_http_rbac_filter.cc " +
"src\\core\\xds\\grpc\\xds_http_stateful_session_filter.cc " +
"src\\core\\xds\\grpc\\xds_lb_policy_registry.cc " +
"src\\core\\xds\\grpc\\xds_listener.cc " +
+ "src\\core\\xds\\grpc\\xds_listener_parser.cc " +
"src\\core\\xds\\grpc\\xds_route_config.cc " +
+ "src\\core\\xds\\grpc\\xds_route_config_parser.cc " +
"src\\core\\xds\\grpc\\xds_routing.cc " +
+ "src\\core\\xds\\grpc\\xds_server_grpc.cc " +
"src\\core\\xds\\grpc\\xds_transport_grpc.cc " +
"src\\core\\xds\\xds_client\\xds_api.cc " +
"src\\core\\xds\\xds_client\\xds_bootstrap.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 137e0723b6d..2063af27118 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -1336,19 +1336,26 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_certificate_provider.h',
'src/core/xds/grpc/xds_client_grpc.h',
'src/core/xds/grpc/xds_cluster.h',
+ 'src/core/xds/grpc/xds_cluster_parser.h',
'src/core/xds/grpc/xds_cluster_specifier_plugin.h',
'src/core/xds/grpc/xds_common_types.h',
+ 'src/core/xds/grpc/xds_common_types_parser.h',
'src/core/xds/grpc/xds_enabled_server.h',
'src/core/xds/grpc/xds_endpoint.h',
+ 'src/core/xds/grpc/xds_endpoint_parser.h',
'src/core/xds/grpc/xds_health_status.h',
'src/core/xds/grpc/xds_http_fault_filter.h',
- 'src/core/xds/grpc/xds_http_filters.h',
+ 'src/core/xds/grpc/xds_http_filter.h',
+ 'src/core/xds/grpc/xds_http_filter_registry.h',
'src/core/xds/grpc/xds_http_rbac_filter.h',
'src/core/xds/grpc/xds_http_stateful_session_filter.h',
'src/core/xds/grpc/xds_lb_policy_registry.h',
'src/core/xds/grpc/xds_listener.h',
+ 'src/core/xds/grpc/xds_listener_parser.h',
'src/core/xds/grpc/xds_route_config.h',
+ 'src/core/xds/grpc/xds_route_config_parser.h',
'src/core/xds/grpc/xds_routing.h',
+ 'src/core/xds/grpc/xds_server_grpc.h',
'src/core/xds/grpc/xds_transport_grpc.h',
'src/core/xds/xds_client/xds_api.h',
'src/core/xds/xds_client/xds_bootstrap.h',
@@ -2613,19 +2620,26 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_certificate_provider.h',
'src/core/xds/grpc/xds_client_grpc.h',
'src/core/xds/grpc/xds_cluster.h',
+ 'src/core/xds/grpc/xds_cluster_parser.h',
'src/core/xds/grpc/xds_cluster_specifier_plugin.h',
'src/core/xds/grpc/xds_common_types.h',
+ 'src/core/xds/grpc/xds_common_types_parser.h',
'src/core/xds/grpc/xds_enabled_server.h',
'src/core/xds/grpc/xds_endpoint.h',
+ 'src/core/xds/grpc/xds_endpoint_parser.h',
'src/core/xds/grpc/xds_health_status.h',
'src/core/xds/grpc/xds_http_fault_filter.h',
- 'src/core/xds/grpc/xds_http_filters.h',
+ 'src/core/xds/grpc/xds_http_filter.h',
+ 'src/core/xds/grpc/xds_http_filter_registry.h',
'src/core/xds/grpc/xds_http_rbac_filter.h',
'src/core/xds/grpc/xds_http_stateful_session_filter.h',
'src/core/xds/grpc/xds_lb_policy_registry.h',
'src/core/xds/grpc/xds_listener.h',
+ 'src/core/xds/grpc/xds_listener_parser.h',
'src/core/xds/grpc/xds_route_config.h',
+ 'src/core/xds/grpc/xds_route_config_parser.h',
'src/core/xds/grpc/xds_routing.h',
+ 'src/core/xds/grpc/xds_server_grpc.h',
'src/core/xds/grpc/xds_transport_grpc.h',
'src/core/xds/xds_client/xds_api.h',
'src/core/xds/xds_client/xds_bootstrap.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 580ce29b707..a0900b009c6 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -2091,18 +2091,25 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_client_grpc.h',
'src/core/xds/grpc/xds_cluster.cc',
'src/core/xds/grpc/xds_cluster.h',
+ 'src/core/xds/grpc/xds_cluster_parser.cc',
+ 'src/core/xds/grpc/xds_cluster_parser.h',
'src/core/xds/grpc/xds_cluster_specifier_plugin.cc',
'src/core/xds/grpc/xds_cluster_specifier_plugin.h',
'src/core/xds/grpc/xds_common_types.cc',
'src/core/xds/grpc/xds_common_types.h',
+ 'src/core/xds/grpc/xds_common_types_parser.cc',
+ 'src/core/xds/grpc/xds_common_types_parser.h',
'src/core/xds/grpc/xds_endpoint.cc',
'src/core/xds/grpc/xds_endpoint.h',
+ 'src/core/xds/grpc/xds_endpoint_parser.cc',
+ 'src/core/xds/grpc/xds_endpoint_parser.h',
'src/core/xds/grpc/xds_health_status.cc',
'src/core/xds/grpc/xds_health_status.h',
'src/core/xds/grpc/xds_http_fault_filter.cc',
'src/core/xds/grpc/xds_http_fault_filter.h',
- 'src/core/xds/grpc/xds_http_filters.cc',
- 'src/core/xds/grpc/xds_http_filters.h',
+ 'src/core/xds/grpc/xds_http_filter.h',
+ 'src/core/xds/grpc/xds_http_filter_registry.cc',
+ 'src/core/xds/grpc/xds_http_filter_registry.h',
'src/core/xds/grpc/xds_http_rbac_filter.cc',
'src/core/xds/grpc/xds_http_rbac_filter.h',
'src/core/xds/grpc/xds_http_stateful_session_filter.cc',
@@ -2111,10 +2118,16 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_lb_policy_registry.h',
'src/core/xds/grpc/xds_listener.cc',
'src/core/xds/grpc/xds_listener.h',
+ 'src/core/xds/grpc/xds_listener_parser.cc',
+ 'src/core/xds/grpc/xds_listener_parser.h',
'src/core/xds/grpc/xds_route_config.cc',
'src/core/xds/grpc/xds_route_config.h',
+ 'src/core/xds/grpc/xds_route_config_parser.cc',
+ 'src/core/xds/grpc/xds_route_config_parser.h',
'src/core/xds/grpc/xds_routing.cc',
'src/core/xds/grpc/xds_routing.h',
+ 'src/core/xds/grpc/xds_server_grpc.cc',
+ 'src/core/xds/grpc/xds_server_grpc.h',
'src/core/xds/grpc/xds_transport_grpc.cc',
'src/core/xds/grpc/xds_transport_grpc.h',
'src/core/xds/xds_client/xds_api.cc',
@@ -3388,18 +3401,25 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_certificate_provider.h',
'src/core/xds/grpc/xds_client_grpc.h',
'src/core/xds/grpc/xds_cluster.h',
+ 'src/core/xds/grpc/xds_cluster_parser.h',
'src/core/xds/grpc/xds_cluster_specifier_plugin.h',
'src/core/xds/grpc/xds_common_types.h',
+ 'src/core/xds/grpc/xds_common_types_parser.h',
'src/core/xds/grpc/xds_endpoint.h',
+ 'src/core/xds/grpc/xds_endpoint_parser.h',
'src/core/xds/grpc/xds_health_status.h',
'src/core/xds/grpc/xds_http_fault_filter.h',
- 'src/core/xds/grpc/xds_http_filters.h',
+ 'src/core/xds/grpc/xds_http_filter.h',
+ 'src/core/xds/grpc/xds_http_filter_registry.h',
'src/core/xds/grpc/xds_http_rbac_filter.h',
'src/core/xds/grpc/xds_http_stateful_session_filter.h',
'src/core/xds/grpc/xds_lb_policy_registry.h',
'src/core/xds/grpc/xds_listener.h',
+ 'src/core/xds/grpc/xds_listener_parser.h',
'src/core/xds/grpc/xds_route_config.h',
+ 'src/core/xds/grpc/xds_route_config_parser.h',
'src/core/xds/grpc/xds_routing.h',
+ 'src/core/xds/grpc/xds_server_grpc.h',
'src/core/xds/grpc/xds_transport_grpc.h',
'src/core/xds/xds_client/xds_api.h',
'src/core/xds/xds_client/xds_bootstrap.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index c4fc9e0c34c..0608a1907de 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -1977,18 +1977,25 @@ Gem::Specification.new do |s|
s.files += %w( src/core/xds/grpc/xds_client_grpc.h )
s.files += %w( src/core/xds/grpc/xds_cluster.cc )
s.files += %w( src/core/xds/grpc/xds_cluster.h )
+ s.files += %w( src/core/xds/grpc/xds_cluster_parser.cc )
+ s.files += %w( src/core/xds/grpc/xds_cluster_parser.h )
s.files += %w( src/core/xds/grpc/xds_cluster_specifier_plugin.cc )
s.files += %w( src/core/xds/grpc/xds_cluster_specifier_plugin.h )
s.files += %w( src/core/xds/grpc/xds_common_types.cc )
s.files += %w( src/core/xds/grpc/xds_common_types.h )
+ s.files += %w( src/core/xds/grpc/xds_common_types_parser.cc )
+ s.files += %w( src/core/xds/grpc/xds_common_types_parser.h )
s.files += %w( src/core/xds/grpc/xds_endpoint.cc )
s.files += %w( src/core/xds/grpc/xds_endpoint.h )
+ s.files += %w( src/core/xds/grpc/xds_endpoint_parser.cc )
+ s.files += %w( src/core/xds/grpc/xds_endpoint_parser.h )
s.files += %w( src/core/xds/grpc/xds_health_status.cc )
s.files += %w( src/core/xds/grpc/xds_health_status.h )
s.files += %w( src/core/xds/grpc/xds_http_fault_filter.cc )
s.files += %w( src/core/xds/grpc/xds_http_fault_filter.h )
- s.files += %w( src/core/xds/grpc/xds_http_filters.cc )
- s.files += %w( src/core/xds/grpc/xds_http_filters.h )
+ s.files += %w( src/core/xds/grpc/xds_http_filter.h )
+ s.files += %w( src/core/xds/grpc/xds_http_filter_registry.cc )
+ s.files += %w( src/core/xds/grpc/xds_http_filter_registry.h )
s.files += %w( src/core/xds/grpc/xds_http_rbac_filter.cc )
s.files += %w( src/core/xds/grpc/xds_http_rbac_filter.h )
s.files += %w( src/core/xds/grpc/xds_http_stateful_session_filter.cc )
@@ -1997,10 +2004,16 @@ Gem::Specification.new do |s|
s.files += %w( src/core/xds/grpc/xds_lb_policy_registry.h )
s.files += %w( src/core/xds/grpc/xds_listener.cc )
s.files += %w( src/core/xds/grpc/xds_listener.h )
+ s.files += %w( src/core/xds/grpc/xds_listener_parser.cc )
+ s.files += %w( src/core/xds/grpc/xds_listener_parser.h )
s.files += %w( src/core/xds/grpc/xds_route_config.cc )
s.files += %w( src/core/xds/grpc/xds_route_config.h )
+ s.files += %w( src/core/xds/grpc/xds_route_config_parser.cc )
+ s.files += %w( src/core/xds/grpc/xds_route_config_parser.h )
s.files += %w( src/core/xds/grpc/xds_routing.cc )
s.files += %w( src/core/xds/grpc/xds_routing.h )
+ s.files += %w( src/core/xds/grpc/xds_server_grpc.cc )
+ s.files += %w( src/core/xds/grpc/xds_server_grpc.h )
s.files += %w( src/core/xds/grpc/xds_transport_grpc.cc )
s.files += %w( src/core/xds/grpc/xds_transport_grpc.h )
s.files += %w( src/core/xds/xds_client/xds_api.cc )
diff --git a/package.xml b/package.xml
index ff3a77d0382..339828a27b3 100644
--- a/package.xml
+++ b/package.xml
@@ -1959,18 +1959,25 @@
+
+
+
+
+
+
-
-
+
+
+
@@ -1979,10 +1986,16 @@
+
+
+
+
+
+
diff --git a/src/core/BUILD b/src/core/BUILD
index 4c91a2d7f2b..e1b6c0ac465 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -5229,24 +5229,226 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "xds_common_types",
+ srcs = [
+ "xds/grpc/xds_common_types.cc",
+ ],
+ hdrs = [
+ "xds/grpc/xds_common_types.h",
+ ],
+ external_deps = [
+ "absl/strings",
+ "absl/strings:str_format",
+ "absl/types:variant",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ deps = [
+ "grpc_matchers",
+ "json",
+ "validation_errors",
+ ],
+)
+
+grpc_cc_library(
+ name = "xds_http_filter",
+ hdrs = [
+ "xds/grpc/xds_http_filter.h",
+ ],
+ external_deps = [
+ "absl/status:statusor",
+ "absl/strings",
+ "absl/types:optional",
+ "@com_google_protobuf//upb:reflection",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ deps = [
+ "channel_args",
+ "channel_fwd",
+ "interception_chain",
+ "json",
+ "json_writer",
+ "validation_errors",
+ "xds_common_types",
+ "//:xds_client",
+ ],
+)
+
+grpc_cc_library(
+ name = "xds_route_config",
+ srcs = [
+ "xds/grpc/xds_route_config.cc",
+ ],
+ hdrs = [
+ "xds/grpc/xds_route_config.h",
+ ],
+ external_deps = [
+ "absl/strings",
+ "absl/strings:str_format",
+ "absl/types:optional",
+ "absl/types:variant",
+ "re2",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ deps = [
+ "grpc_matchers",
+ "match",
+ "time",
+ "xds_http_filter",
+ "//:grpc_base",
+ "//:xds_client",
+ ],
+)
+
+grpc_cc_library(
+ name = "xds_listener",
+ srcs = [
+ "xds/grpc/xds_listener.cc",
+ ],
+ hdrs = [
+ "xds/grpc/xds_listener.h",
+ ],
+ external_deps = [
+ "absl/strings",
+ "absl/strings:str_format",
+ "absl/types:optional",
+ "absl/types:variant",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ deps = [
+ "match",
+ "resolved_address",
+ "time",
+ "xds_common_types",
+ "xds_http_filter",
+ "xds_route_config",
+ "//:sockaddr_utils",
+ "//:xds_client",
+ ],
+)
+
+grpc_cc_library(
+ name = "xds_health_status",
+ srcs = [
+ "xds/grpc/xds_health_status.cc",
+ ],
+ hdrs = [
+ "xds/grpc/xds_health_status.h",
+ ],
+ external_deps = [
+ "absl/strings",
+ "absl/types:optional",
+ "absl/types:span",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ deps = [
+ "envoy_config_core_upb",
+ "//:endpoint_addresses",
+ ],
+)
+
+grpc_cc_library(
+ name = "xds_server_grpc",
+ srcs = [
+ "xds/grpc/xds_server_grpc.cc",
+ ],
+ hdrs = [
+ "xds/grpc/xds_server_grpc.h",
+ ],
+ external_deps = [
+ "absl/strings",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ deps = [
+ "channel_creds_registry",
+ "json",
+ "json_args",
+ "json_object_loader",
+ "json_reader",
+ "json_writer",
+ "validation_errors",
+ "//:config",
+ "//:ref_counted_ptr",
+ "//:xds_client",
+ ],
+)
+
+grpc_cc_library(
+ name = "xds_cluster",
+ srcs = [
+ "xds/grpc/xds_cluster.cc",
+ ],
+ hdrs = [
+ "xds/grpc/xds_cluster.h",
+ ],
+ external_deps = [
+ "absl/strings",
+ "absl/types:optional",
+ "absl/types:variant",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ deps = [
+ "grpc_outlier_detection_header",
+ "json",
+ "json_writer",
+ "match",
+ "time",
+ "xds_common_types",
+ "xds_health_status",
+ "xds_server_grpc",
+ "//:xds_client",
+ ],
+)
+
+grpc_cc_library(
+ name = "xds_endpoint",
+ srcs = [
+ "xds/grpc/xds_endpoint.cc",
+ ],
+ hdrs = [
+ "xds/grpc/xds_endpoint.h",
+ ],
+ external_deps = [
+ "absl/base:core_headers",
+ "absl/random",
+ "absl/strings",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ deps = [
+ "ref_counted",
+ "//:endpoint_addresses",
+ "//:gpr",
+ "//:ref_counted_ptr",
+ "//:xds_client",
+ ],
+)
+
+# TODO(roth): Split this up into individual targets.
grpc_cc_library(
name = "grpc_xds_client",
srcs = [
"xds/grpc/xds_audit_logger_registry.cc",
"xds/grpc/xds_bootstrap_grpc.cc",
"xds/grpc/xds_client_grpc.cc",
- "xds/grpc/xds_cluster.cc",
+ "xds/grpc/xds_cluster_parser.cc",
"xds/grpc/xds_cluster_specifier_plugin.cc",
- "xds/grpc/xds_common_types.cc",
- "xds/grpc/xds_endpoint.cc",
- "xds/grpc/xds_health_status.cc",
+ "xds/grpc/xds_common_types_parser.cc",
+ "xds/grpc/xds_endpoint_parser.cc",
"xds/grpc/xds_http_fault_filter.cc",
- "xds/grpc/xds_http_filters.cc",
+ "xds/grpc/xds_http_filter_registry.cc",
"xds/grpc/xds_http_rbac_filter.cc",
"xds/grpc/xds_http_stateful_session_filter.cc",
"xds/grpc/xds_lb_policy_registry.cc",
- "xds/grpc/xds_listener.cc",
- "xds/grpc/xds_route_config.cc",
+ "xds/grpc/xds_listener_parser.cc",
+ "xds/grpc/xds_route_config_parser.cc",
"xds/grpc/xds_routing.cc",
"xds/grpc/xds_transport_grpc.cc",
],
@@ -5254,18 +5456,17 @@ grpc_cc_library(
"xds/grpc/xds_audit_logger_registry.h",
"xds/grpc/xds_bootstrap_grpc.h",
"xds/grpc/xds_client_grpc.h",
- "xds/grpc/xds_cluster.h",
+ "xds/grpc/xds_cluster_parser.h",
"xds/grpc/xds_cluster_specifier_plugin.h",
- "xds/grpc/xds_common_types.h",
- "xds/grpc/xds_endpoint.h",
- "xds/grpc/xds_health_status.h",
+ "xds/grpc/xds_common_types_parser.h",
+ "xds/grpc/xds_endpoint_parser.h",
"xds/grpc/xds_http_fault_filter.h",
- "xds/grpc/xds_http_filters.h",
+ "xds/grpc/xds_http_filter_registry.h",
"xds/grpc/xds_http_rbac_filter.h",
"xds/grpc/xds_http_stateful_session_filter.h",
"xds/grpc/xds_lb_policy_registry.h",
- "xds/grpc/xds_listener.h",
- "xds/grpc/xds_route_config.h",
+ "xds/grpc/xds_listener_parser.h",
+ "xds/grpc/xds_route_config_parser.h",
"xds/grpc/xds_routing.h",
"xds/grpc/xds_transport_grpc.h",
],
@@ -5400,8 +5601,16 @@ grpc_cc_library(
"validation_errors",
"xds_certificate_provider",
"xds_certificate_provider_store",
+ "xds_cluster",
+ "xds_common_types",
"xds_credentials",
+ "xds_endpoint",
"xds_file_watcher_certificate_provider_factory",
+ "xds_health_status",
+ "xds_http_filter",
+ "xds_listener",
+ "xds_route_config",
+ "xds_server_grpc",
"xds_type_upb",
"xds_type_upbdefs",
"//:channel",
@@ -5492,7 +5701,11 @@ grpc_cc_library(
"unique_type_name",
"xds_certificate_provider",
"xds_certificate_provider_store",
+ "xds_common_types",
"xds_credentials",
+ "xds_http_filter",
+ "xds_listener",
+ "xds_route_config",
"//:api_trace",
"//:config",
"//:debug_location",
@@ -5574,7 +5787,10 @@ grpc_cc_library(
"pollset_set",
"time",
"unique_type_name",
+ "xds_cluster",
+ "xds_common_types",
"xds_dependency_manager",
+ "xds_health_status",
"//:config",
"//:debug_location",
"//:gpr",
@@ -5639,6 +5855,7 @@ grpc_cc_library(
"validation_errors",
"xds_credentials",
"xds_dependency_manager",
+ "xds_endpoint",
"//:call_tracer",
"//:config",
"//:debug_location",
@@ -6350,6 +6567,7 @@ grpc_cc_library(
"subchannel_interface",
"validation_errors",
"xds_dependency_manager",
+ "xds_health_status",
"//:config",
"//:debug_location",
"//:endpoint_addresses",
@@ -6713,6 +6931,10 @@ grpc_cc_library(
"grpc_xds_client",
"match",
"ref_counted",
+ "xds_cluster",
+ "xds_endpoint",
+ "xds_listener",
+ "xds_route_config",
"//:config",
"//:gpr",
"//:grpc_resolver",
@@ -6761,6 +6983,9 @@ grpc_cc_library(
"slice",
"time",
"xds_dependency_manager",
+ "xds_http_filter",
+ "xds_listener",
+ "xds_route_config",
"xxhash_inline",
"//:channel_arg_names",
"//:config",
diff --git a/src/core/resolver/xds/xds_dependency_manager.cc b/src/core/resolver/xds/xds_dependency_manager.cc
index 0197984143a..61bc5418ac2 100644
--- a/src/core/resolver/xds/xds_dependency_manager.cc
+++ b/src/core/resolver/xds/xds_dependency_manager.cc
@@ -28,6 +28,10 @@
#include "src/core/lib/gprpp/match.h"
#include "src/core/load_balancing/xds/xds_channel_args.h"
#include "src/core/resolver/fake/fake_resolver.h"
+#include "src/core/xds/grpc/xds_cluster_parser.h"
+#include "src/core/xds/grpc/xds_endpoint_parser.h"
+#include "src/core/xds/grpc/xds_listener_parser.h"
+#include "src/core/xds/grpc/xds_route_config_parser.h"
#include "src/core/xds/grpc/xds_routing.h"
namespace grpc_core {
diff --git a/src/core/resolver/xds/xds_resolver.cc b/src/core/resolver/xds/xds_resolver.cc
index a91708c67f4..4933d5f1954 100644
--- a/src/core/resolver/xds/xds_resolver.cc
+++ b/src/core/resolver/xds/xds_resolver.cc
@@ -86,7 +86,7 @@
#include "src/core/service_config/service_config_impl.h"
#include "src/core/xds/grpc/xds_bootstrap_grpc.h"
#include "src/core/xds/grpc/xds_client_grpc.h"
-#include "src/core/xds/grpc/xds_http_filters.h"
+#include "src/core/xds/grpc/xds_http_filter.h"
#include "src/core/xds/grpc/xds_listener.h"
#include "src/core/xds/grpc/xds_route_config.h"
#include "src/core/xds/grpc/xds_routing.h"
diff --git a/src/core/server/xds_server_config_fetcher.cc b/src/core/server/xds_server_config_fetcher.cc
index ddf2273176b..1366b0702fa 100644
--- a/src/core/server/xds_server_config_fetcher.cc
+++ b/src/core/server/xds_server_config_fetcher.cc
@@ -84,9 +84,12 @@
#include "src/core/xds/grpc/xds_certificate_provider.h"
#include "src/core/xds/grpc/xds_client_grpc.h"
#include "src/core/xds/grpc/xds_common_types.h"
-#include "src/core/xds/grpc/xds_http_filters.h"
+#include "src/core/xds/grpc/xds_http_filter.h"
+#include "src/core/xds/grpc/xds_http_filter_registry.h"
#include "src/core/xds/grpc/xds_listener.h"
+#include "src/core/xds/grpc/xds_listener_parser.h"
#include "src/core/xds/grpc/xds_route_config.h"
+#include "src/core/xds/grpc/xds_route_config_parser.h"
#include "src/core/xds/grpc/xds_routing.h"
#include "src/core/xds/xds_client/xds_client.h"
diff --git a/src/core/xds/grpc/xds_audit_logger_registry.cc b/src/core/xds/grpc/xds_audit_logger_registry.cc
index 328849808ce..7ec3a98edf1 100644
--- a/src/core/xds/grpc/xds_audit_logger_registry.cc
+++ b/src/core/xds/grpc/xds_audit_logger_registry.cc
@@ -32,6 +32,7 @@
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/security/authorization/audit_logging.h"
#include "src/core/xds/grpc/xds_common_types.h"
+#include "src/core/xds/grpc/xds_common_types_parser.h"
namespace grpc_core {
diff --git a/src/core/xds/grpc/xds_bootstrap_grpc.cc b/src/core/xds/grpc/xds_bootstrap_grpc.cc
index 9ab26b38238..58b958cb994 100644
--- a/src/core/xds/grpc/xds_bootstrap_grpc.cc
+++ b/src/core/xds/grpc/xds_bootstrap_grpc.cc
@@ -90,131 +90,6 @@ const JsonLoaderInterface* GrpcXdsBootstrap::GrpcNode::JsonLoader(
return loader;
}
-//
-// GrpcXdsBootstrap::GrpcXdsServer
-//
-
-namespace {
-
-constexpr absl::string_view kServerFeatureIgnoreResourceDeletion =
- "ignore_resource_deletion";
-
-} // namespace
-
-bool GrpcXdsBootstrap::GrpcXdsServer::IgnoreResourceDeletion() const {
- return server_features_.find(std::string(
- kServerFeatureIgnoreResourceDeletion)) != server_features_.end();
-}
-
-bool GrpcXdsBootstrap::GrpcXdsServer::Equals(const XdsServer& other) const {
- const auto& o = static_cast(other);
- return (server_uri_ == o.server_uri_ &&
- channel_creds_config_->type() == o.channel_creds_config_->type() &&
- channel_creds_config_->Equals(*o.channel_creds_config_) &&
- server_features_ == o.server_features_);
-}
-
-std::string GrpcXdsBootstrap::GrpcXdsServer::Key() const {
- return JsonDump(ToJson());
-}
-
-const JsonLoaderInterface* GrpcXdsBootstrap::GrpcXdsServer::JsonLoader(
- const JsonArgs&) {
- static const auto* loader =
- JsonObjectLoader()
- .Field("server_uri", &GrpcXdsServer::server_uri_)
- .Finish();
- return loader;
-}
-
-namespace {
-
-struct ChannelCreds {
- std::string type;
- Json::Object config;
-
- static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
- static const auto* loader =
- JsonObjectLoader()
- .Field("type", &ChannelCreds::type)
- .OptionalField("config", &ChannelCreds::config)
- .Finish();
- return loader;
- }
-};
-
-} // namespace
-
-void GrpcXdsBootstrap::GrpcXdsServer::JsonPostLoad(const Json& json,
- const JsonArgs& args,
- ValidationErrors* errors) {
- // Parse "channel_creds".
- auto channel_creds_list = LoadJsonObjectField>(
- json.object(), args, "channel_creds", errors);
- if (channel_creds_list.has_value()) {
- ValidationErrors::ScopedField field(errors, ".channel_creds");
- for (size_t i = 0; i < channel_creds_list->size(); ++i) {
- ValidationErrors::ScopedField field(errors, absl::StrCat("[", i, "]"));
- auto& creds = (*channel_creds_list)[i];
- // Select the first channel creds type that we support, but
- // validate all entries.
- if (CoreConfiguration::Get().channel_creds_registry().IsSupported(
- creds.type)) {
- ValidationErrors::ScopedField field(errors, ".config");
- auto config =
- CoreConfiguration::Get().channel_creds_registry().ParseConfig(
- creds.type, Json::FromObject(creds.config), args, errors);
- if (channel_creds_config_ == nullptr) {
- channel_creds_config_ = std::move(config);
- }
- }
- }
- if (channel_creds_config_ == nullptr) {
- errors->AddError("no known creds type found");
- }
- }
- // Parse "server_features".
- {
- ValidationErrors::ScopedField field(errors, ".server_features");
- auto it = json.object().find("server_features");
- if (it != json.object().end()) {
- if (it->second.type() != Json::Type::kArray) {
- errors->AddError("is not an array");
- } else {
- const Json::Array& array = it->second.array();
- for (const Json& feature_json : array) {
- if (feature_json.type() == Json::Type::kString &&
- (feature_json.string() == kServerFeatureIgnoreResourceDeletion)) {
- server_features_.insert(feature_json.string());
- }
- }
- }
- }
- }
-}
-
-Json GrpcXdsBootstrap::GrpcXdsServer::ToJson() const {
- Json::Object channel_creds_json{
- {"type", Json::FromString(std::string(channel_creds_config_->type()))},
- };
- if (channel_creds_config_ != nullptr) {
- channel_creds_json["config"] = channel_creds_config_->ToJson();
- }
- Json::Object json{
- {"server_uri", Json::FromString(server_uri_)},
- {"channel_creds",
- Json::FromArray({Json::FromObject(std::move(channel_creds_json))})},
- };
- if (!server_features_.empty()) {
- Json::Array server_features_json;
- for (auto& feature : server_features_) {
- server_features_json.emplace_back(Json::FromString(feature));
- }
- json["server_features"] = Json::FromArray(std::move(server_features_json));
- }
- return Json::FromObject(std::move(json));
-}
-
//
// GrpcXdsBootstrap::GrpcAuthority
//
diff --git a/src/core/xds/grpc/xds_bootstrap_grpc.h b/src/core/xds/grpc/xds_bootstrap_grpc.h
index 00c08f9e2e2..a21f0017aa2 100644
--- a/src/core/xds/grpc/xds_bootstrap_grpc.h
+++ b/src/core/xds/grpc/xds_bootstrap_grpc.h
@@ -38,8 +38,9 @@
#include "src/core/xds/grpc/certificate_provider_store.h"
#include "src/core/xds/grpc/xds_audit_logger_registry.h"
#include "src/core/xds/grpc/xds_cluster_specifier_plugin.h"
-#include "src/core/xds/grpc/xds_http_filters.h"
+#include "src/core/xds/grpc/xds_http_filter_registry.h"
#include "src/core/xds/grpc/xds_lb_policy_registry.h"
+#include "src/core/xds/grpc/xds_server_grpc.h"
#include "src/core/xds/xds_client/xds_bootstrap.h"
namespace grpc_core {
@@ -76,32 +77,6 @@ class GrpcXdsBootstrap final : public XdsBootstrap {
Json::Object metadata_;
};
- class GrpcXdsServer final : public XdsServer {
- public:
- const std::string& server_uri() const override { return server_uri_; }
-
- bool IgnoreResourceDeletion() const override;
-
- bool Equals(const XdsServer& other) const override;
-
- std::string Key() const override;
-
- RefCountedPtr channel_creds_config() const {
- return channel_creds_config_;
- }
-
- static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
- void JsonPostLoad(const Json& json, const JsonArgs& args,
- ValidationErrors* errors);
-
- Json ToJson() const;
-
- private:
- std::string server_uri_;
- RefCountedPtr channel_creds_config_;
- std::set server_features_;
- };
-
class GrpcAuthority final : public Authority {
public:
std::vector servers() const override {
diff --git a/src/core/xds/grpc/xds_cluster.cc b/src/core/xds/grpc/xds_cluster.cc
index 7b232fa0ef8..300528f5a16 100644
--- a/src/core/xds/grpc/xds_cluster.cc
+++ b/src/core/xds/grpc/xds_cluster.cc
@@ -16,68 +16,16 @@
#include "src/core/xds/grpc/xds_cluster.h"
-#include
-
-#include
-#include
-#include
-
-#include "absl/log/check.h"
-#include "absl/log/log.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
-#include "absl/strings/strip.h"
-#include "absl/types/variant.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/cluster/v3/outlier_detection.upb.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/core/v3/extension.upb.h"
-#include "envoy/config/core/v3/health_check.upb.h"
-#include "envoy/config/core/v3/protocol.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 "envoy/extensions/transport_sockets/tls/v3/tls.upb.h"
-#include "envoy/extensions/upstreams/http/v3/http_protocol_options.upb.h"
-#include "google/protobuf/any.upb.h"
-#include "google/protobuf/duration.upb.h"
-#include "google/protobuf/struct.upb.h"
-#include "google/protobuf/wrappers.upb.h"
-#include "upb/base/string_view.h"
-#include "upb/text/encode.h"
-
-#include
-#include
-#include "src/core/lib/config/core_configuration.h"
-#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/gprpp/match.h"
-#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h"
-#include "src/core/lib/gprpp/validation_errors.h"
-#include "src/core/lib/matchers/matchers.h"
-#include "src/core/load_balancing/lb_policy_registry.h"
#include "src/core/util/json/json_writer.h"
-#include "src/core/util/upb_utils.h"
#include "src/core/xds/grpc/xds_common_types.h"
-#include "src/core/xds/grpc/xds_lb_policy_registry.h"
-#include "src/core/xds/xds_client/xds_client.h"
-#include "src/core/xds/xds_client/xds_resource_type.h"
namespace grpc_core {
-//
-// XdsClusterResource
-//
-
std::string XdsClusterResource::ToString() const {
std::vector contents;
Match(
@@ -129,674 +77,4 @@ std::string XdsClusterResource::ToString() const {
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
-//
-// XdsClusterResourceType
-//
-
-namespace {
-
-CommonTlsContext UpstreamTlsContextParse(
- const XdsResourceType::DecodeContext& context,
- const envoy_config_core_v3_TransportSocket* transport_socket,
- ValidationErrors* errors) {
- ValidationErrors::ScopedField field(errors, ".typed_config");
- const auto* typed_config =
- envoy_config_core_v3_TransportSocket_typed_config(transport_socket);
- auto extension = ExtractXdsExtension(context, typed_config, errors);
- if (!extension.has_value()) return {};
- if (extension->type !=
- "envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext") {
- ValidationErrors::ScopedField field(errors, ".type_url");
- errors->AddError("unsupported transport socket type");
- return {};
- }
- absl::string_view* serialized_upstream_tls_context =
- absl::get_if(&extension->value);
- if (serialized_upstream_tls_context == nullptr) {
- errors->AddError("can't decode UpstreamTlsContext");
- return {};
- }
- const auto* upstream_tls_context =
- envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_parse(
- serialized_upstream_tls_context->data(),
- serialized_upstream_tls_context->size(), context.arena);
- if (upstream_tls_context == nullptr) {
- errors->AddError("can't decode UpstreamTlsContext");
- return {};
- }
- ValidationErrors::ScopedField field3(errors, ".common_tls_context");
- const auto* common_tls_context_proto =
- envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_common_tls_context(
- upstream_tls_context);
- CommonTlsContext common_tls_context;
- if (common_tls_context_proto != nullptr) {
- common_tls_context =
- CommonTlsContext::Parse(context, common_tls_context_proto, errors);
- }
- if (common_tls_context.certificate_validation_context
- .ca_certificate_provider_instance.instance_name.empty()) {
- errors->AddError("no CA certificate provider instance configured");
- }
- return common_tls_context;
-}
-
-XdsClusterResource::Eds EdsConfigParse(
- const envoy_config_cluster_v3_Cluster* cluster, ValidationErrors* errors) {
- XdsClusterResource::Eds eds;
- ValidationErrors::ScopedField field(errors, ".eds_cluster_config");
- const envoy_config_cluster_v3_Cluster_EdsClusterConfig* eds_cluster_config =
- envoy_config_cluster_v3_Cluster_eds_cluster_config(cluster);
- if (eds_cluster_config == nullptr) {
- errors->AddError("field not present");
- } else {
- // Validate ConfigSource.
- {
- ValidationErrors::ScopedField field(errors, ".eds_config");
- const envoy_config_core_v3_ConfigSource* eds_config =
- envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_config(
- eds_cluster_config);
- if (eds_config == nullptr) {
- errors->AddError("field not present");
- } else {
- if (!envoy_config_core_v3_ConfigSource_has_ads(eds_config) &&
- !envoy_config_core_v3_ConfigSource_has_self(eds_config)) {
- errors->AddError("ConfigSource is not ads or self");
- }
- }
- }
- // Record EDS service_name (if any).
- // This field is required if the CDS resource has an xdstp name.
- eds.eds_service_name = UpbStringToStdString(
- envoy_config_cluster_v3_Cluster_EdsClusterConfig_service_name(
- eds_cluster_config));
- if (eds.eds_service_name.empty()) {
- absl::string_view cluster_name =
- UpbStringToAbsl(envoy_config_cluster_v3_Cluster_name(cluster));
- if (absl::StartsWith(cluster_name, "xdstp:")) {
- ValidationErrors::ScopedField field(errors, ".service_name");
- errors->AddError("must be set if Cluster resource has an xdstp name");
- }
- }
- }
- return eds;
-}
-
-XdsClusterResource::LogicalDns LogicalDnsParse(
- const envoy_config_cluster_v3_Cluster* cluster, ValidationErrors* errors) {
- XdsClusterResource::LogicalDns logical_dns;
- ValidationErrors::ScopedField field(errors, ".load_assignment");
- const auto* load_assignment =
- envoy_config_cluster_v3_Cluster_load_assignment(cluster);
- if (load_assignment == nullptr) {
- errors->AddError("field not present for LOGICAL_DNS cluster");
- return logical_dns;
- }
- ValidationErrors::ScopedField field2(errors, ".endpoints");
- size_t num_localities;
- const auto* const* localities =
- envoy_config_endpoint_v3_ClusterLoadAssignment_endpoints(load_assignment,
- &num_localities);
- if (num_localities != 1) {
- errors->AddError(absl::StrCat(
- "must contain exactly one locality for LOGICAL_DNS cluster, found ",
- num_localities));
- return logical_dns;
- }
- ValidationErrors::ScopedField field3(errors, "[0].lb_endpoints");
- size_t num_endpoints;
- const auto* const* endpoints =
- envoy_config_endpoint_v3_LocalityLbEndpoints_lb_endpoints(localities[0],
- &num_endpoints);
- if (num_endpoints != 1) {
- errors->AddError(absl::StrCat(
- "must contain exactly one endpoint for LOGICAL_DNS cluster, found ",
- num_endpoints));
- return logical_dns;
- }
- ValidationErrors::ScopedField field4(errors, "[0].endpoint");
- const auto* endpoint =
- envoy_config_endpoint_v3_LbEndpoint_endpoint(endpoints[0]);
- if (endpoint == nullptr) {
- errors->AddError("field not present");
- return logical_dns;
- }
- ValidationErrors::ScopedField field5(errors, ".address");
- const auto* address = envoy_config_endpoint_v3_Endpoint_address(endpoint);
- if (address == nullptr) {
- errors->AddError("field not present");
- return logical_dns;
- }
- ValidationErrors::ScopedField field6(errors, ".socket_address");
- const auto* socket_address =
- envoy_config_core_v3_Address_socket_address(address);
- if (socket_address == nullptr) {
- errors->AddError("field not present");
- return logical_dns;
- }
- if (envoy_config_core_v3_SocketAddress_resolver_name(socket_address).size !=
- 0) {
- ValidationErrors::ScopedField field(errors, ".resolver_name");
- errors->AddError(
- "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()) {
- ValidationErrors::ScopedField field(errors, ".address");
- errors->AddError("field not present");
- }
- if (!envoy_config_core_v3_SocketAddress_has_port_value(socket_address)) {
- ValidationErrors::ScopedField field(errors, ".port_value");
- errors->AddError("field not present");
- }
- logical_dns.hostname = JoinHostPort(
- address_str,
- envoy_config_core_v3_SocketAddress_port_value(socket_address));
- return logical_dns;
-}
-
-XdsClusterResource::Aggregate AggregateClusterParse(
- const XdsResourceType::DecodeContext& context,
- absl::string_view serialized_config, ValidationErrors* errors) {
- XdsClusterResource::Aggregate aggregate;
- const auto* aggregate_cluster_config =
- envoy_extensions_clusters_aggregate_v3_ClusterConfig_parse(
- serialized_config.data(), serialized_config.size(), context.arena);
- if (aggregate_cluster_config == nullptr) {
- errors->AddError("can't parse aggregate cluster config");
- return aggregate;
- }
- size_t size;
- const upb_StringView* clusters =
- envoy_extensions_clusters_aggregate_v3_ClusterConfig_clusters(
- aggregate_cluster_config, &size);
- if (size == 0) {
- ValidationErrors::ScopedField field(errors, ".clusters");
- errors->AddError("must be non-empty");
- }
- for (size_t i = 0; i < size; ++i) {
- aggregate.prioritized_cluster_names.emplace_back(
- UpbStringToStdString(clusters[i]));
- }
- return aggregate;
-}
-
-void ParseLbPolicyConfig(const XdsResourceType::DecodeContext& context,
- const envoy_config_cluster_v3_Cluster* cluster,
- XdsClusterResource* cds_update,
- ValidationErrors* errors) {
- // First, check the new load_balancing_policy field.
- const auto* load_balancing_policy =
- envoy_config_cluster_v3_Cluster_load_balancing_policy(cluster);
- if (load_balancing_policy != nullptr) {
- const auto& registry =
- static_cast(context.client->bootstrap())
- .lb_policy_registry();
- ValidationErrors::ScopedField field(errors, ".load_balancing_policy");
- const size_t original_error_count = errors->size();
- cds_update->lb_policy_config = registry.ConvertXdsLbPolicyConfig(
- context, load_balancing_policy, errors);
- // If there were no conversion errors, validate that the converted config
- // parses with the gRPC LB policy registry.
- if (original_error_count == errors->size()) {
- auto config = CoreConfiguration::Get()
- .lb_policy_registry()
- .ParseLoadBalancingConfig(
- Json::FromArray(cds_update->lb_policy_config));
- if (!config.ok()) errors->AddError(config.status().message());
- }
- return;
- }
- // Didn't find load_balancing_policy field, so fall back to the old
- // lb_policy enum field.
- if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
- envoy_config_cluster_v3_Cluster_ROUND_ROBIN) {
- cds_update->lb_policy_config = {
- Json::FromObject({
- {"xds_wrr_locality_experimental",
- Json::FromObject({
- {"childPolicy", Json::FromArray({
- Json::FromObject({
- {"round_robin", Json::FromObject({})},
- }),
- })},
- })},
- }),
- };
- } else if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
- envoy_config_cluster_v3_Cluster_RING_HASH) {
- // Record ring hash lb config
- auto* ring_hash_config =
- envoy_config_cluster_v3_Cluster_ring_hash_lb_config(cluster);
- uint64_t min_ring_size = 1024;
- uint64_t max_ring_size = 8388608;
- if (ring_hash_config != nullptr) {
- ValidationErrors::ScopedField field(errors, ".ring_hash_lb_config");
- const google_protobuf_UInt64Value* uint64_value =
- envoy_config_cluster_v3_Cluster_RingHashLbConfig_maximum_ring_size(
- ring_hash_config);
- if (uint64_value != nullptr) {
- ValidationErrors::ScopedField field(errors, ".maximum_ring_size");
- max_ring_size = google_protobuf_UInt64Value_value(uint64_value);
- if (max_ring_size > 8388608 || max_ring_size == 0) {
- errors->AddError("must be in the range of 1 to 8388608");
- }
- }
- uint64_value =
- envoy_config_cluster_v3_Cluster_RingHashLbConfig_minimum_ring_size(
- ring_hash_config);
- if (uint64_value != nullptr) {
- ValidationErrors::ScopedField field(errors, ".minimum_ring_size");
- min_ring_size = google_protobuf_UInt64Value_value(uint64_value);
- if (min_ring_size > 8388608 || min_ring_size == 0) {
- errors->AddError("must be in the range of 1 to 8388608");
- }
- if (min_ring_size > max_ring_size) {
- errors->AddError("cannot be greater than maximum_ring_size");
- }
- }
- if (envoy_config_cluster_v3_Cluster_RingHashLbConfig_hash_function(
- ring_hash_config) !=
- envoy_config_cluster_v3_Cluster_RingHashLbConfig_XX_HASH) {
- ValidationErrors::ScopedField field(errors, ".hash_function");
- errors->AddError("invalid hash function");
- }
- }
- cds_update->lb_policy_config = {
- Json::FromObject({
- {"ring_hash_experimental",
- Json::FromObject({
- {"minRingSize", Json::FromNumber(min_ring_size)},
- {"maxRingSize", Json::FromNumber(max_ring_size)},
- })},
- }),
- };
- } else {
- ValidationErrors::ScopedField field(errors, ".lb_policy");
- errors->AddError("LB policy is not supported");
- }
-}
-
-void ParseUpstreamConfig(
- const XdsResourceType::DecodeContext& context,
- const envoy_config_core_v3_TypedExtensionConfig* upstream_config,
- XdsClusterResource* cds_update, ValidationErrors* errors) {
- ValidationErrors::ScopedField field(errors, ".typed_config");
- const auto* typed_config =
- envoy_config_core_v3_TypedExtensionConfig_typed_config(upstream_config);
- auto extension = ExtractXdsExtension(context, typed_config, errors);
- if (!extension.has_value()) return;
- if (extension->type !=
- "envoy.extensions.upstreams.http.v3.HttpProtocolOptions") {
- ValidationErrors::ScopedField field(errors, ".type_url");
- errors->AddError("unsupported upstream config type");
- return;
- }
- absl::string_view* serialized_http_protocol_options =
- absl::get_if(&extension->value);
- if (serialized_http_protocol_options == nullptr) {
- errors->AddError("can't decode HttpProtocolOptions");
- return;
- }
- const auto* http_protocol_options =
- envoy_extensions_upstreams_http_v3_HttpProtocolOptions_parse(
- serialized_http_protocol_options->data(),
- serialized_http_protocol_options->size(), context.arena);
- if (http_protocol_options == nullptr) {
- errors->AddError("can't decode HttpProtocolOptions");
- return;
- }
- ValidationErrors::ScopedField field2(errors, ".common_http_protocol_options");
- const auto* common_http_protocol_options =
- envoy_extensions_upstreams_http_v3_HttpProtocolOptions_common_http_protocol_options(
- http_protocol_options);
- if (common_http_protocol_options != nullptr) {
- const auto* idle_timeout =
- envoy_config_core_v3_HttpProtocolOptions_idle_timeout(
- common_http_protocol_options);
- if (idle_timeout != nullptr) {
- ValidationErrors::ScopedField field(errors, ".idle_timeout");
- cds_update->connection_idle_timeout = ParseDuration(idle_timeout, errors);
- }
- }
-}
-
-absl::StatusOr> CdsResourceParse(
- const XdsResourceType::DecodeContext& context,
- const envoy_config_cluster_v3_Cluster* cluster) {
- auto cds_update = std::make_shared();
- ValidationErrors errors;
- // Check the cluster discovery type.
- if (envoy_config_cluster_v3_Cluster_type(cluster) ==
- envoy_config_cluster_v3_Cluster_EDS) {
- cds_update->type = EdsConfigParse(cluster, &errors);
- } else if (envoy_config_cluster_v3_Cluster_type(cluster) ==
- envoy_config_cluster_v3_Cluster_LOGICAL_DNS) {
- cds_update->type = LogicalDnsParse(cluster, &errors);
- } else if (envoy_config_cluster_v3_Cluster_has_cluster_type(cluster)) {
- ValidationErrors::ScopedField field(&errors, ".cluster_type");
- const auto* custom_cluster_type =
- envoy_config_cluster_v3_Cluster_cluster_type(cluster);
- CHECK_NE(custom_cluster_type, nullptr);
- ValidationErrors::ScopedField field2(&errors, ".typed_config");
- const auto* typed_config =
- envoy_config_cluster_v3_Cluster_CustomClusterType_typed_config(
- custom_cluster_type);
- if (typed_config == nullptr) {
- errors.AddError("field not present");
- } else {
- absl::string_view type_url = absl::StripPrefix(
- UpbStringToAbsl(google_protobuf_Any_type_url(typed_config)),
- "type.googleapis.com/");
- if (type_url != "envoy.extensions.clusters.aggregate.v3.ClusterConfig") {
- ValidationErrors::ScopedField field(&errors, ".type_url");
- errors.AddError(
- absl::StrCat("unknown cluster_type extension: ", type_url));
- } else {
- // Retrieve aggregate clusters.
- ValidationErrors::ScopedField field(
- &errors,
- ".value[envoy.extensions.clusters.aggregate.v3.ClusterConfig]");
- absl::string_view serialized_config =
- UpbStringToAbsl(google_protobuf_Any_value(typed_config));
- cds_update->type =
- AggregateClusterParse(context, serialized_config, &errors);
- }
- }
- } else {
- ValidationErrors::ScopedField field(&errors, ".type");
- errors.AddError("unknown discovery type");
- }
- // Check the LB policy.
- ParseLbPolicyConfig(context, cluster, cds_update.get(), &errors);
- // transport_socket
- auto* transport_socket =
- envoy_config_cluster_v3_Cluster_transport_socket(cluster);
- if (transport_socket != nullptr) {
- ValidationErrors::ScopedField field(&errors, ".transport_socket");
- cds_update->common_tls_context =
- UpstreamTlsContextParse(context, transport_socket, &errors);
- }
- // 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)) {
- ValidationErrors::ScopedField field(&errors, ".lrs_server");
- errors.AddError("ConfigSource is not self");
- }
- cds_update->lrs_load_reporting_server.emplace(
- static_cast(context.server));
- }
- // Protocol options.
- auto* upstream_config =
- envoy_config_cluster_v3_Cluster_upstream_config(cluster);
- if (upstream_config != nullptr) {
- ValidationErrors::ScopedField field(&errors, ".upstream_config");
- ParseUpstreamConfig(context, upstream_config, cds_update.get(), &errors);
- }
- // 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;
- }
- }
- }
- // Outlier detection config.
- if (envoy_config_cluster_v3_Cluster_has_outlier_detection(cluster)) {
- ValidationErrors::ScopedField field(&errors, ".outlier_detection");
- OutlierDetectionConfig outlier_detection_update;
- const envoy_config_cluster_v3_OutlierDetection* outlier_detection =
- envoy_config_cluster_v3_Cluster_outlier_detection(cluster);
- const google_protobuf_Duration* duration =
- envoy_config_cluster_v3_OutlierDetection_interval(outlier_detection);
- if (duration != nullptr) {
- ValidationErrors::ScopedField field(&errors, ".interval");
- outlier_detection_update.interval = ParseDuration(duration, &errors);
- }
- duration = envoy_config_cluster_v3_OutlierDetection_base_ejection_time(
- outlier_detection);
- if (duration != nullptr) {
- ValidationErrors::ScopedField field(&errors, ".base_ejection_time");
- outlier_detection_update.base_ejection_time =
- ParseDuration(duration, &errors);
- }
- duration = envoy_config_cluster_v3_OutlierDetection_max_ejection_time(
- outlier_detection);
- if (duration != nullptr) {
- ValidationErrors::ScopedField field(&errors, ".max_ejection_time");
- outlier_detection_update.max_ejection_time =
- ParseDuration(duration, &errors);
- }
- const google_protobuf_UInt32Value* max_ejection_percent =
- envoy_config_cluster_v3_OutlierDetection_max_ejection_percent(
- outlier_detection);
- if (max_ejection_percent != nullptr) {
- outlier_detection_update.max_ejection_percent =
- google_protobuf_UInt32Value_value(max_ejection_percent);
- if (outlier_detection_update.max_ejection_percent > 100) {
- ValidationErrors::ScopedField field(&errors, ".max_ejection_percent");
- errors.AddError("value must be <= 100");
- }
- }
- const google_protobuf_UInt32Value* enforcing_success_rate =
- envoy_config_cluster_v3_OutlierDetection_enforcing_success_rate(
- outlier_detection);
- if (enforcing_success_rate != nullptr) {
- uint32_t enforcement_percentage =
- google_protobuf_UInt32Value_value(enforcing_success_rate);
- if (enforcement_percentage > 100) {
- ValidationErrors::ScopedField field(&errors, ".enforcing_success_rate");
- errors.AddError("value must be <= 100");
- }
- if (enforcement_percentage != 0) {
- OutlierDetectionConfig::SuccessRateEjection success_rate_ejection;
- success_rate_ejection.enforcement_percentage = enforcement_percentage;
- const google_protobuf_UInt32Value* minimum_hosts =
- envoy_config_cluster_v3_OutlierDetection_success_rate_minimum_hosts(
- outlier_detection);
- if (minimum_hosts != nullptr) {
- success_rate_ejection.minimum_hosts =
- google_protobuf_UInt32Value_value(minimum_hosts);
- }
- const google_protobuf_UInt32Value* request_volume =
- envoy_config_cluster_v3_OutlierDetection_success_rate_request_volume(
- outlier_detection);
- if (request_volume != nullptr) {
- success_rate_ejection.request_volume =
- google_protobuf_UInt32Value_value(request_volume);
- }
- const google_protobuf_UInt32Value* stdev_factor =
- envoy_config_cluster_v3_OutlierDetection_success_rate_stdev_factor(
- outlier_detection);
- if (stdev_factor != nullptr) {
- success_rate_ejection.stdev_factor =
- google_protobuf_UInt32Value_value(stdev_factor);
- }
- outlier_detection_update.success_rate_ejection = success_rate_ejection;
- }
- }
- const google_protobuf_UInt32Value* enforcing_failure_percentage =
- envoy_config_cluster_v3_OutlierDetection_enforcing_failure_percentage(
- outlier_detection);
- if (enforcing_failure_percentage != nullptr) {
- uint32_t enforcement_percentage =
- google_protobuf_UInt32Value_value(enforcing_failure_percentage);
- if (enforcement_percentage > 100) {
- ValidationErrors::ScopedField field(&errors,
- ".enforcing_failure_percentage");
- errors.AddError("value must be <= 100");
- }
- if (enforcement_percentage != 0) {
- OutlierDetectionConfig::FailurePercentageEjection
- failure_percentage_ejection;
- failure_percentage_ejection.enforcement_percentage =
- enforcement_percentage;
- const google_protobuf_UInt32Value* minimum_hosts =
- envoy_config_cluster_v3_OutlierDetection_failure_percentage_minimum_hosts(
- outlier_detection);
- if (minimum_hosts != nullptr) {
- failure_percentage_ejection.minimum_hosts =
- google_protobuf_UInt32Value_value(minimum_hosts);
- }
- const google_protobuf_UInt32Value* request_volume =
- envoy_config_cluster_v3_OutlierDetection_failure_percentage_request_volume(
- outlier_detection);
- if (request_volume != nullptr) {
- failure_percentage_ejection.request_volume =
- google_protobuf_UInt32Value_value(request_volume);
- }
- const google_protobuf_UInt32Value* threshold =
- envoy_config_cluster_v3_OutlierDetection_failure_percentage_threshold(
- outlier_detection);
- if (threshold != nullptr) {
- failure_percentage_ejection.threshold =
- google_protobuf_UInt32Value_value(threshold);
- if (enforcement_percentage > 100) {
- ValidationErrors::ScopedField field(
- &errors, ".failure_percentage_threshold");
- errors.AddError("value must be <= 100");
- }
- }
- outlier_detection_update.failure_percentage_ejection =
- failure_percentage_ejection;
- }
- }
- cds_update->outlier_detection = outlier_detection_update;
- }
- // Validate override host status.
- const auto* common_lb_config =
- envoy_config_cluster_v3_Cluster_common_lb_config(cluster);
- bool override_host_status_found = false;
- if (common_lb_config != nullptr) {
- ValidationErrors::ScopedField field(&errors, ".common_lb_config");
- const auto* override_host_status =
- envoy_config_cluster_v3_Cluster_CommonLbConfig_override_host_status(
- common_lb_config);
- if (override_host_status != nullptr) {
- ValidationErrors::ScopedField field(&errors, ".override_host_status");
- size_t size;
- const int32_t* statuses = envoy_config_core_v3_HealthStatusSet_statuses(
- override_host_status, &size);
- for (size_t i = 0; i < size; ++i) {
- auto status = XdsHealthStatus::FromUpb(statuses[i]);
- if (status.has_value()) {
- cds_update->override_host_statuses.Add(*status);
- }
- }
- override_host_status_found = true;
- }
- }
- // If the field is not set, we default to [UNKNOWN, HEALTHY].
- if (!override_host_status_found) {
- cds_update->override_host_statuses.Add(
- XdsHealthStatus(XdsHealthStatus::kUnknown));
- cds_update->override_host_statuses.Add(
- XdsHealthStatus(XdsHealthStatus::kHealthy));
- }
- // Record telemetry labels (if any).
- const envoy_config_core_v3_Metadata* metadata =
- envoy_config_cluster_v3_Cluster_metadata(cluster);
- if (metadata != nullptr) {
- google_protobuf_Struct* telemetry_labels_struct;
- if (envoy_config_core_v3_Metadata_filter_metadata_get(
- metadata,
- StdStringToUpbString(
- absl::string_view("com.google.csm.telemetry_labels")),
- &telemetry_labels_struct)) {
- size_t iter = kUpb_Map_Begin;
- const google_protobuf_Struct_FieldsEntry* fields_entry;
- while ((fields_entry = google_protobuf_Struct_fields_next(
- telemetry_labels_struct, &iter)) != nullptr) {
- // Adds any entry whose value is a string to telemetry_labels.
- const google_protobuf_Value* value =
- google_protobuf_Struct_FieldsEntry_value(fields_entry);
- if (google_protobuf_Value_has_string_value(value)) {
- if (UpbStringToAbsl(google_protobuf_Struct_FieldsEntry_key(
- fields_entry)) == "service_name") {
- cds_update->service_telemetry_label = RefCountedStringValue(
- UpbStringToAbsl(google_protobuf_Value_string_value(value)));
- } else if (UpbStringToAbsl(google_protobuf_Struct_FieldsEntry_key(
- fields_entry)) == "service_namespace") {
- cds_update->namespace_telemetry_label = RefCountedStringValue(
- UpbStringToAbsl(google_protobuf_Value_string_value(value)));
- }
- }
- }
- }
- }
- // Return result.
- if (!errors.ok()) {
- return errors.status(absl::StatusCode::kInvalidArgument,
- "errors validating Cluster resource");
- }
- return cds_update;
-}
-
-void MaybeLogCluster(const XdsResourceType::DecodeContext& context,
- const envoy_config_cluster_v3_Cluster* cluster) {
- if (GRPC_TRACE_FLAG_ENABLED_OBJ(*context.tracer) && ABSL_VLOG_IS_ON(2)) {
- const upb_MessageDef* msg_type =
- envoy_config_cluster_v3_Cluster_getmsgdef(context.symtab);
- char buf[10240];
- upb_TextEncode(reinterpret_cast(cluster), msg_type,
- nullptr, 0, buf, sizeof(buf));
- VLOG(2) << "[xds_client " << context.client << "] Cluster: " << buf;
- }
-}
-
-} // namespace
-
-XdsResourceType::DecodeResult XdsClusterResourceType::Decode(
- const XdsResourceType::DecodeContext& context,
- absl::string_view serialized_resource) const {
- DecodeResult result;
- // Parse serialized proto.
- auto* resource = envoy_config_cluster_v3_Cluster_parse(
- serialized_resource.data(), serialized_resource.size(), context.arena);
- if (resource == nullptr) {
- result.resource =
- absl::InvalidArgumentError("Can't parse Cluster resource.");
- return result;
- }
- MaybeLogCluster(context, resource);
- // Validate resource.
- result.name =
- UpbStringToStdString(envoy_config_cluster_v3_Cluster_name(resource));
- auto cds_resource = CdsResourceParse(context, resource);
- if (!cds_resource.ok()) {
- if (GRPC_TRACE_FLAG_ENABLED_OBJ(*context.tracer)) {
- LOG(ERROR) << "[xds_client " << context.client << "] invalid Cluster "
- << *result.name << ": " << cds_resource.status();
- }
- result.resource = cds_resource.status();
- } else {
- if (GRPC_TRACE_FLAG_ENABLED_OBJ(*context.tracer)) {
- LOG(INFO) << "[xds_client " << context.client << "] parsed Cluster "
- << *result.name << ": " << (*cds_resource)->ToString();
- }
- result.resource = std::move(*cds_resource);
- }
- return result;
-}
-
} // namespace grpc_core
diff --git a/src/core/xds/grpc/xds_cluster.h b/src/core/xds/grpc/xds_cluster.h
index 5eb7fca6aa9..601593541e5 100644
--- a/src/core/xds/grpc/xds_cluster.h
+++ b/src/core/xds/grpc/xds_cluster.h
@@ -17,31 +17,17 @@
#ifndef GRPC_SRC_CORE_XDS_GRPC_XDS_CLUSTER_H
#define GRPC_SRC_CORE_XDS_GRPC_XDS_CLUSTER_H
-#include
-
-#include
#include
#include
-#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
-#include "envoy/config/cluster/v3/cluster.upbdefs.h"
-#include "envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h"
-#include "envoy/extensions/transport_sockets/tls/v3/tls.upbdefs.h"
-#include "envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.h"
-#include "upb/reflection/def.h"
-
-#include
-#include
#include "src/core/load_balancing/outlier_detection/outlier_detection.h"
#include "src/core/util/json/json.h"
-#include "src/core/xds/grpc/xds_bootstrap_grpc.h"
#include "src/core/xds/grpc/xds_common_types.h"
#include "src/core/xds/grpc/xds_health_status.h"
-#include "src/core/xds/xds_client/xds_bootstrap.h"
-#include "src/core/xds/xds_client/xds_client.h"
+#include "src/core/xds/grpc/xds_server_grpc.h"
#include "src/core/xds/xds_client/xds_resource_type.h"
#include "src/core/xds/xds_client/xds_resource_type_impl.h"
@@ -84,7 +70,7 @@ struct XdsClusterResource : public XdsResourceType::ResourceData {
// The LRS server to use for load reporting.
// If not set, load reporting will be disabled.
- absl::optional lrs_load_reporting_server;
+ absl::optional lrs_load_reporting_server;
// Tls Context used by clients
CommonTlsContext common_tls_context;
@@ -118,27 +104,6 @@ struct XdsClusterResource : public XdsResourceType::ResourceData {
std::string ToString() const;
};
-class XdsClusterResourceType
- : public XdsResourceTypeImpl {
- public:
- absl::string_view type_url() const override {
- return "envoy.config.cluster.v3.Cluster";
- }
-
- DecodeResult Decode(const XdsResourceType::DecodeContext& context,
- absl::string_view serialized_resource) const override;
-
- bool AllResourcesRequiredInSotW() const override { return true; }
-
- void InitUpbSymtab(XdsClient*, upb_DefPool* symtab) const override {
- envoy_config_cluster_v3_Cluster_getmsgdef(symtab);
- envoy_extensions_clusters_aggregate_v3_ClusterConfig_getmsgdef(symtab);
- envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_getmsgdef(
- symtab);
- envoy_extensions_upstreams_http_v3_HttpProtocolOptions_getmsgdef(symtab);
- }
-};
-
} // namespace grpc_core
#endif // GRPC_SRC_CORE_XDS_GRPC_XDS_CLUSTER_H
diff --git a/src/core/xds/grpc/xds_cluster_parser.cc b/src/core/xds/grpc/xds_cluster_parser.cc
new file mode 100644
index 00000000000..50e3807b9b9
--- /dev/null
+++ b/src/core/xds/grpc/xds_cluster_parser.cc
@@ -0,0 +1,730 @@
+// 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 "src/core/xds/grpc/xds_cluster_parser.h"
+
+#include
+#include
+#include
+
+#include "absl/log/check.h"
+#include "absl/log/log.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/strip.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/cluster/v3/outlier_detection.upb.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/core/v3/extension.upb.h"
+#include "envoy/config/core/v3/health_check.upb.h"
+#include "envoy/config/core/v3/protocol.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 "envoy/extensions/transport_sockets/tls/v3/tls.upb.h"
+#include "envoy/extensions/upstreams/http/v3/http_protocol_options.upb.h"
+#include "google/protobuf/any.upb.h"
+#include "google/protobuf/duration.upb.h"
+#include "google/protobuf/struct.upb.h"
+#include "google/protobuf/wrappers.upb.h"
+#include "upb/base/string_view.h"
+#include "upb/text/encode.h"
+
+#include "src/core/lib/config/core_configuration.h"
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gprpp/host_port.h"
+#include "src/core/lib/gprpp/time.h"
+#include "src/core/lib/gprpp/validation_errors.h"
+#include "src/core/load_balancing/lb_policy_registry.h"
+#include "src/core/util/upb_utils.h"
+#include "src/core/xds/grpc/xds_bootstrap_grpc.h"
+#include "src/core/xds/grpc/xds_common_types.h"
+#include "src/core/xds/grpc/xds_common_types_parser.h"
+#include "src/core/xds/grpc/xds_lb_policy_registry.h"
+
+namespace grpc_core {
+
+namespace {
+
+CommonTlsContext UpstreamTlsContextParse(
+ const XdsResourceType::DecodeContext& context,
+ const envoy_config_core_v3_TransportSocket* transport_socket,
+ ValidationErrors* errors) {
+ ValidationErrors::ScopedField field(errors, ".typed_config");
+ const auto* typed_config =
+ envoy_config_core_v3_TransportSocket_typed_config(transport_socket);
+ auto extension = ExtractXdsExtension(context, typed_config, errors);
+ if (!extension.has_value()) return {};
+ if (extension->type !=
+ "envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext") {
+ ValidationErrors::ScopedField field(errors, ".type_url");
+ errors->AddError("unsupported transport socket type");
+ return {};
+ }
+ absl::string_view* serialized_upstream_tls_context =
+ absl::get_if(&extension->value);
+ if (serialized_upstream_tls_context == nullptr) {
+ errors->AddError("can't decode UpstreamTlsContext");
+ return {};
+ }
+ const auto* upstream_tls_context =
+ envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_parse(
+ serialized_upstream_tls_context->data(),
+ serialized_upstream_tls_context->size(), context.arena);
+ if (upstream_tls_context == nullptr) {
+ errors->AddError("can't decode UpstreamTlsContext");
+ return {};
+ }
+ ValidationErrors::ScopedField field3(errors, ".common_tls_context");
+ const auto* common_tls_context_proto =
+ envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_common_tls_context(
+ upstream_tls_context);
+ CommonTlsContext common_tls_context;
+ if (common_tls_context_proto != nullptr) {
+ common_tls_context =
+ CommonTlsContextParse(context, common_tls_context_proto, errors);
+ }
+ if (common_tls_context.certificate_validation_context
+ .ca_certificate_provider_instance.instance_name.empty()) {
+ errors->AddError("no CA certificate provider instance configured");
+ }
+ return common_tls_context;
+}
+
+XdsClusterResource::Eds EdsConfigParse(
+ const envoy_config_cluster_v3_Cluster* cluster, ValidationErrors* errors) {
+ XdsClusterResource::Eds eds;
+ ValidationErrors::ScopedField field(errors, ".eds_cluster_config");
+ const envoy_config_cluster_v3_Cluster_EdsClusterConfig* eds_cluster_config =
+ envoy_config_cluster_v3_Cluster_eds_cluster_config(cluster);
+ if (eds_cluster_config == nullptr) {
+ errors->AddError("field not present");
+ } else {
+ // Validate ConfigSource.
+ {
+ ValidationErrors::ScopedField field(errors, ".eds_config");
+ const envoy_config_core_v3_ConfigSource* eds_config =
+ envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_config(
+ eds_cluster_config);
+ if (eds_config == nullptr) {
+ errors->AddError("field not present");
+ } else {
+ if (!envoy_config_core_v3_ConfigSource_has_ads(eds_config) &&
+ !envoy_config_core_v3_ConfigSource_has_self(eds_config)) {
+ errors->AddError("ConfigSource is not ads or self");
+ }
+ }
+ }
+ // Record EDS service_name (if any).
+ // This field is required if the CDS resource has an xdstp name.
+ eds.eds_service_name = UpbStringToStdString(
+ envoy_config_cluster_v3_Cluster_EdsClusterConfig_service_name(
+ eds_cluster_config));
+ if (eds.eds_service_name.empty()) {
+ absl::string_view cluster_name =
+ UpbStringToAbsl(envoy_config_cluster_v3_Cluster_name(cluster));
+ if (absl::StartsWith(cluster_name, "xdstp:")) {
+ ValidationErrors::ScopedField field(errors, ".service_name");
+ errors->AddError("must be set if Cluster resource has an xdstp name");
+ }
+ }
+ }
+ return eds;
+}
+
+XdsClusterResource::LogicalDns LogicalDnsParse(
+ const envoy_config_cluster_v3_Cluster* cluster, ValidationErrors* errors) {
+ XdsClusterResource::LogicalDns logical_dns;
+ ValidationErrors::ScopedField field(errors, ".load_assignment");
+ const auto* load_assignment =
+ envoy_config_cluster_v3_Cluster_load_assignment(cluster);
+ if (load_assignment == nullptr) {
+ errors->AddError("field not present for LOGICAL_DNS cluster");
+ return logical_dns;
+ }
+ ValidationErrors::ScopedField field2(errors, ".endpoints");
+ size_t num_localities;
+ const auto* const* localities =
+ envoy_config_endpoint_v3_ClusterLoadAssignment_endpoints(load_assignment,
+ &num_localities);
+ if (num_localities != 1) {
+ errors->AddError(absl::StrCat(
+ "must contain exactly one locality for LOGICAL_DNS cluster, found ",
+ num_localities));
+ return logical_dns;
+ }
+ ValidationErrors::ScopedField field3(errors, "[0].lb_endpoints");
+ size_t num_endpoints;
+ const auto* const* endpoints =
+ envoy_config_endpoint_v3_LocalityLbEndpoints_lb_endpoints(localities[0],
+ &num_endpoints);
+ if (num_endpoints != 1) {
+ errors->AddError(absl::StrCat(
+ "must contain exactly one endpoint for LOGICAL_DNS cluster, found ",
+ num_endpoints));
+ return logical_dns;
+ }
+ ValidationErrors::ScopedField field4(errors, "[0].endpoint");
+ const auto* endpoint =
+ envoy_config_endpoint_v3_LbEndpoint_endpoint(endpoints[0]);
+ if (endpoint == nullptr) {
+ errors->AddError("field not present");
+ return logical_dns;
+ }
+ ValidationErrors::ScopedField field5(errors, ".address");
+ const auto* address = envoy_config_endpoint_v3_Endpoint_address(endpoint);
+ if (address == nullptr) {
+ errors->AddError("field not present");
+ return logical_dns;
+ }
+ ValidationErrors::ScopedField field6(errors, ".socket_address");
+ const auto* socket_address =
+ envoy_config_core_v3_Address_socket_address(address);
+ if (socket_address == nullptr) {
+ errors->AddError("field not present");
+ return logical_dns;
+ }
+ if (envoy_config_core_v3_SocketAddress_resolver_name(socket_address).size !=
+ 0) {
+ ValidationErrors::ScopedField field(errors, ".resolver_name");
+ errors->AddError(
+ "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()) {
+ ValidationErrors::ScopedField field(errors, ".address");
+ errors->AddError("field not present");
+ }
+ if (!envoy_config_core_v3_SocketAddress_has_port_value(socket_address)) {
+ ValidationErrors::ScopedField field(errors, ".port_value");
+ errors->AddError("field not present");
+ }
+ logical_dns.hostname = JoinHostPort(
+ address_str,
+ envoy_config_core_v3_SocketAddress_port_value(socket_address));
+ return logical_dns;
+}
+
+XdsClusterResource::Aggregate AggregateClusterParse(
+ const XdsResourceType::DecodeContext& context,
+ absl::string_view serialized_config, ValidationErrors* errors) {
+ XdsClusterResource::Aggregate aggregate;
+ const auto* aggregate_cluster_config =
+ envoy_extensions_clusters_aggregate_v3_ClusterConfig_parse(
+ serialized_config.data(), serialized_config.size(), context.arena);
+ if (aggregate_cluster_config == nullptr) {
+ errors->AddError("can't parse aggregate cluster config");
+ return aggregate;
+ }
+ size_t size;
+ const upb_StringView* clusters =
+ envoy_extensions_clusters_aggregate_v3_ClusterConfig_clusters(
+ aggregate_cluster_config, &size);
+ if (size == 0) {
+ ValidationErrors::ScopedField field(errors, ".clusters");
+ errors->AddError("must be non-empty");
+ }
+ for (size_t i = 0; i < size; ++i) {
+ aggregate.prioritized_cluster_names.emplace_back(
+ UpbStringToStdString(clusters[i]));
+ }
+ return aggregate;
+}
+
+void ParseLbPolicyConfig(const XdsResourceType::DecodeContext& context,
+ const envoy_config_cluster_v3_Cluster* cluster,
+ XdsClusterResource* cds_update,
+ ValidationErrors* errors) {
+ // First, check the new load_balancing_policy field.
+ const auto* load_balancing_policy =
+ envoy_config_cluster_v3_Cluster_load_balancing_policy(cluster);
+ if (load_balancing_policy != nullptr) {
+ const auto& registry =
+ static_cast(context.client->bootstrap())
+ .lb_policy_registry();
+ ValidationErrors::ScopedField field(errors, ".load_balancing_policy");
+ const size_t original_error_count = errors->size();
+ cds_update->lb_policy_config = registry.ConvertXdsLbPolicyConfig(
+ context, load_balancing_policy, errors);
+ // If there were no conversion errors, validate that the converted config
+ // parses with the gRPC LB policy registry.
+ if (original_error_count == errors->size()) {
+ auto config = CoreConfiguration::Get()
+ .lb_policy_registry()
+ .ParseLoadBalancingConfig(
+ Json::FromArray(cds_update->lb_policy_config));
+ if (!config.ok()) errors->AddError(config.status().message());
+ }
+ return;
+ }
+ // Didn't find load_balancing_policy field, so fall back to the old
+ // lb_policy enum field.
+ if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
+ envoy_config_cluster_v3_Cluster_ROUND_ROBIN) {
+ cds_update->lb_policy_config = {
+ Json::FromObject({
+ {"xds_wrr_locality_experimental",
+ Json::FromObject({
+ {"childPolicy", Json::FromArray({
+ Json::FromObject({
+ {"round_robin", Json::FromObject({})},
+ }),
+ })},
+ })},
+ }),
+ };
+ } else if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
+ envoy_config_cluster_v3_Cluster_RING_HASH) {
+ // Record ring hash lb config
+ auto* ring_hash_config =
+ envoy_config_cluster_v3_Cluster_ring_hash_lb_config(cluster);
+ uint64_t min_ring_size = 1024;
+ uint64_t max_ring_size = 8388608;
+ if (ring_hash_config != nullptr) {
+ ValidationErrors::ScopedField field(errors, ".ring_hash_lb_config");
+ const google_protobuf_UInt64Value* uint64_value =
+ envoy_config_cluster_v3_Cluster_RingHashLbConfig_maximum_ring_size(
+ ring_hash_config);
+ if (uint64_value != nullptr) {
+ ValidationErrors::ScopedField field(errors, ".maximum_ring_size");
+ max_ring_size = google_protobuf_UInt64Value_value(uint64_value);
+ if (max_ring_size > 8388608 || max_ring_size == 0) {
+ errors->AddError("must be in the range of 1 to 8388608");
+ }
+ }
+ uint64_value =
+ envoy_config_cluster_v3_Cluster_RingHashLbConfig_minimum_ring_size(
+ ring_hash_config);
+ if (uint64_value != nullptr) {
+ ValidationErrors::ScopedField field(errors, ".minimum_ring_size");
+ min_ring_size = google_protobuf_UInt64Value_value(uint64_value);
+ if (min_ring_size > 8388608 || min_ring_size == 0) {
+ errors->AddError("must be in the range of 1 to 8388608");
+ }
+ if (min_ring_size > max_ring_size) {
+ errors->AddError("cannot be greater than maximum_ring_size");
+ }
+ }
+ if (envoy_config_cluster_v3_Cluster_RingHashLbConfig_hash_function(
+ ring_hash_config) !=
+ envoy_config_cluster_v3_Cluster_RingHashLbConfig_XX_HASH) {
+ ValidationErrors::ScopedField field(errors, ".hash_function");
+ errors->AddError("invalid hash function");
+ }
+ }
+ cds_update->lb_policy_config = {
+ Json::FromObject({
+ {"ring_hash_experimental",
+ Json::FromObject({
+ {"minRingSize", Json::FromNumber(min_ring_size)},
+ {"maxRingSize", Json::FromNumber(max_ring_size)},
+ })},
+ }),
+ };
+ } else {
+ ValidationErrors::ScopedField field(errors, ".lb_policy");
+ errors->AddError("LB policy is not supported");
+ }
+}
+
+void ParseUpstreamConfig(
+ const XdsResourceType::DecodeContext& context,
+ const envoy_config_core_v3_TypedExtensionConfig* upstream_config,
+ XdsClusterResource* cds_update, ValidationErrors* errors) {
+ ValidationErrors::ScopedField field(errors, ".typed_config");
+ const auto* typed_config =
+ envoy_config_core_v3_TypedExtensionConfig_typed_config(upstream_config);
+ auto extension = ExtractXdsExtension(context, typed_config, errors);
+ if (!extension.has_value()) return;
+ if (extension->type !=
+ "envoy.extensions.upstreams.http.v3.HttpProtocolOptions") {
+ ValidationErrors::ScopedField field(errors, ".type_url");
+ errors->AddError("unsupported upstream config type");
+ return;
+ }
+ absl::string_view* serialized_http_protocol_options =
+ absl::get_if(&extension->value);
+ if (serialized_http_protocol_options == nullptr) {
+ errors->AddError("can't decode HttpProtocolOptions");
+ return;
+ }
+ const auto* http_protocol_options =
+ envoy_extensions_upstreams_http_v3_HttpProtocolOptions_parse(
+ serialized_http_protocol_options->data(),
+ serialized_http_protocol_options->size(), context.arena);
+ if (http_protocol_options == nullptr) {
+ errors->AddError("can't decode HttpProtocolOptions");
+ return;
+ }
+ ValidationErrors::ScopedField field2(errors, ".common_http_protocol_options");
+ const auto* common_http_protocol_options =
+ envoy_extensions_upstreams_http_v3_HttpProtocolOptions_common_http_protocol_options(
+ http_protocol_options);
+ if (common_http_protocol_options != nullptr) {
+ const auto* idle_timeout =
+ envoy_config_core_v3_HttpProtocolOptions_idle_timeout(
+ common_http_protocol_options);
+ if (idle_timeout != nullptr) {
+ ValidationErrors::ScopedField field(errors, ".idle_timeout");
+ cds_update->connection_idle_timeout = ParseDuration(idle_timeout, errors);
+ }
+ }
+}
+
+absl::StatusOr> CdsResourceParse(
+ const XdsResourceType::DecodeContext& context,
+ const envoy_config_cluster_v3_Cluster* cluster) {
+ auto cds_update = std::make_shared();
+ ValidationErrors errors;
+ // Check the cluster discovery type.
+ if (envoy_config_cluster_v3_Cluster_type(cluster) ==
+ envoy_config_cluster_v3_Cluster_EDS) {
+ cds_update->type = EdsConfigParse(cluster, &errors);
+ } else if (envoy_config_cluster_v3_Cluster_type(cluster) ==
+ envoy_config_cluster_v3_Cluster_LOGICAL_DNS) {
+ cds_update->type = LogicalDnsParse(cluster, &errors);
+ } else if (envoy_config_cluster_v3_Cluster_has_cluster_type(cluster)) {
+ ValidationErrors::ScopedField field(&errors, ".cluster_type");
+ const auto* custom_cluster_type =
+ envoy_config_cluster_v3_Cluster_cluster_type(cluster);
+ CHECK_NE(custom_cluster_type, nullptr);
+ ValidationErrors::ScopedField field2(&errors, ".typed_config");
+ const auto* typed_config =
+ envoy_config_cluster_v3_Cluster_CustomClusterType_typed_config(
+ custom_cluster_type);
+ if (typed_config == nullptr) {
+ errors.AddError("field not present");
+ } else {
+ absl::string_view type_url = absl::StripPrefix(
+ UpbStringToAbsl(google_protobuf_Any_type_url(typed_config)),
+ "type.googleapis.com/");
+ if (type_url != "envoy.extensions.clusters.aggregate.v3.ClusterConfig") {
+ ValidationErrors::ScopedField field(&errors, ".type_url");
+ errors.AddError(
+ absl::StrCat("unknown cluster_type extension: ", type_url));
+ } else {
+ // Retrieve aggregate clusters.
+ ValidationErrors::ScopedField field(
+ &errors,
+ ".value[envoy.extensions.clusters.aggregate.v3.ClusterConfig]");
+ absl::string_view serialized_config =
+ UpbStringToAbsl(google_protobuf_Any_value(typed_config));
+ cds_update->type =
+ AggregateClusterParse(context, serialized_config, &errors);
+ }
+ }
+ } else {
+ ValidationErrors::ScopedField field(&errors, ".type");
+ errors.AddError("unknown discovery type");
+ }
+ // Check the LB policy.
+ ParseLbPolicyConfig(context, cluster, cds_update.get(), &errors);
+ // transport_socket
+ auto* transport_socket =
+ envoy_config_cluster_v3_Cluster_transport_socket(cluster);
+ if (transport_socket != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".transport_socket");
+ cds_update->common_tls_context =
+ UpstreamTlsContextParse(context, transport_socket, &errors);
+ }
+ // 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)) {
+ ValidationErrors::ScopedField field(&errors, ".lrs_server");
+ errors.AddError("ConfigSource is not self");
+ }
+ cds_update->lrs_load_reporting_server.emplace(
+ static_cast(context.server));
+ }
+ // Protocol options.
+ auto* upstream_config =
+ envoy_config_cluster_v3_Cluster_upstream_config(cluster);
+ if (upstream_config != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".upstream_config");
+ ParseUpstreamConfig(context, upstream_config, cds_update.get(), &errors);
+ }
+ // 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;
+ }
+ }
+ }
+ // Outlier detection config.
+ if (envoy_config_cluster_v3_Cluster_has_outlier_detection(cluster)) {
+ ValidationErrors::ScopedField field(&errors, ".outlier_detection");
+ OutlierDetectionConfig outlier_detection_update;
+ const envoy_config_cluster_v3_OutlierDetection* outlier_detection =
+ envoy_config_cluster_v3_Cluster_outlier_detection(cluster);
+ const google_protobuf_Duration* duration =
+ envoy_config_cluster_v3_OutlierDetection_interval(outlier_detection);
+ if (duration != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".interval");
+ outlier_detection_update.interval = ParseDuration(duration, &errors);
+ }
+ duration = envoy_config_cluster_v3_OutlierDetection_base_ejection_time(
+ outlier_detection);
+ if (duration != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".base_ejection_time");
+ outlier_detection_update.base_ejection_time =
+ ParseDuration(duration, &errors);
+ }
+ duration = envoy_config_cluster_v3_OutlierDetection_max_ejection_time(
+ outlier_detection);
+ if (duration != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".max_ejection_time");
+ outlier_detection_update.max_ejection_time =
+ ParseDuration(duration, &errors);
+ }
+ const google_protobuf_UInt32Value* max_ejection_percent =
+ envoy_config_cluster_v3_OutlierDetection_max_ejection_percent(
+ outlier_detection);
+ if (max_ejection_percent != nullptr) {
+ outlier_detection_update.max_ejection_percent =
+ google_protobuf_UInt32Value_value(max_ejection_percent);
+ if (outlier_detection_update.max_ejection_percent > 100) {
+ ValidationErrors::ScopedField field(&errors, ".max_ejection_percent");
+ errors.AddError("value must be <= 100");
+ }
+ }
+ const google_protobuf_UInt32Value* enforcing_success_rate =
+ envoy_config_cluster_v3_OutlierDetection_enforcing_success_rate(
+ outlier_detection);
+ if (enforcing_success_rate != nullptr) {
+ uint32_t enforcement_percentage =
+ google_protobuf_UInt32Value_value(enforcing_success_rate);
+ if (enforcement_percentage > 100) {
+ ValidationErrors::ScopedField field(&errors, ".enforcing_success_rate");
+ errors.AddError("value must be <= 100");
+ }
+ if (enforcement_percentage != 0) {
+ OutlierDetectionConfig::SuccessRateEjection success_rate_ejection;
+ success_rate_ejection.enforcement_percentage = enforcement_percentage;
+ const google_protobuf_UInt32Value* minimum_hosts =
+ envoy_config_cluster_v3_OutlierDetection_success_rate_minimum_hosts(
+ outlier_detection);
+ if (minimum_hosts != nullptr) {
+ success_rate_ejection.minimum_hosts =
+ google_protobuf_UInt32Value_value(minimum_hosts);
+ }
+ const google_protobuf_UInt32Value* request_volume =
+ envoy_config_cluster_v3_OutlierDetection_success_rate_request_volume(
+ outlier_detection);
+ if (request_volume != nullptr) {
+ success_rate_ejection.request_volume =
+ google_protobuf_UInt32Value_value(request_volume);
+ }
+ const google_protobuf_UInt32Value* stdev_factor =
+ envoy_config_cluster_v3_OutlierDetection_success_rate_stdev_factor(
+ outlier_detection);
+ if (stdev_factor != nullptr) {
+ success_rate_ejection.stdev_factor =
+ google_protobuf_UInt32Value_value(stdev_factor);
+ }
+ outlier_detection_update.success_rate_ejection = success_rate_ejection;
+ }
+ }
+ const google_protobuf_UInt32Value* enforcing_failure_percentage =
+ envoy_config_cluster_v3_OutlierDetection_enforcing_failure_percentage(
+ outlier_detection);
+ if (enforcing_failure_percentage != nullptr) {
+ uint32_t enforcement_percentage =
+ google_protobuf_UInt32Value_value(enforcing_failure_percentage);
+ if (enforcement_percentage > 100) {
+ ValidationErrors::ScopedField field(&errors,
+ ".enforcing_failure_percentage");
+ errors.AddError("value must be <= 100");
+ }
+ if (enforcement_percentage != 0) {
+ OutlierDetectionConfig::FailurePercentageEjection
+ failure_percentage_ejection;
+ failure_percentage_ejection.enforcement_percentage =
+ enforcement_percentage;
+ const google_protobuf_UInt32Value* minimum_hosts =
+ envoy_config_cluster_v3_OutlierDetection_failure_percentage_minimum_hosts(
+ outlier_detection);
+ if (minimum_hosts != nullptr) {
+ failure_percentage_ejection.minimum_hosts =
+ google_protobuf_UInt32Value_value(minimum_hosts);
+ }
+ const google_protobuf_UInt32Value* request_volume =
+ envoy_config_cluster_v3_OutlierDetection_failure_percentage_request_volume(
+ outlier_detection);
+ if (request_volume != nullptr) {
+ failure_percentage_ejection.request_volume =
+ google_protobuf_UInt32Value_value(request_volume);
+ }
+ const google_protobuf_UInt32Value* threshold =
+ envoy_config_cluster_v3_OutlierDetection_failure_percentage_threshold(
+ outlier_detection);
+ if (threshold != nullptr) {
+ failure_percentage_ejection.threshold =
+ google_protobuf_UInt32Value_value(threshold);
+ if (enforcement_percentage > 100) {
+ ValidationErrors::ScopedField field(
+ &errors, ".failure_percentage_threshold");
+ errors.AddError("value must be <= 100");
+ }
+ }
+ outlier_detection_update.failure_percentage_ejection =
+ failure_percentage_ejection;
+ }
+ }
+ cds_update->outlier_detection = outlier_detection_update;
+ }
+ // Validate override host status.
+ const auto* common_lb_config =
+ envoy_config_cluster_v3_Cluster_common_lb_config(cluster);
+ bool override_host_status_found = false;
+ if (common_lb_config != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".common_lb_config");
+ const auto* override_host_status =
+ envoy_config_cluster_v3_Cluster_CommonLbConfig_override_host_status(
+ common_lb_config);
+ if (override_host_status != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".override_host_status");
+ size_t size;
+ const int32_t* statuses = envoy_config_core_v3_HealthStatusSet_statuses(
+ override_host_status, &size);
+ for (size_t i = 0; i < size; ++i) {
+ auto status = XdsHealthStatus::FromUpb(statuses[i]);
+ if (status.has_value()) {
+ cds_update->override_host_statuses.Add(*status);
+ }
+ }
+ override_host_status_found = true;
+ }
+ }
+ // If the field is not set, we default to [UNKNOWN, HEALTHY].
+ if (!override_host_status_found) {
+ cds_update->override_host_statuses.Add(
+ XdsHealthStatus(XdsHealthStatus::kUnknown));
+ cds_update->override_host_statuses.Add(
+ XdsHealthStatus(XdsHealthStatus::kHealthy));
+ }
+ // Record telemetry labels (if any).
+ const envoy_config_core_v3_Metadata* metadata =
+ envoy_config_cluster_v3_Cluster_metadata(cluster);
+ if (metadata != nullptr) {
+ google_protobuf_Struct* telemetry_labels_struct;
+ if (envoy_config_core_v3_Metadata_filter_metadata_get(
+ metadata,
+ StdStringToUpbString(
+ absl::string_view("com.google.csm.telemetry_labels")),
+ &telemetry_labels_struct)) {
+ size_t iter = kUpb_Map_Begin;
+ const google_protobuf_Struct_FieldsEntry* fields_entry;
+ while ((fields_entry = google_protobuf_Struct_fields_next(
+ telemetry_labels_struct, &iter)) != nullptr) {
+ // Adds any entry whose value is a string to telemetry_labels.
+ const google_protobuf_Value* value =
+ google_protobuf_Struct_FieldsEntry_value(fields_entry);
+ if (google_protobuf_Value_has_string_value(value)) {
+ if (UpbStringToAbsl(google_protobuf_Struct_FieldsEntry_key(
+ fields_entry)) == "service_name") {
+ cds_update->service_telemetry_label = RefCountedStringValue(
+ UpbStringToAbsl(google_protobuf_Value_string_value(value)));
+ } else if (UpbStringToAbsl(google_protobuf_Struct_FieldsEntry_key(
+ fields_entry)) == "service_namespace") {
+ cds_update->namespace_telemetry_label = RefCountedStringValue(
+ UpbStringToAbsl(google_protobuf_Value_string_value(value)));
+ }
+ }
+ }
+ }
+ }
+ // Return result.
+ if (!errors.ok()) {
+ return errors.status(absl::StatusCode::kInvalidArgument,
+ "errors validating Cluster resource");
+ }
+ return cds_update;
+}
+
+void MaybeLogCluster(const XdsResourceType::DecodeContext& context,
+ const envoy_config_cluster_v3_Cluster* cluster) {
+ if (GRPC_TRACE_FLAG_ENABLED_OBJ(*context.tracer) && ABSL_VLOG_IS_ON(2)) {
+ const upb_MessageDef* msg_type =
+ envoy_config_cluster_v3_Cluster_getmsgdef(context.symtab);
+ char buf[10240];
+ upb_TextEncode(reinterpret_cast(cluster), msg_type,
+ nullptr, 0, buf, sizeof(buf));
+ VLOG(2) << "[xds_client " << context.client << "] Cluster: " << buf;
+ }
+}
+
+} // namespace
+
+XdsResourceType::DecodeResult XdsClusterResourceType::Decode(
+ const XdsResourceType::DecodeContext& context,
+ absl::string_view serialized_resource) const {
+ DecodeResult result;
+ // Parse serialized proto.
+ auto* resource = envoy_config_cluster_v3_Cluster_parse(
+ serialized_resource.data(), serialized_resource.size(), context.arena);
+ if (resource == nullptr) {
+ result.resource =
+ absl::InvalidArgumentError("Can't parse Cluster resource.");
+ return result;
+ }
+ MaybeLogCluster(context, resource);
+ // Validate resource.
+ result.name =
+ UpbStringToStdString(envoy_config_cluster_v3_Cluster_name(resource));
+ auto cds_resource = CdsResourceParse(context, resource);
+ if (!cds_resource.ok()) {
+ if (GRPC_TRACE_FLAG_ENABLED_OBJ(*context.tracer)) {
+ LOG(ERROR) << "[xds_client " << context.client << "] invalid Cluster "
+ << *result.name << ": " << cds_resource.status();
+ }
+ result.resource = cds_resource.status();
+ } else {
+ if (GRPC_TRACE_FLAG_ENABLED_OBJ(*context.tracer)) {
+ LOG(INFO) << "[xds_client " << context.client << "] parsed Cluster "
+ << *result.name << ": " << (*cds_resource)->ToString();
+ }
+ result.resource = std::move(*cds_resource);
+ }
+ return result;
+}
+
+} // namespace grpc_core
diff --git a/src/core/xds/grpc/xds_cluster_parser.h b/src/core/xds/grpc/xds_cluster_parser.h
new file mode 100644
index 00000000000..109818a079f
--- /dev/null
+++ b/src/core/xds/grpc/xds_cluster_parser.h
@@ -0,0 +1,57 @@
+//
+// 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_SRC_CORE_XDS_GRPC_XDS_CLUSTER_PARSER_H
+#define GRPC_SRC_CORE_XDS_GRPC_XDS_CLUSTER_PARSER_H
+
+#include "absl/strings/string_view.h"
+#include "envoy/config/cluster/v3/cluster.upbdefs.h"
+#include "envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h"
+#include "envoy/extensions/transport_sockets/tls/v3/tls.upbdefs.h"
+#include "envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.h"
+#include "upb/reflection/def.h"
+
+#include "src/core/xds/grpc/xds_cluster.h"
+#include "src/core/xds/xds_client/xds_client.h"
+#include "src/core/xds/xds_client/xds_resource_type.h"
+#include "src/core/xds/xds_client/xds_resource_type_impl.h"
+
+namespace grpc_core {
+
+class XdsClusterResourceType
+ : public XdsResourceTypeImpl {
+ public:
+ absl::string_view type_url() const override {
+ return "envoy.config.cluster.v3.Cluster";
+ }
+
+ DecodeResult Decode(const XdsResourceType::DecodeContext& context,
+ absl::string_view serialized_resource) const override;
+
+ bool AllResourcesRequiredInSotW() const override { return true; }
+
+ void InitUpbSymtab(XdsClient*, upb_DefPool* symtab) const override {
+ envoy_config_cluster_v3_Cluster_getmsgdef(symtab);
+ envoy_extensions_clusters_aggregate_v3_ClusterConfig_getmsgdef(symtab);
+ envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_getmsgdef(
+ symtab);
+ envoy_extensions_upstreams_http_v3_HttpProtocolOptions_getmsgdef(symtab);
+ }
+};
+
+} // namespace grpc_core
+
+#endif // GRPC_SRC_CORE_XDS_GRPC_XDS_CLUSTER_PARSER_H
diff --git a/src/core/xds/grpc/xds_common_types.cc b/src/core/xds/grpc/xds_common_types.cc
index 2e8fafda588..4617334dddb 100644
--- a/src/core/xds/grpc/xds_common_types.cc
+++ b/src/core/xds/grpc/xds_common_types.cc
@@ -16,60 +16,12 @@
#include "src/core/xds/grpc/xds_common_types.h"
-#include
-#include
-
-#include
-#include