diff --git a/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc b/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc index 0e00e6f2017..fc2dac9586f 100644 --- a/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc @@ -235,7 +235,7 @@ class XdsResolver : public Resolver { void MaybeAddCluster(const std::string& name); grpc_error_handle CreateMethodConfig( const XdsApi::Route& route, - const XdsApi::Route::ClusterWeight* cluster_weight, + const XdsApi::Route::RouteAction::ClusterWeight* cluster_weight, RefCountedPtr* method_config); RefCountedPtr resolver_; @@ -392,30 +392,34 @@ XdsResolver::XdsConfigSelector::XdsConfigSelector( route_table_.emplace_back(); auto& route_entry = route_table_.back(); route_entry.route = route; - // If the route doesn't specify a timeout, set its timeout to the global - // one. - if (!route.max_stream_duration.has_value()) { - route_entry.route.max_stream_duration = - resolver_->current_listener_.http_connection_manager - .http_max_stream_duration; - } - if (route.weighted_clusters.empty()) { - *error = CreateMethodConfig(route_entry.route, nullptr, - &route_entry.method_config); - MaybeAddCluster(route.cluster_name); - } else { - uint32_t end = 0; - for (const auto& weighted_cluster : route_entry.route.weighted_clusters) { - Route::ClusterWeightState cluster_weight_state; - *error = CreateMethodConfig(route_entry.route, &weighted_cluster, - &cluster_weight_state.method_config); - if (*error != GRPC_ERROR_NONE) return; - end += weighted_cluster.weight; - cluster_weight_state.range_end = end; - cluster_weight_state.cluster = weighted_cluster.name; - route_entry.weighted_cluster_state.push_back( - std::move(cluster_weight_state)); - MaybeAddCluster(weighted_cluster.name); + auto* route_action = + absl::get_if(&route_entry.route.action); + if (route_action != nullptr) { + // If the route doesn't specify a timeout, set its timeout to the global + // one. + if (!route_action->max_stream_duration.has_value()) { + route_action->max_stream_duration = + resolver_->current_listener_.http_connection_manager + .http_max_stream_duration; + } + if (route_action->weighted_clusters.empty()) { + *error = CreateMethodConfig(route_entry.route, nullptr, + &route_entry.method_config); + MaybeAddCluster(route_action->cluster_name); + } else { + uint32_t end = 0; + for (const auto& weighted_cluster : route_action->weighted_clusters) { + Route::ClusterWeightState cluster_weight_state; + *error = CreateMethodConfig(route_entry.route, &weighted_cluster, + &cluster_weight_state.method_config); + if (*error != GRPC_ERROR_NONE) return; + end += weighted_cluster.weight; + cluster_weight_state.range_end = end; + cluster_weight_state.cluster = weighted_cluster.name; + route_entry.weighted_cluster_state.push_back( + std::move(cluster_weight_state)); + MaybeAddCluster(weighted_cluster.name); + } } } } @@ -447,7 +451,7 @@ XdsResolver::XdsConfigSelector::~XdsConfigSelector() { const XdsHttpFilterImpl::FilterConfig* FindFilterConfigOverride( const std::string& instance_name, const XdsApi::RdsUpdate::VirtualHost& vhost, const XdsApi::Route& route, - const XdsApi::Route::ClusterWeight* cluster_weight) { + const XdsApi::Route::RouteAction::ClusterWeight* cluster_weight) { // Check ClusterWeight, if any. if (cluster_weight != nullptr) { auto it = cluster_weight->typed_per_filter_config.find(instance_name); @@ -465,11 +469,14 @@ const XdsHttpFilterImpl::FilterConfig* FindFilterConfigOverride( grpc_error_handle XdsResolver::XdsConfigSelector::CreateMethodConfig( const XdsApi::Route& route, - const XdsApi::Route::ClusterWeight* cluster_weight, + const XdsApi::Route::RouteAction::ClusterWeight* cluster_weight, RefCountedPtr* method_config) { std::vector fields; + const auto& route_action = + absl::get(route.action); // Set retry policy if any. - if (route.retry_policy.has_value() && !route.retry_policy->retry_on.Empty()) { + if (route_action.retry_policy.has_value() && + !route_action.retry_policy->retry_on.Empty()) { std::vector retry_parts; retry_parts.push_back(absl::StrFormat( "\"retryPolicy\": {\n" @@ -477,25 +484,27 @@ grpc_error_handle XdsResolver::XdsConfigSelector::CreateMethodConfig( " \"initialBackoff\": \"%d.%09ds\",\n" " \"maxBackoff\": \"%d.%09ds\",\n" " \"backoffMultiplier\": 2,\n", - route.retry_policy->num_retries + 1, - route.retry_policy->retry_back_off.base_interval.seconds, - route.retry_policy->retry_back_off.base_interval.nanos, - route.retry_policy->retry_back_off.max_interval.seconds, - route.retry_policy->retry_back_off.max_interval.nanos)); + route_action.retry_policy->num_retries + 1, + route_action.retry_policy->retry_back_off.base_interval.seconds, + route_action.retry_policy->retry_back_off.base_interval.nanos, + route_action.retry_policy->retry_back_off.max_interval.seconds, + route_action.retry_policy->retry_back_off.max_interval.nanos)); std::vector code_parts; - if (route.retry_policy->retry_on.Contains(GRPC_STATUS_CANCELLED)) { + if (route_action.retry_policy->retry_on.Contains(GRPC_STATUS_CANCELLED)) { code_parts.push_back(" \"CANCELLED\""); } - if (route.retry_policy->retry_on.Contains(GRPC_STATUS_DEADLINE_EXCEEDED)) { + if (route_action.retry_policy->retry_on.Contains( + GRPC_STATUS_DEADLINE_EXCEEDED)) { code_parts.push_back(" \"DEADLINE_EXCEEDED\""); } - if (route.retry_policy->retry_on.Contains(GRPC_STATUS_INTERNAL)) { + if (route_action.retry_policy->retry_on.Contains(GRPC_STATUS_INTERNAL)) { code_parts.push_back(" \"INTERNAL\""); } - if (route.retry_policy->retry_on.Contains(GRPC_STATUS_RESOURCE_EXHAUSTED)) { + if (route_action.retry_policy->retry_on.Contains( + GRPC_STATUS_RESOURCE_EXHAUSTED)) { code_parts.push_back(" \"RESOURCE_EXHAUSTED\""); } - if (route.retry_policy->retry_on.Contains(GRPC_STATUS_UNAVAILABLE)) { + if (route_action.retry_policy->retry_on.Contains(GRPC_STATUS_UNAVAILABLE)) { code_parts.push_back(" \"UNAVAILABLE\""); } retry_parts.push_back( @@ -505,12 +514,13 @@ grpc_error_handle XdsResolver::XdsConfigSelector::CreateMethodConfig( fields.emplace_back(absl::StrJoin(retry_parts, "")); } // Set timeout. - if (route.max_stream_duration.has_value() && - (route.max_stream_duration->seconds != 0 || - route.max_stream_duration->nanos != 0)) { - fields.emplace_back(absl::StrFormat(" \"timeout\": \"%d.%09ds\"", - route.max_stream_duration->seconds, - route.max_stream_duration->nanos)); + if (route_action.max_stream_duration.has_value() && + (route_action.max_stream_duration->seconds != 0 || + route_action.max_stream_duration->nanos != 0)) { + fields.emplace_back( + absl::StrFormat(" \"timeout\": \"%d.%09ds\"", + route_action.max_stream_duration->seconds, + route_action.max_stream_duration->nanos)); } // Handle xDS HTTP filters. std::map> per_filter_configs; @@ -613,9 +623,9 @@ bool HeadersMatch(const std::vector& header_matchers, } absl::optional HeaderHashHelper( - const XdsApi::Route::HashPolicy& policy, + const XdsApi::Route::RouteAction::HashPolicy& policy, grpc_metadata_batch* initial_metadata) { - GPR_ASSERT(policy.type == XdsApi::Route::HashPolicy::HEADER); + GPR_ASSERT(policy.type == XdsApi::Route::RouteAction::HashPolicy::HEADER); std::string value_buffer; absl::optional header_value = GetHeaderValue(initial_metadata, policy.header_name, &value_buffer); @@ -659,10 +669,20 @@ ConfigSelector::CallConfig XdsResolver::XdsConfigSelector::GetCallConfig( continue; } // Found a route match + const auto* route_action = + absl::get_if(&entry.route.action); + if (route_action == nullptr) { + CallConfig call_config; + call_config.error = grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Matching route has inappropriate action"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE); + return call_config; + } absl::string_view cluster_name; RefCountedPtr method_config; - if (entry.route.weighted_clusters.empty()) { - cluster_name = entry.route.cluster_name; + if (route_action->weighted_clusters.empty()) { + cluster_name = route_action->cluster_name; method_config = entry.method_config; } else { const uint32_t key = @@ -694,13 +714,13 @@ ConfigSelector::CallConfig XdsResolver::XdsConfigSelector::GetCallConfig( GPR_ASSERT(it != clusters_.end()); // Generate a hash. absl::optional hash; - for (const auto& hash_policy : entry.route.hash_policies) { + for (const auto& hash_policy : route_action->hash_policies) { absl::optional new_hash; switch (hash_policy.type) { - case XdsApi::Route::HashPolicy::HEADER: + case XdsApi::Route::RouteAction::HashPolicy::HEADER: new_hash = HeaderHashHelper(hash_policy, args.initial_metadata); break; - case XdsApi::Route::HashPolicy::CHANNEL_ID: + case XdsApi::Route::RouteAction::HashPolicy::CHANNEL_ID: new_hash = static_cast( reinterpret_cast(resolver_.get())); break; @@ -907,13 +927,15 @@ void XdsResolver::GenerateResult() { grpc_error_handle error = GRPC_ERROR_NONE; auto config_selector = MakeRefCounted(Ref(), &error); if (error != GRPC_ERROR_NONE) { - OnError(error); + OnError(grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAVAILABLE)); return; } Result result; error = CreateServiceConfig(&result.service_config); if (error != GRPC_ERROR_NONE) { - OnError(error); + OnError(grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAVAILABLE)); return; } if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { diff --git a/src/core/ext/xds/xds_api.cc b/src/core/ext/xds/xds_api.cc index bccaa74c7e5..6e1b2322b15 100644 --- a/src/core/ext/xds/xds_api.cc +++ b/src/core/ext/xds/xds_api.cc @@ -115,11 +115,58 @@ bool XdsAggregateAndLogicalDnsClusterEnabled() { return parse_succeeded && parsed_value; } +// TODO(yashykt): Remove once RBAC is no longer experimental +bool XdsRbacEnabled() { + char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_RBAC"); + bool parsed_value; + bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value); + gpr_free(value); + return parse_succeeded && parsed_value; +} + +// +// XdsApi::RetryPolicy +// + +std::string XdsApi::RetryPolicy::RetryBackOff::ToString() const { + std::vector contents; + contents.push_back( + absl::StrCat("RetryBackOff Base: ", base_interval.ToString())); + contents.push_back( + absl::StrCat("RetryBackOff max: ", max_interval.ToString())); + return absl::StrJoin(contents, ","); +} + +std::string XdsApi::RetryPolicy::ToString() const { + std::vector contents; + contents.push_back(absl::StrFormat("num_retries=%d", num_retries)); + contents.push_back(retry_back_off.ToString()); + return absl::StrCat("{", absl::StrJoin(contents, ","), "}"); +} + +// +// XdsApi::Route::Matchers +// + +std::string XdsApi::Route::Matchers::ToString() const { + std::vector contents; + contents.push_back( + absl::StrFormat("PathMatcher{%s}", path_matcher.ToString())); + for (const HeaderMatcher& header_matcher : header_matchers) { + contents.push_back(header_matcher.ToString()); + } + if (fraction_per_million.has_value()) { + contents.push_back(absl::StrFormat("Fraction Per Million %d", + fraction_per_million.value())); + } + return absl::StrJoin(contents, "\n"); +} + // -// XdsApi::Route::HashPolicy +// XdsApi::Route::RouteAction::HashPolicy // -XdsApi::Route::HashPolicy::HashPolicy(const HashPolicy& other) +XdsApi::Route::RouteAction::HashPolicy::HashPolicy(const HashPolicy& other) : type(other.type), header_name(other.header_name), regex_substitution(other.regex_substitution) { @@ -129,8 +176,8 @@ XdsApi::Route::HashPolicy::HashPolicy(const HashPolicy& other) } } -XdsApi::Route::HashPolicy& XdsApi::Route::HashPolicy::operator=( - const HashPolicy& other) { +XdsApi::Route::RouteAction::HashPolicy& +XdsApi::Route::RouteAction::HashPolicy::operator=(const HashPolicy& other) { type = other.type; header_name = other.header_name; if (other.regex != nullptr) { @@ -141,14 +188,14 @@ XdsApi::Route::HashPolicy& XdsApi::Route::HashPolicy::operator=( return *this; } -XdsApi::Route::HashPolicy::HashPolicy(HashPolicy&& other) noexcept +XdsApi::Route::RouteAction::HashPolicy::HashPolicy(HashPolicy&& other) noexcept : type(other.type), header_name(std::move(other.header_name)), regex(std::move(other.regex)), regex_substitution(std::move(other.regex_substitution)) {} -XdsApi::Route::HashPolicy& XdsApi::Route::HashPolicy::operator=( - HashPolicy&& other) noexcept { +XdsApi::Route::RouteAction::HashPolicy& +XdsApi::Route::RouteAction::HashPolicy::operator=(HashPolicy&& other) noexcept { type = other.type; header_name = std::move(other.header_name); regex = std::move(other.regex); @@ -156,7 +203,7 @@ XdsApi::Route::HashPolicy& XdsApi::Route::HashPolicy::operator=( return *this; } -bool XdsApi::Route::HashPolicy::HashPolicy::operator==( +bool XdsApi::Route::RouteAction::HashPolicy::HashPolicy::operator==( const HashPolicy& other) const { if (type != other.type) return false; if (type == Type::HEADER) { @@ -172,7 +219,7 @@ bool XdsApi::Route::HashPolicy::HashPolicy::operator==( return true; } -std::string XdsApi::Route::HashPolicy::ToString() const { +std::string XdsApi::Route::RouteAction::HashPolicy::ToString() const { std::vector contents; switch (type) { case Type::HEADER: @@ -193,43 +240,10 @@ std::string XdsApi::Route::HashPolicy::ToString() const { } // -// XdsApi::Route::RetryPolicy -// -std::string XdsApi::Route::RetryPolicy::RetryBackOff::ToString() const { - std::vector contents; - contents.push_back( - absl::StrCat("RetryBackOff Base: ", base_interval.ToString())); - contents.push_back( - absl::StrCat("RetryBackOff max: ", max_interval.ToString())); - return absl::StrJoin(contents, ","); -} - -std::string XdsApi::Route::RetryPolicy::ToString() const { - std::vector contents; - contents.push_back(absl::StrFormat("num_retries=%d", num_retries)); - contents.push_back(retry_back_off.ToString()); - return absl::StrJoin(contents, ","); -} - -// -// XdsApi::Route +// XdsApi::Route::RouteAction::ClusterWeight // -std::string XdsApi::Route::Matchers::ToString() const { - std::vector contents; - contents.push_back( - absl::StrFormat("PathMatcher{%s}", path_matcher.ToString())); - for (const HeaderMatcher& header_matcher : header_matchers) { - contents.push_back(header_matcher.ToString()); - } - if (fraction_per_million.has_value()) { - contents.push_back(absl::StrFormat("Fraction Per Million %d", - fraction_per_million.value())); - } - return absl::StrJoin(contents, "\n"); -} - -std::string XdsApi::Route::ClusterWeight::ToString() const { +std::string XdsApi::Route::RouteAction::ClusterWeight::ToString() const { std::vector contents; contents.push_back(absl::StrCat("cluster=", name)); contents.push_back(absl::StrCat("weight=", weight)); @@ -246,15 +260,17 @@ std::string XdsApi::Route::ClusterWeight::ToString() const { return absl::StrCat("{", absl::StrJoin(contents, ", "), "}"); } -std::string XdsApi::Route::ToString() const { +// +// XdsApi::Route::RouteAction +// + +std::string XdsApi::Route::RouteAction::ToString() const { std::vector contents; - contents.push_back(matchers.ToString()); for (const HashPolicy& hash_policy : hash_policies) { contents.push_back(absl::StrCat("hash_policy=", hash_policy.ToString())); } if (retry_policy.has_value()) { - contents.push_back( - absl::StrCat("retry_policy={", retry_policy->ToString(), "}")); + contents.push_back(absl::StrCat("retry_policy=", retry_policy->ToString())); } if (!cluster_name.empty()) { contents.push_back(absl::StrFormat("Cluster name: %s", cluster_name)); @@ -265,6 +281,25 @@ std::string XdsApi::Route::ToString() const { if (max_stream_duration.has_value()) { contents.push_back(max_stream_duration->ToString()); } + return absl::StrCat("{", absl::StrJoin(contents, ", "), "}"); +} + +// +// XdsApi::Route +// + +std::string XdsApi::Route::ToString() const { + std::vector contents; + contents.push_back(matchers.ToString()); + auto* route_action = absl::get_if(&action); + if (route_action != nullptr) { + contents.push_back(absl::StrCat("route=", route_action->ToString())); + } else if (absl::holds_alternative( + action)) { + contents.push_back("non_forwarding_action={}"); + } else { + contents.push_back("unknown_action={}"); + } if (!typed_per_filter_config.empty()) { contents.push_back("typed_per_filter_config={"); for (const auto& p : typed_per_filter_config) { @@ -1528,9 +1563,9 @@ XdsApi::Duration DurationParse(const google_protobuf_Duration* proto_duration) { grpc_error_handle RetryPolicyParse( const EncodingContext& context, const envoy_config_route_v3_RetryPolicy* retry_policy, - absl::optional* retry) { + absl::optional* retry) { std::vector errors; - XdsApi::Route::RetryPolicy retry_to_return; + XdsApi::RetryPolicy retry_to_return; auto retry_on = UpbStringToStdString( envoy_config_route_v3_RetryPolicy_retry_on(retry_policy)); std::vector codes = absl::StrSplit(retry_on, ','); @@ -1610,11 +1645,8 @@ grpc_error_handle RetryPolicyParse( grpc_error_handle RouteActionParse(const EncodingContext& context, const envoy_config_route_v3_Route* route_msg, - XdsApi::Route* route, bool* ignore_route) { - if (!envoy_config_route_v3_Route_has_route(route_msg)) { - return GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "No RouteAction found in route."); - } + XdsApi::Route::RouteAction* route, + bool* ignore_route) { const envoy_config_route_v3_RouteAction* route_action = envoy_config_route_v3_Route_route(route_msg); // Get the cluster or weighted_clusters in the RouteAction. @@ -1643,7 +1675,7 @@ grpc_error_handle RouteActionParse(const EncodingContext& context, for (size_t j = 0; j < clusters_size; ++j) { const envoy_config_route_v3_WeightedCluster_ClusterWeight* cluster_weight = clusters[j]; - XdsApi::Route::ClusterWeight cluster; + XdsApi::Route::RouteAction::ClusterWeight cluster; cluster.name = UpbStringToStdString( envoy_config_route_v3_WeightedCluster_ClusterWeight_name( cluster_weight)); @@ -1712,7 +1744,7 @@ grpc_error_handle RouteActionParse(const EncodingContext& context, for (size_t i = 0; i < size; ++i) { const envoy_config_route_v3_RouteAction_HashPolicy* hash_policy = hash_policies[i]; - XdsApi::Route::HashPolicy policy; + XdsApi::Route::RouteAction::HashPolicy policy; policy.terminal = envoy_config_route_v3_RouteAction_HashPolicy_terminal(hash_policy); const envoy_config_route_v3_RouteAction_HashPolicy_Header* header; @@ -1720,7 +1752,7 @@ grpc_error_handle RouteActionParse(const EncodingContext& context, filter_state; if ((header = envoy_config_route_v3_RouteAction_HashPolicy_header( hash_policy)) != nullptr) { - policy.type = XdsApi::Route::HashPolicy::Type::HEADER; + policy.type = XdsApi::Route::RouteAction::HashPolicy::Type::HEADER; policy.header_name = UpbStringToStdString( envoy_config_route_v3_RouteAction_HashPolicy_Header_header_name( header)); @@ -1764,7 +1796,7 @@ grpc_error_handle RouteActionParse(const EncodingContext& context, envoy_config_route_v3_RouteAction_HashPolicy_FilterState_key( filter_state)); if (key == "io.grpc.channel_id") { - policy.type = XdsApi::Route::HashPolicy::Type::CHANNEL_ID; + policy.type = XdsApi::Route::RouteAction::HashPolicy::Type::CHANNEL_ID; } else { gpr_log(GPR_DEBUG, "RouteAction HashPolicy contains policy specifier " @@ -1783,7 +1815,7 @@ grpc_error_handle RouteActionParse(const EncodingContext& context, const envoy_config_route_v3_RetryPolicy* retry_policy = envoy_config_route_v3_RouteAction_retry_policy(route_action); if (retry_policy != nullptr) { - absl::optional retry; + absl::optional retry; grpc_error_handle error = RetryPolicyParse(context, retry_policy, &retry); if (error != GRPC_ERROR_NONE) return error; route->retry_policy = retry; @@ -1833,7 +1865,7 @@ grpc_error_handle RouteConfigParse( if (error != GRPC_ERROR_NONE) return error; } // Parse retry policy. - absl::optional virtual_host_retry_policy; + absl::optional virtual_host_retry_policy; const envoy_config_route_v3_RetryPolicy* retry_policy = envoy_config_route_v3_VirtualHost_retry_policy(virtual_hosts[i]); if (retry_policy != nullptr) { @@ -1872,11 +1904,21 @@ grpc_error_handle RouteConfigParse( if (error != GRPC_ERROR_NONE) return error; error = RouteRuntimeFractionParse(match, &route); if (error != GRPC_ERROR_NONE) return error; - error = RouteActionParse(context, routes[j], &route, &ignore_route); - if (error != GRPC_ERROR_NONE) return error; - if (ignore_route) continue; - if (route.retry_policy == absl::nullopt && retry_policy != nullptr) { - route.retry_policy = virtual_host_retry_policy; + if (envoy_config_route_v3_Route_has_route(routes[j])) { + route.action.emplace(); + auto& route_action = + absl::get(route.action); + error = + RouteActionParse(context, routes[j], &route_action, &ignore_route); + if (error != GRPC_ERROR_NONE) return error; + if (ignore_route) continue; + if (route_action.retry_policy == absl::nullopt && + retry_policy != nullptr) { + route_action.retry_policy = virtual_host_retry_policy; + } + } else if (envoy_config_route_v3_Route_has_non_forwarding_action( + routes[j])) { + route.action.emplace(); } if (context.use_v3) { grpc_error_handle error = ParseTypedPerFilterConfig< @@ -2233,32 +2275,47 @@ grpc_error_handle HttpConnectionManagerParse( absl::StrFormat("Filter %s is not supported on %s", filter_type, is_client ? "clients" : "servers")); } - if (i < num_filters - 1) { + absl::StatusOr filter_config = + filter_impl->GenerateFilterConfig(google_protobuf_Any_value(any), + context.arena); + if (!filter_config.ok()) { + return GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat( + "filter config for type ", filter_type, + " failed to parse: ", filter_config.status().ToString())); + } + http_connection_manager->http_filters.emplace_back( + XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter{ + std::string(name), std::move(*filter_config)}); + } + if (http_connection_manager->http_filters.empty()) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Expected at least one HTTP filter"); + } + // Make sure that the last filter is terminal and non-last filters are + // non-terminal. Note that this check is being performed in a separate loop + // to take care of the case where there are two terminal filters in the list + // out of which only one gets added in the final list. + for (const auto& http_filter : http_connection_manager->http_filters) { + const XdsHttpFilterImpl* filter_impl = + XdsHttpFilterRegistry::GetFilterForType( + http_filter.config.config_proto_type_name); + if (&http_filter != &http_connection_manager->http_filters.back()) { // Filters before the last filter must not be terminal. if (filter_impl->IsTerminalFilter()) { return GRPC_ERROR_CREATE_FROM_CPP_STRING( - absl::StrCat("terminal filter for config type ", filter_type, + absl::StrCat("terminal filter for config type ", + http_filter.config.config_proto_type_name, " must be the last filter in the chain")); } } else { // The last filter must be terminal. if (!filter_impl->IsTerminalFilter()) { return GRPC_ERROR_CREATE_FROM_CPP_STRING( - absl::StrCat("non-terminal filter for config type ", filter_type, + absl::StrCat("non-terminal filter for config type ", + http_filter.config.config_proto_type_name, " is the last filter in the chain")); } } - absl::StatusOr filter_config = - filter_impl->GenerateFilterConfig(google_protobuf_Any_value(any), - context.arena); - if (!filter_config.ok()) { - return GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat( - "filter config for type ", filter_type, - " failed to parse: ", filter_config.status().ToString())); - } - http_connection_manager->http_filters.emplace_back( - XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter{ - std::string(name), std::move(*filter_config)}); } } else { // If using a v2 config, we just hard-code a list containing only the @@ -2269,7 +2326,10 @@ grpc_error_handle HttpConnectionManagerParse( XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter{ "router", {kXdsHttpRouterFilterConfigName, Json()}}); } - if (is_client) { + // Guarding parsing of RouteConfig on the server side with the environmental + // variable since that's the first feature on the server side that will be + // using this. + if (is_client || XdsRbacEnabled()) { // Found inlined route_config. Parse it to find the cluster_name. if (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_route_config( http_connection_manager_proto)) { @@ -2504,6 +2564,8 @@ grpc_error_handle FilterChainParse( filter_chain_match, &filter_chain->filter_chain_match); if (error != GRPC_ERROR_NONE) errors.push_back(error); } + filter_chain->filter_chain_data = + std::make_shared(); // Parse the filters list. Currently we only support HttpConnectionManager. size_t size = 0; auto* filters = @@ -2539,8 +2601,6 @@ grpc_error_handle FilterChainParse( "Could not parse HttpConnectionManager config from filter " "typed_config")); } else { - filter_chain->filter_chain_data = - std::make_shared(); grpc_error_handle error = HttpConnectionManagerParse( false /* is_client */, context, http_connection_manager, is_v2, &filter_chain->filter_chain_data->http_connection_manager); diff --git a/src/core/ext/xds/xds_api.h b/src/core/ext/xds/xds_api.h index c469347b319..b163af57823 100644 --- a/src/core/ext/xds/xds_api.h +++ b/src/core/ext/xds/xds_api.h @@ -27,6 +27,7 @@ #include "absl/container/inlined_vector.h" #include "absl/types/optional.h" +#include "absl/types/variant.h" #include "envoy/admin/v3/config_dump.upb.h" #include "re2/re2.h" #include "upb/def.hpp" @@ -65,6 +66,29 @@ class XdsApi { using TypedPerFilterConfig = std::map; + struct RetryPolicy { + internal::StatusCodeSet retry_on; + uint32_t num_retries; + + struct RetryBackOff { + Duration base_interval; + Duration max_interval; + + bool operator==(const RetryBackOff& other) const { + return base_interval == other.base_interval && + max_interval == other.max_interval; + } + std::string ToString() const; + }; + RetryBackOff retry_back_off; + + bool operator==(const RetryPolicy& other) const { + return (retry_on == other.retry_on && num_retries == other.num_retries && + retry_back_off == other.retry_back_off); + } + std::string ToString() const; + }; + // TODO(donnadionne): When we can use absl::variant<>, consider using that // for: PathMatcher, HeaderMatcher, cluster_name and weighted_clusters struct Route { @@ -82,85 +106,83 @@ class XdsApi { std::string ToString() const; }; - struct HashPolicy { - enum Type { HEADER, CHANNEL_ID }; - Type type; - bool terminal = false; - // Fields used for type HEADER. - std::string header_name; - std::unique_ptr regex = nullptr; - std::string regex_substitution; + Matchers matchers; + + struct UnknownAction { + bool operator==(const UnknownAction& /* other */) const { return true; } + }; - HashPolicy() {} + struct RouteAction { + struct HashPolicy { + enum Type { HEADER, CHANNEL_ID }; + Type type; + bool terminal = false; + // Fields used for type HEADER. + std::string header_name; + std::unique_ptr regex = nullptr; + std::string regex_substitution; - // Copyable. - HashPolicy(const HashPolicy& other); - HashPolicy& operator=(const HashPolicy& other); + HashPolicy() {} - // Moveable. - HashPolicy(HashPolicy&& other) noexcept; - HashPolicy& operator=(HashPolicy&& other) noexcept; + // Copyable. + HashPolicy(const HashPolicy& other); + HashPolicy& operator=(const HashPolicy& other); - bool operator==(const HashPolicy& other) const; - std::string ToString() const; - }; - Matchers matchers; - std::vector hash_policies; + // Moveable. + HashPolicy(HashPolicy&& other) noexcept; + HashPolicy& operator=(HashPolicy&& other) noexcept; - struct RetryPolicy { - internal::StatusCodeSet retry_on; - uint32_t num_retries; + bool operator==(const HashPolicy& other) const; + std::string ToString() const; + }; - struct RetryBackOff { - Duration base_interval; - Duration max_interval; + struct ClusterWeight { + std::string name; + uint32_t weight; + TypedPerFilterConfig typed_per_filter_config; - bool operator==(const RetryBackOff& other) const { - return base_interval == other.base_interval && - max_interval == other.max_interval; + bool operator==(const ClusterWeight& other) const { + return name == other.name && weight == other.weight && + typed_per_filter_config == other.typed_per_filter_config; } std::string ToString() const; }; - RetryBackOff retry_back_off; - bool operator==(const RetryPolicy& other) const { - return (retry_on == other.retry_on && - num_retries == other.num_retries && - retry_back_off == other.retry_back_off); + std::vector hash_policies; + absl::optional retry_policy; + + // Action for this route. + // TODO(roth): When we can use absl::variant<>, consider using that + // here, to enforce the fact that only one of the two fields can be set. + std::string cluster_name; + std::vector weighted_clusters; + // Storing the timeout duration from route action: + // RouteAction.max_stream_duration.grpc_timeout_header_max or + // RouteAction.max_stream_duration.max_stream_duration if the former is + // not set. + absl::optional max_stream_duration; + + bool operator==(const RouteAction& other) const { + return hash_policies == other.hash_policies && + retry_policy == other.retry_policy && + cluster_name == other.cluster_name && + weighted_clusters == other.weighted_clusters && + max_stream_duration == other.max_stream_duration; } std::string ToString() const; }; - absl::optional retry_policy; - - // Action for this route. - // TODO(roth): When we can use absl::variant<>, consider using that - // here, to enforce the fact that only one of the two fields can be set. - std::string cluster_name; - struct ClusterWeight { - std::string name; - uint32_t weight; - TypedPerFilterConfig typed_per_filter_config; - bool operator==(const ClusterWeight& other) const { - return name == other.name && weight == other.weight && - typed_per_filter_config == other.typed_per_filter_config; + struct NonForwardingAction { + bool operator==(const NonForwardingAction& /* other */) const { + return true; } - std::string ToString() const; }; - std::vector weighted_clusters; - // Storing the timeout duration from route action: - // RouteAction.max_stream_duration.grpc_timeout_header_max or - // RouteAction.max_stream_duration.max_stream_duration if the former is - // not set. - absl::optional max_stream_duration; + absl::variant action; TypedPerFilterConfig typed_per_filter_config; bool operator==(const Route& other) const { - return matchers == other.matchers && cluster_name == other.cluster_name && - retry_policy == other.retry_policy && - weighted_clusters == other.weighted_clusters && - max_stream_duration == other.max_stream_duration && + return matchers == other.matchers && action == other.action && typed_per_filter_config == other.typed_per_filter_config; } std::string ToString() const; diff --git a/src/proto/grpc/testing/xds/v3/route.proto b/src/proto/grpc/testing/xds/v3/route.proto index 8b0bd1a5c14..7109fe21db1 100644 --- a/src/proto/grpc/testing/xds/v3/route.proto +++ b/src/proto/grpc/testing/xds/v3/route.proto @@ -103,12 +103,21 @@ message Route { // Route matching parameters. RouteMatch match = 1; + message NonForwardingAction { + } + oneof action { // Route request to some upstream cluster. RouteAction route = 2; // Return a redirect. RedirectAction redirect = 3; + + // An action used when the route will generate a response directly, + // without forwarding to an upstream host. This will be used in non-proxy + // xDS clients like the gRPC server. It could also be used in the future + // in Envoy for a filter that directly generates responses for requests. + NonForwardingAction non_forwarding_action = 18; } // The typed_per_filter_config field can be used to provide route-specific diff --git a/test/cpp/end2end/xds/xds_end2end_test.cc b/test/cpp/end2end/xds/xds_end2end_test.cc index 66553e715d5..17057270a5a 100644 --- a/test/cpp/end2end/xds/xds_end2end_test.cc +++ b/test/cpp/end2end/xds/xds_end2end_test.cc @@ -146,6 +146,8 @@ constexpr char kLbDropType[] = "lb"; constexpr char kThrottleDropType[] = "throttle"; constexpr char kServerName[] = "server.example.com"; constexpr char kDefaultRouteConfigurationName[] = "route_config_name"; +constexpr char kDefaultServerRouteConfigurationName[] = + "default_server_route_config_name"; constexpr char kDefaultClusterName[] = "cluster_name"; constexpr char kDefaultEdsServiceName[] = "eds_service_name"; constexpr int kDefaultLocalityWeight = 3; @@ -571,10 +573,11 @@ std::shared_ptr CreateTlsFallbackCredentials() { class NoOpHttpFilter : public grpc_core::XdsHttpFilterImpl { public: NoOpHttpFilter(std::string name, bool supported_on_clients, - bool supported_on_servers) + bool supported_on_servers, bool is_terminal_filter) : name_(std::move(name)), supported_on_clients_(supported_on_clients), - supported_on_servers_(supported_on_servers) {} + supported_on_servers_(supported_on_servers), + is_terminal_filter_(is_terminal_filter) {} void PopulateSymtab(upb_symtab* /* symtab */) const override {} @@ -603,10 +606,13 @@ class NoOpHttpFilter : public grpc_core::XdsHttpFilterImpl { bool IsSupportedOnServers() const override { return supported_on_servers_; } + bool IsTerminalFilter() const override { return is_terminal_filter_; } + private: const std::string name_; const bool supported_on_clients_; const bool supported_on_servers_; + const bool is_terminal_filter_; }; // There is slight difference between time fetched by GPR and by C++ system @@ -715,6 +721,31 @@ class XdsEnd2endTest : public ::testing::TestWithParam { if (GetParam().enable_load_reporting()) { default_cluster_.mutable_lrs_server()->mutable_self(); } + // Construct a default server-side RDS resource for tests to use. + default_server_route_config_.set_name(kDefaultServerRouteConfigurationName); + virtual_host = default_server_route_config_.add_virtual_hosts(); + virtual_host->add_domains("*"); + route = virtual_host->add_routes(); + route->mutable_match()->set_prefix(""); + route->mutable_non_forwarding_action(); + // Construct a default server-side Listener resource + default_server_listener_.mutable_address() + ->mutable_socket_address() + ->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); + default_server_listener_.mutable_default_filter_chain() + ->add_filters() + ->mutable_typed_config() + ->PackFrom(http_connection_manager); + // Create the backends but don't start them yet. We need to create the + // backends to allocate the ports, so that we know what resource names to + // populate in the xDS servers when we start them. However, we can't start + // the backends until after we've started the xDS servers, because in the + // tests that use xDS-enabled servers, the backends will try to contact the + // xDS servers as soon as they start up. + for (size_t i = 0; i < num_backends_; ++i) { + backends_.emplace_back( + new BackendServerThread(this, use_xds_enabled_server_)); + } // Start the load balancers. for (size_t i = 0; i < num_balancers_; ++i) { balancers_.emplace_back(new BalancerServerThread( @@ -725,6 +756,13 @@ class XdsEnd2endTest : public ::testing::TestWithParam { // Initialize resources. SetListenerAndRouteConfiguration(i, default_listener_, default_route_config_); + if (use_xds_enabled_server_) { + for (const auto& backend : backends_) { + SetServerListenerNameAndRouteConfiguration( + i, default_server_listener_, backend->port(), + default_server_route_config_); + } + } balancers_.back()->ads_service()->SetCdsResource(default_cluster_); } // Create fake resolver response generators used by client. @@ -773,11 +811,9 @@ class XdsEnd2endTest : public ::testing::TestWithParam { // args for the xDS channel. grpc_core::internal::UnsetGlobalXdsClientForTest(); } - // Start the backends. - for (size_t i = 0; i < num_backends_; ++i) { - backends_.emplace_back( - new BackendServerThread(this, use_xds_enabled_server_)); - backends_.back()->Start(); + // Start the backends + for (const auto& backend : backends_) { + backend->Start(); } // Create channel and stub. ResetStub(); @@ -1332,12 +1368,65 @@ class XdsEnd2endTest : public ::testing::TestWithParam { return ads_service->lds_response_state(); } + Listener PopulateServerListenerNameAndPort(const Listener& listener_template, + int port) { + Listener listener = listener_template; + listener.set_name( + absl::StrCat("grpc/server?xds.resource.listening_address=", + ipv6_only_ ? "[::1]:" : "127.0.0.1:", port)); + listener.mutable_address()->mutable_socket_address()->set_port_value(port); + return listener; + } + + // Interface for accessing HttpConnectionManager config in Listener. + class HcmAccessor { + public: + virtual ~HcmAccessor() = default; + virtual HttpConnectionManager Unpack(const Listener& listener) const = 0; + virtual void Pack(const HttpConnectionManager& hcm, + Listener* listener) const = 0; + }; + + // Client-side impl. + class ClientHcmAccessor : public HcmAccessor { + public: + HttpConnectionManager Unpack(const Listener& listener) const override { + HttpConnectionManager http_connection_manager; + listener.api_listener().api_listener().UnpackTo(&http_connection_manager); + return http_connection_manager; + } + void Pack(const HttpConnectionManager& hcm, + Listener* listener) const override { + auto* api_listener = + listener->mutable_api_listener()->mutable_api_listener(); + api_listener->PackFrom(hcm); + } + }; + + // Server-side impl. + class ServerHcmAccessor : public HcmAccessor { + public: + HttpConnectionManager Unpack(const Listener& listener) const override { + HttpConnectionManager http_connection_manager; + listener.default_filter_chain().filters().at(0).typed_config().UnpackTo( + &http_connection_manager); + return http_connection_manager; + } + void Pack(const HttpConnectionManager& hcm, + Listener* listener) const override { + listener->mutable_default_filter_chain() + ->mutable_filters() + ->at(0) + .mutable_typed_config() + ->PackFrom(hcm); + } + }; + void SetListenerAndRouteConfiguration( - int idx, Listener listener, const RouteConfiguration& route_config) { - auto* api_listener = - listener.mutable_api_listener()->mutable_api_listener(); - HttpConnectionManager http_connection_manager; - api_listener->UnpackTo(&http_connection_manager); + int idx, Listener listener, const RouteConfiguration& route_config, + const HcmAccessor& hcm_accessor = ClientHcmAccessor()) { + HttpConnectionManager http_connection_manager = + hcm_accessor.Unpack(listener); if (GetParam().enable_rds_testing()) { auto* rds = http_connection_manager.mutable_rds(); rds->set_route_config_name(kDefaultRouteConfigurationName); @@ -1346,10 +1435,18 @@ class XdsEnd2endTest : public ::testing::TestWithParam { } else { *http_connection_manager.mutable_route_config() = route_config; } - api_listener->PackFrom(http_connection_manager); + hcm_accessor.Pack(http_connection_manager, &listener); balancers_[idx]->ads_service()->SetLdsResource(listener); } + void SetServerListenerNameAndRouteConfiguration( + int idx, Listener listener, int port, + const RouteConfiguration& route_config) { + SetListenerAndRouteConfiguration( + idx, PopulateServerListenerNameAndPort(listener, port), route_config, + ServerHcmAccessor()); + } + void SetRouteConfiguration(int idx, const RouteConfiguration& route_config, const Listener* listener_to_copy = nullptr) { if (GetParam().enable_rds_testing()) { @@ -1845,6 +1942,8 @@ class XdsEnd2endTest : public ::testing::TestWithParam { Listener default_listener_; RouteConfiguration default_route_config_; + Listener default_server_listener_; + RouteConfiguration default_server_route_config_; Cluster default_cluster_; bool use_xds_enabled_server_; bool bootstrap_contents_from_env_var_; @@ -2761,8 +2860,12 @@ TEST_P(LdsTest, NacksTerminalFilterBeforeEndOfList) { HttpConnectionManager http_connection_manager; listener.mutable_api_listener()->mutable_api_listener()->UnpackTo( &http_connection_manager); - *http_connection_manager.add_http_filters() = - http_connection_manager.http_filters(0); + // The default_listener_ has a terminal router filter by default. Add an + // additional filter. + auto* filter = http_connection_manager.add_http_filters(); + filter->set_name("grpc.testing.terminal_http_filter"); + filter->mutable_typed_config()->set_type_url( + "grpc.testing.terminal_http_filter"); listener.mutable_api_listener()->mutable_api_listener()->PackFrom( http_connection_manager); SetListenerAndRouteConfiguration(0, listener, default_route_config_); @@ -3314,19 +3417,23 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPathRegex) { "path matcher: Invalid regex string specified in matcher.")); } -// Tests that LDS client should send a NACK if route has an action other than -// RouteAction in the LDS response. -TEST_P(LdsRdsTest, RouteHasNoRouteAction) { +// Tests that LDS client should fail RPCs with UNAVAILABLE status code if the +// matching route has an action other than RouteAction. +TEST_P(LdsRdsTest, MatchingRouteHasNoRouteAction) { RouteConfiguration route_config = default_route_config_; - route_config.mutable_virtual_hosts(0)->mutable_routes(0)->mutable_redirect(); + // Set a route with an inappropriate route action + auto* vhost = route_config.mutable_virtual_hosts(0); + vhost->mutable_routes(0)->mutable_redirect(); + // Add another route to make sure that the resolver code actually tries to + // match to a route instead of using a shorthand logic to error out. + auto* route = vhost->add_routes(); + route->mutable_match()->set_prefix(""); + route->mutable_route()->set_cluster(kDefaultClusterName); SetRouteConfiguration(0, route_config); SetNextResolution({}); SetNextResolutionForLbChannelAllBalancers(); - ASSERT_TRUE(WaitForRdsNack()) << "timed out waiting for NACK"; - const auto response_state = RouteConfigurationResponseState(0); - EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); - EXPECT_THAT(response_state.error_message, - ::testing::HasSubstr("No RouteAction found in route.")); + CheckRpcSendFailure(CheckRpcSendFailureOptions().set_expected_error_code( + StatusCode::UNAVAILABLE)); } TEST_P(LdsRdsTest, RouteActionClusterHasEmptyClusterName) { @@ -8149,28 +8256,14 @@ class XdsEnabledServerTest : public XdsEnd2endTest { } }; -TEST_P(XdsEnabledServerTest, Basic) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "::1" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); - balancers_[0]->ads_service()->SetLdsResource(listener); - WaitForBackend(0); -} +TEST_P(XdsEnabledServerTest, Basic) { WaitForBackend(0); } TEST_P(XdsEnabledServerTest, BadLdsUpdateNoApiListenerNorAddress) { - Listener listener; + Listener listener = default_server_listener_; + listener.clear_address(); listener.set_name( absl::StrCat("grpc/server?xds.resource.listening_address=", ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); balancers_[0]->ads_service()->SetLdsResource(listener); ASSERT_TRUE(WaitForLdsNack()) << "timed out waiting for NACK"; const auto response_state = @@ -8182,19 +8275,10 @@ TEST_P(XdsEnabledServerTest, BadLdsUpdateNoApiListenerNorAddress) { } TEST_P(XdsEnabledServerTest, BadLdsUpdateBothApiListenerAndAddress) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "::1" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; listener.mutable_api_listener(); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack()) << "timed out waiting for NACK"; const auto response_state = balancers_[0]->ads_service()->lds_response_state(); @@ -8205,16 +8289,11 @@ TEST_P(XdsEnabledServerTest, BadLdsUpdateBothApiListenerAndAddress) { } TEST_P(XdsEnabledServerTest, UnsupportedL4Filter) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "::1" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom(default_listener_ /* any proto object other than HttpConnectionManager */); - balancers_[0]->ads_service()->SetLdsResource(listener); + Listener listener = default_server_listener_; + listener.mutable_default_filter_chain()->clear_filters(); + listener.mutable_default_filter_chain()->add_filters()->mutable_typed_config()->PackFrom(default_listener_ /* any proto object other than HttpConnectionManager */); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); ASSERT_TRUE(WaitForLdsNack()) << "timed out waiting for NACK"; const auto response_state = balancers_[0]->ads_service()->lds_response_state(); @@ -8223,23 +8302,38 @@ TEST_P(XdsEnabledServerTest, UnsupportedL4Filter) { ::testing::HasSubstr("Unsupported filter type")); } +TEST_P(XdsEnabledServerTest, NacksEmptyHttpFilterList) { + Listener listener = default_server_listener_; + HttpConnectionManager http_connection_manager = + ServerHcmAccessor().Unpack(listener); + http_connection_manager.clear_http_filters(); + ServerHcmAccessor().Pack(http_connection_manager, &listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); + ASSERT_TRUE(WaitForLdsNack()) << "timed out waiting for NACK"; + const auto response_state = + balancers_[0]->ads_service()->lds_response_state(); + EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); + EXPECT_THAT(response_state.error_message, + ::testing::HasSubstr("Expected at least one HTTP filter")); +} + TEST_P(XdsEnabledServerTest, UnsupportedHttpFilter) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "::1" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - HttpConnectionManager http_connection_manager; + Listener listener = default_server_listener_; + HttpConnectionManager http_connection_manager = + ServerHcmAccessor().Unpack(listener); + http_connection_manager.clear_http_filters(); auto* http_filter = http_connection_manager.add_http_filters(); http_filter->set_name("grpc.testing.unsupported_http_filter"); http_filter->mutable_typed_config()->set_type_url( "grpc.testing.unsupported_http_filter"); - listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom( - http_connection_manager); - balancers_[0]->ads_service()->SetLdsResource(listener); + http_filter = http_connection_manager.add_http_filters(); + http_filter->set_name("router"); + http_filter->mutable_typed_config()->PackFrom( + envoy::extensions::filters::http::router::v3::Router()); + ServerHcmAccessor().Pack(http_connection_manager, &listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack()) << "timed out waiting for NACK"; const auto response_state = balancers_[0]->ads_service()->lds_response_state(); @@ -8250,15 +8344,10 @@ TEST_P(XdsEnabledServerTest, UnsupportedHttpFilter) { } TEST_P(XdsEnabledServerTest, HttpFilterNotSupportedOnServer) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "::1" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - HttpConnectionManager http_connection_manager; + Listener listener = default_server_listener_; + HttpConnectionManager http_connection_manager = + ServerHcmAccessor().Unpack(listener); + http_connection_manager.clear_http_filters(); auto* http_filter = http_connection_manager.add_http_filters(); http_filter->set_name("grpc.testing.client_only_http_filter"); http_filter->mutable_typed_config()->set_type_url( @@ -8267,9 +8356,9 @@ TEST_P(XdsEnabledServerTest, HttpFilterNotSupportedOnServer) { http_filter->set_name("router"); http_filter->mutable_typed_config()->PackFrom( envoy::extensions::filters::http::router::v3::Router()); - listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom( - http_connection_manager); - balancers_[0]->ads_service()->SetLdsResource(listener); + ServerHcmAccessor().Pack(http_connection_manager, &listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack()) << "timed out waiting for NACK"; const auto response_state = balancers_[0]->ads_service()->lds_response_state(); @@ -8282,23 +8371,22 @@ TEST_P(XdsEnabledServerTest, HttpFilterNotSupportedOnServer) { TEST_P(XdsEnabledServerTest, HttpFilterNotSupportedOnServerIgnoredWhenOptional) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "::1" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - HttpConnectionManager http_connection_manager; + Listener listener = default_server_listener_; + HttpConnectionManager http_connection_manager = + ServerHcmAccessor().Unpack(listener); + http_connection_manager.clear_http_filters(); auto* http_filter = http_connection_manager.add_http_filters(); http_filter->set_name("grpc.testing.client_only_http_filter"); http_filter->mutable_typed_config()->set_type_url( "grpc.testing.client_only_http_filter"); http_filter->set_is_optional(true); - listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom( - http_connection_manager); - balancers_[0]->ads_service()->SetLdsResource(listener); + http_filter = http_connection_manager.add_http_filters(); + http_filter->set_name("router"); + http_filter->mutable_typed_config()->PackFrom( + envoy::extensions::filters::http::router::v3::Router()); + ServerHcmAccessor().Pack(http_connection_manager, &listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); WaitForBackend(0); const auto response_state = balancers_[0]->ads_service()->lds_response_state(); @@ -8308,36 +8396,22 @@ TEST_P(XdsEnabledServerTest, // Verify that a mismatch of listening address results in "not serving" // status. TEST_P(XdsEnabledServerTest, ListenerAddressMismatch) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); + Listener listener = default_server_listener_; // Set a different listening address in the LDS update listener.mutable_address()->mutable_socket_address()->set_address( "192.168.1.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); backends_[0]->notifier()->WaitOnServingStatusChange( absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()), grpc::StatusCode::FAILED_PRECONDITION); } TEST_P(XdsEnabledServerTest, UseOriginalDstNotSupported) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "::1" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; listener.mutable_use_original_dst()->set_value(true); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack()) << "timed out waiting for NACK"; const auto response_state = balancers_[0]->ads_service()->lds_response_state(); @@ -8387,18 +8461,8 @@ class XdsServerSecurityTest : public XdsEnd2endTest { absl::string_view identity_instance_name, absl::string_view identity_certificate_name, bool require_client_certificates) { - Listener listener; - listener.set_name(absl::StrCat( - ipv6_only_ ? "grpc/server?xds.resource.listening_address=[::1]:" - : "grpc/server?xds.resource.listening_address=127.0.0.1:", - backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "[::1]" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; + auto* filter_chain = listener.mutable_default_filter_chain(); if (!identity_instance_name.empty()) { auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); @@ -8424,7 +8488,8 @@ class XdsServerSecurityTest : public XdsEnd2endTest { transport_socket->mutable_typed_config()->PackFrom( downstream_tls_context); } - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration( + 0, listener, backends_[0]->port(), default_server_route_config_); } std::shared_ptr CreateMtlsChannel() { @@ -8572,19 +8637,12 @@ class XdsServerSecurityTest : public XdsEnd2endTest { }; TEST_P(XdsServerSecurityTest, UnknownTransportSocket) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; + auto* filter_chain = listener.mutable_default_filter_chain(); auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("unknown_transport_socket"); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; const auto response_state = @@ -8596,16 +8654,8 @@ TEST_P(XdsServerSecurityTest, UnknownTransportSocket) { } TEST_P(XdsServerSecurityTest, NacksRequireSNI) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; + auto* filter_chain = listener.mutable_default_filter_chain(); auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); DownstreamTlsContext downstream_tls_context; @@ -8614,7 +8664,8 @@ TEST_P(XdsServerSecurityTest, NacksRequireSNI) { ->set_instance_name("fake_plugin1"); downstream_tls_context.mutable_require_sni()->set_value(true); transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; const auto response_state = @@ -8625,16 +8676,8 @@ TEST_P(XdsServerSecurityTest, NacksRequireSNI) { } TEST_P(XdsServerSecurityTest, NacksOcspStaplePolicyOtherThanLenientStapling) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; + auto* filter_chain = listener.mutable_default_filter_chain(); auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); DownstreamTlsContext downstream_tls_context; @@ -8645,7 +8688,8 @@ TEST_P(XdsServerSecurityTest, NacksOcspStaplePolicyOtherThanLenientStapling) { envoy::extensions::transport_sockets::tls::v3:: DownstreamTlsContext_OcspStaplePolicy_STRICT_STAPLING); transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; const auto response_state = @@ -8659,16 +8703,8 @@ TEST_P(XdsServerSecurityTest, NacksOcspStaplePolicyOtherThanLenientStapling) { TEST_P( XdsServerSecurityTest, NacksRequiringClientCertificateWithoutValidationCertificateProviderInstance) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; + auto* filter_chain = listener.mutable_default_filter_chain(); auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); DownstreamTlsContext downstream_tls_context; @@ -8677,7 +8713,8 @@ TEST_P( ->set_instance_name("fake_plugin1"); downstream_tls_context.mutable_require_client_certificate()->set_value(true); transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; const auto response_state = @@ -8691,21 +8728,14 @@ TEST_P( TEST_P(XdsServerSecurityTest, NacksTlsConfigurationWithoutIdentityProviderInstance) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; + auto* filter_chain = listener.mutable_default_filter_chain(); auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); DownstreamTlsContext downstream_tls_context; transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; const auto response_state = @@ -8717,16 +8747,8 @@ TEST_P(XdsServerSecurityTest, } TEST_P(XdsServerSecurityTest, NacksMatchSubjectAltNames) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; + auto* filter_chain = listener.mutable_default_filter_chain(); auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); DownstreamTlsContext downstream_tls_context; @@ -8738,7 +8760,8 @@ TEST_P(XdsServerSecurityTest, NacksMatchSubjectAltNames) { ->add_match_subject_alt_names() ->set_exact("*.test.google.fr"); transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; const auto response_state = @@ -8782,18 +8805,10 @@ TEST_P(XdsServerSecurityTest, FakeCertificateProvider::CertDataMap fake1_cert_map = { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; - Listener listener; - listener.set_name(absl::StrCat( - ipv6_only_ ? "grpc/server?xds.resource.listening_address=[::1]:" - : "grpc/server?xds.resource.listening_address=127.0.0.1:", - backends_[0]->port())); - listener.mutable_address()->mutable_socket_address()->set_address( - ipv6_only_ ? "[::1]" : "127.0.0.1"); - listener.mutable_address()->mutable_socket_address()->set_port_value( - backends_[0]->port()); - auto* filter_chain = listener.add_filter_chains(); - filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + Listener listener = default_server_listener_; + auto* filter_chain = listener.mutable_default_filter_chain(); + filter_chain->mutable_filters()->at(0).mutable_typed_config()->PackFrom( + ServerHcmAccessor().Unpack(listener)); auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); DownstreamTlsContext downstream_tls_context; @@ -8801,7 +8816,8 @@ TEST_P(XdsServerSecurityTest, ->mutable_tls_certificate_certificate_provider_instance() ->set_instance_name("fake_plugin1"); transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); SendRpc([this]() { return CreateTlsChannel(); }, server_authenticated_identity_, {}); } @@ -9047,13 +9063,11 @@ class XdsEnabledServerStatusNotificationTest : public XdsServerSecurityTest { void SetValidLdsUpdate() { SetLdsUpdate("", "", "", "", false); } void SetInvalidLdsUpdate() { - Listener listener; + Listener listener = default_server_listener_; + listener.clear_address(); listener.set_name(absl::StrCat( "grpc/server?xds.resource.listening_address=", ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); balancers_[0]->ads_service()->SetLdsResource(listener); } @@ -9209,63 +9223,37 @@ using XdsServerFilterChainMatchTest = XdsServerSecurityTest; TEST_P(XdsServerFilterChainMatchTest, DefaultFilterChainUsedWhenNoFilterChainMentioned) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); - listener.mutable_default_filter_chain() - ->add_filters() - ->mutable_typed_config() - ->PackFrom(HttpConnectionManager()); - balancers_[0]->ads_service()->SetLdsResource(listener); SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}); } TEST_P(XdsServerFilterChainMatchTest, DefaultFilterChainUsedWhenOtherFilterChainsDontMatch) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add a filter chain that will never get matched auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match() ->mutable_destination_port() ->set_value(8080); - // Add default filter chain that should get used - listener.mutable_default_filter_chain() - ->add_filters() - ->mutable_typed_config() - ->PackFrom(HttpConnectionManager()); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}); } TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithDestinationPortDontMatch) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with destination port that should never get matched auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match() ->mutable_destination_port() ->set_value(8080); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // RPC should fail since no matching filter chain was found and no default // filter chain is configured. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}, @@ -9273,19 +9261,15 @@ TEST_P(XdsServerFilterChainMatchTest, } TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithServerNamesDontMatch) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with server name that should never get matched auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->add_server_names("server_name"); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // RPC should fail since no matching filter chain was found and no default // filter chain is configured. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}, @@ -9294,19 +9278,15 @@ TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithServerNamesDontMatch) { TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithTransportProtocolsOtherThanRawBufferDontMatch) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with transport protocol "tls" that should never match auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_transport_protocol("tls"); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // RPC should fail since no matching filter chain was found and no default // filter chain is configured. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}, @@ -9315,19 +9295,15 @@ TEST_P(XdsServerFilterChainMatchTest, TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithApplicationProtocolsDontMatch) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with application protocol that should never get matched auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->add_application_protocols("h2"); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // RPC should fail since no matching filter chain was found and no default // filter chain is configured. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}, @@ -9336,26 +9312,22 @@ TEST_P(XdsServerFilterChainMatchTest, TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithTransportProtocolRawBufferIsPreferred) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with "raw_buffer" transport protocol auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_transport_protocol( "raw_buffer"); // Add another filter chain with no transport protocol set but application // protocol set (fails match) filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->add_application_protocols("h2"); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // A successful RPC proves that filter chains that mention "raw_buffer" as // the transport protocol are chosen as the best match in the round. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}); @@ -9363,18 +9335,12 @@ TEST_P(XdsServerFilterChainMatchTest, TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithMoreSpecificDestinationPrefixRangesArePreferred) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with prefix range (length 4 and 16) but with server name // mentioned. (Prefix range is matched first.) auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); auto* prefix_range = filter_chain->mutable_filter_chain_match()->add_prefix_ranges(); prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); @@ -9388,7 +9354,7 @@ TEST_P(XdsServerFilterChainMatchTest, // the highest match, it should be chosen. filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); prefix_range = filter_chain->mutable_filter_chain_match()->add_prefix_ranges(); prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); @@ -9401,7 +9367,7 @@ TEST_P(XdsServerFilterChainMatchTest, // 30) filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); prefix_range = filter_chain->mutable_filter_chain_match()->add_prefix_ranges(); prefix_range->set_address_prefix("192.168.1.1"); @@ -9410,9 +9376,11 @@ TEST_P(XdsServerFilterChainMatchTest, // Add another filter chain with no prefix range mentioned filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->add_server_names("server_name"); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // A successful RPC proves that the filter chain with the longest matching // prefix range was the best match. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}); @@ -9420,17 +9388,11 @@ TEST_P(XdsServerFilterChainMatchTest, TEST_P(XdsServerFilterChainMatchTest, FilterChainsThatMentionSourceTypeArePreferred) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with the local source type (best match) auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_source_type( FilterChainMatch::SAME_IP_OR_LOOPBACK); // Add filter chain with the external source type but bad source port. @@ -9438,7 +9400,7 @@ TEST_P(XdsServerFilterChainMatchTest, // because it is already being used by a backend. filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_source_type( FilterChainMatch::EXTERNAL); filter_chain->mutable_filter_chain_match()->add_source_ports( @@ -9446,10 +9408,12 @@ TEST_P(XdsServerFilterChainMatchTest, // Add filter chain with the default source type (ANY) but bad source port. filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->add_source_ports( backends_[0]->port()); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // A successful RPC proves that the filter chain with the longest matching // prefix range was the best match. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}); @@ -9457,20 +9421,14 @@ TEST_P(XdsServerFilterChainMatchTest, TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithMoreSpecificSourcePrefixRangesArePreferred) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with source prefix range (length 16) but with a bad // source port mentioned. (Prefix range is matched first.) Note that // backends_[0]->port() will never be a match for the source port because it // is already being used by a backend. auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); auto* source_prefix_range = filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges(); source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); @@ -9485,7 +9443,7 @@ TEST_P(XdsServerFilterChainMatchTest, // 24 is the highest match, it should be chosen. filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); source_prefix_range = filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges(); source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); @@ -9498,7 +9456,7 @@ TEST_P(XdsServerFilterChainMatchTest, // length 30) and bad source port filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); source_prefix_range = filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges(); source_prefix_range->set_address_prefix("192.168.1.1"); @@ -9509,10 +9467,12 @@ TEST_P(XdsServerFilterChainMatchTest, // source port filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->add_source_ports( backends_[0]->port()); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // A successful RPC proves that the filter chain with the longest matching // source prefix range was the best match. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}); @@ -9520,16 +9480,10 @@ TEST_P(XdsServerFilterChainMatchTest, TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithMoreSpecificSourcePortArePreferred) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); // Since we don't know which port will be used by the channel, just add all // ports except for 0. for (int i = 1; i < 65536; i++) { @@ -9539,7 +9493,7 @@ TEST_P(XdsServerFilterChainMatchTest, // DownstreamTlsContext configuration. filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); auto* transport_socket = filter_chain->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); DownstreamTlsContext downstream_tls_context; @@ -9547,29 +9501,26 @@ TEST_P(XdsServerFilterChainMatchTest, ->mutable_tls_certificate_provider_instance() ->set_instance_name("fake_plugin1"); transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context); - balancers_[0]->ads_service()->SetLdsResource(listener); + listener.clear_default_filter_chain(); + balancers_[0]->ads_service()->SetLdsResource( + PopulateServerListenerNameAndPort(listener, backends_[0]->port())); // A successful RPC proves that the filter chain with matching source port // was chosen. SendRpc([this]() { return CreateInsecureChannel(); }, {}, {}); } TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchNacked) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); // Add a duplicate filter chain filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); - balancers_[0]->ads_service()->SetLdsResource(listener); + ServerHcmAccessor().Unpack(listener)); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; EXPECT_THAT( @@ -9579,17 +9530,11 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchNacked) { } TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnPrefixRangesNacked) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with prefix range auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); auto* prefix_range = filter_chain->mutable_filter_chain_match()->add_prefix_ranges(); prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); @@ -9601,7 +9546,7 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnPrefixRangesNacked) { // Add a filter chain with a duplicate prefix range entry filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); prefix_range = filter_chain->mutable_filter_chain_match()->add_prefix_ranges(); prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); @@ -9610,7 +9555,8 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnPrefixRangesNacked) { filter_chain->mutable_filter_chain_match()->add_prefix_ranges(); prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); prefix_range->mutable_prefix_len()->set_value(32); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; if (ipv6_only_) { @@ -9631,27 +9577,22 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnPrefixRangesNacked) { } TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnTransportProtocolNacked) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with "raw_buffer" transport protocol auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_transport_protocol( "raw_buffer"); // Add a duplicate filter chain with the same "raw_buffer" transport // protocol entry filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_transport_protocol( "raw_buffer"); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; EXPECT_THAT( @@ -9661,26 +9602,21 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnTransportProtocolNacked) { } TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnLocalSourceTypeNacked) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with the local source type auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_source_type( FilterChainMatch::SAME_IP_OR_LOOPBACK); // Add a duplicate filter chain with the same local source type entry filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_source_type( FilterChainMatch::SAME_IP_OR_LOOPBACK); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; EXPECT_THAT( @@ -9691,26 +9627,21 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnLocalSourceTypeNacked) { TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnExternalSourceTypeNacked) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with the external source type auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_source_type( FilterChainMatch::EXTERNAL); // Add a duplicate filter chain with the same external source type entry filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->set_source_type( FilterChainMatch::EXTERNAL); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; EXPECT_THAT( @@ -9721,17 +9652,11 @@ TEST_P(XdsServerFilterChainMatchTest, TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnSourcePrefixRangesNacked) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with source prefix range auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); auto* prefix_range = filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges(); prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); @@ -9743,7 +9668,7 @@ TEST_P(XdsServerFilterChainMatchTest, // Add a filter chain with a duplicate source prefix range entry filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); prefix_range = filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges(); prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); @@ -9752,7 +9677,8 @@ TEST_P(XdsServerFilterChainMatchTest, filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges(); prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1"); prefix_range->mutable_prefix_len()->set_value(32); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; if (ipv6_only_) { @@ -9774,24 +9700,19 @@ TEST_P(XdsServerFilterChainMatchTest, } TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnSourcePortNacked) { - Listener listener; - listener.set_name( - absl::StrCat("grpc/server?xds.resource.listening_address=", - ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port())); - auto* socket_address = listener.mutable_address()->mutable_socket_address(); - socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1"); - socket_address->set_port_value(backends_[0]->port()); + Listener listener = default_server_listener_; // Add filter chain with the external source type auto* filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->add_source_ports(8080); // Add a duplicate filter chain with the same source port entry filter_chain = listener.add_filter_chains(); filter_chain->add_filters()->mutable_typed_config()->PackFrom( - HttpConnectionManager()); + ServerHcmAccessor().Unpack(listener)); filter_chain->mutable_filter_chain_match()->add_source_ports(8080); - balancers_[0]->ads_service()->SetLdsResource(listener); + SetServerListenerNameAndRouteConfiguration(0, listener, backends_[0]->port(), + default_server_route_config_); ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) << "timed out waiting for NACK"; EXPECT_THAT( @@ -9800,6 +9721,65 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnSourcePortNacked) { "filter chain: {source_ports={8080}}")); } +class XdsServerRdsTest : public XdsServerSecurityTest { + protected: + static void SetUpTestSuite() { + gpr_setenv("GRPC_XDS_EXPERIMENTAL_RBAC", "true"); + } + + static void TearDownTestSuite() { + gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_RBAC"); + } +}; + +TEST_P(XdsServerRdsTest, NacksInvalidDomainPattern) { + RouteConfiguration route_config = default_server_route_config_; + route_config.mutable_virtual_hosts()->at(0).add_domains(""); + SetServerListenerNameAndRouteConfiguration( + 0, default_server_listener_, backends_[0]->port(), route_config); + ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) + << "timed out waiting for NACK"; + EXPECT_THAT(balancers_[0]->ads_service()->lds_response_state().error_message, + ::testing::HasSubstr("Invalid domain pattern \"\"")); +} + +TEST_P(XdsServerRdsTest, NacksEmptyDomainsList) { + RouteConfiguration route_config = default_server_route_config_; + route_config.mutable_virtual_hosts()->at(0).clear_domains(); + SetServerListenerNameAndRouteConfiguration( + 0, default_server_listener_, backends_[0]->port(), route_config); + ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) + << "timed out waiting for NACK"; + EXPECT_THAT(balancers_[0]->ads_service()->lds_response_state().error_message, + ::testing::HasSubstr("VirtualHost has no domains")); +} + +TEST_P(XdsServerRdsTest, NacksEmptyRoutesList) { + RouteConfiguration route_config = default_server_route_config_; + route_config.mutable_virtual_hosts()->at(0).clear_routes(); + SetServerListenerNameAndRouteConfiguration( + 0, default_server_listener_, backends_[0]->port(), route_config); + ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) + << "timed out waiting for NACK"; + EXPECT_THAT(balancers_[0]->ads_service()->lds_response_state().error_message, + ::testing::HasSubstr("No route found in the virtual host")); +} + +TEST_P(XdsServerRdsTest, NacksEmptyMatch) { + RouteConfiguration route_config = default_server_route_config_; + route_config.mutable_virtual_hosts() + ->at(0) + .mutable_routes() + ->at(0) + .clear_match(); + SetServerListenerNameAndRouteConfiguration( + 0, default_server_listener_, backends_[0]->port(), route_config); + ASSERT_TRUE(WaitForLdsNack(StatusCode::DEADLINE_EXCEEDED)) + << "timed out waiting for NACK"; + EXPECT_THAT(balancers_[0]->ads_service()->lds_response_state().error_message, + ::testing::HasSubstr("Match can't be null")); +} + using EdsTest = BasicTest; // Tests that EDS client should send a NACK if the EDS update contains @@ -12499,6 +12479,15 @@ INSTANTIATE_TEST_SUITE_P(XdsTest, XdsServerFilterChainMatchTest, .set_use_xds_credentials()), &TestTypeName); +// We are only testing the server here. +// TODO(yashykt): Also add a test type with set_enable_rds_testing() once we +// start fetching non-inline resources. +INSTANTIATE_TEST_SUITE_P(XdsTest, XdsServerRdsTest, + ::testing::Values(TestType() + .set_use_fake_resolver() + .set_use_xds_credentials()), + &TestTypeName); + // EDS could be tested with or without XdsResolver, but the tests would // be the same either way, so we test it only with XdsResolver. INSTANTIATE_TEST_SUITE_P( @@ -12660,12 +12649,22 @@ int main(int argc, char** argv) { grpc_init(); grpc_core::XdsHttpFilterRegistry::RegisterFilter( absl::make_unique( - "grpc.testing.client_only_http_filter", true, false), + "grpc.testing.client_only_http_filter", + /* supported_on_clients = */ true, /* supported_on_servers = */ false, + /* is_terminal_filter */ false), {"grpc.testing.client_only_http_filter"}); grpc_core::XdsHttpFilterRegistry::RegisterFilter( absl::make_unique( - "grpc.testing.server_only_http_filter", false, true), + "grpc.testing.server_only_http_filter", + /* supported_on_clients = */ false, /* supported_on_servers = */ true, + /* is_terminal_filter */ false), {"grpc.testing.server_only_http_filter"}); + grpc_core::XdsHttpFilterRegistry::RegisterFilter( + absl::make_unique( + "grpc.testing.terminal_http_filter", + /* supported_on_clients = */ true, /* supported_on_servers = */ true, + /* is_terminal_filter */ true), + {"grpc.testing.terminal_http_filter"}); const auto result = RUN_ALL_TESTS(); grpc_shutdown(); return result;