From 72a42151edcf6d60da129d8baa264281fbeda137 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 1 May 2020 07:23:01 -0700 Subject: [PATCH] xds: Check RDS ConfigSource in LDS response. --- .../ext/filters/client_channel/xds/xds_api.cc | 14 +++++- test/cpp/end2end/xds_end2end_test.cc | 46 ++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/core/ext/filters/client_channel/xds/xds_api.cc b/src/core/ext/filters/client_channel/xds/xds_api.cc index 60ca930e060..f124052ce84 100644 --- a/src/core/ext/filters/client_channel/xds/xds_api.cc +++ b/src/core/ext/filters/client_channel/xds/xds_api.cc @@ -1174,10 +1174,22 @@ grpc_error* LdsResponseParse(XdsClient* client, TraceFlag* tracer, return GRPC_ERROR_CREATE_FROM_STATIC_STRING( "HttpConnectionManager neither has inlined route_config nor RDS."); } - // Get the route_config_name. const envoy_config_filter_network_http_connection_manager_v2_Rds* rds = envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_rds( http_connection_manager); + // Check that the ConfigSource specifies ADS. + const envoy_api_v2_core_ConfigSource* config_source = + envoy_config_filter_network_http_connection_manager_v2_Rds_config_source( + rds); + if (config_source == nullptr) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "HttpConnectionManager missing config_source for RDS."); + } + if (!envoy_api_v2_core_ConfigSource_has_ads(config_source)) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "HttpConnectionManager ConfigSource for RDS does not specify ADS."); + } + // Get the route_config_name. const upb_strview route_config_name = envoy_config_filter_network_http_connection_manager_v2_Rds_route_config_name( rds); diff --git a/test/cpp/end2end/xds_end2end_test.cc b/test/cpp/end2end/xds_end2end_test.cc index 5fb6a62b19d..7d70feadbad 100644 --- a/test/cpp/end2end/xds_end2end_test.cc +++ b/test/cpp/end2end/xds_end2end_test.cc @@ -713,8 +713,9 @@ class AdsServiceImpl : public AggregatedDiscoveryService::Service, void SetLdsToUseDynamicRds() { auto listener = default_listener_; HttpConnectionManager http_connection_manager; - http_connection_manager.mutable_rds()->set_route_config_name( - kDefaultResourceName); + auto* rds = http_connection_manager.mutable_rds(); + rds->set_route_config_name(kDefaultResourceName); + rds->mutable_config_source()->mutable_ads(); listener.mutable_api_listener()->mutable_api_listener()->PackFrom( http_connection_manager); SetLdsResource(listener, kDefaultResourceName); @@ -2191,6 +2192,47 @@ TEST_P(LdsTest, WrongRouteSpecifier) { "HttpConnectionManager neither has inlined route_config nor RDS."); } +// Tests that LDS client should send a NACK if the rds message in the +// http_connection_manager is missing the config_source field. +TEST_P(LdsTest, RdsMissingConfigSource) { + auto listener = balancers_[0]->ads_service()->default_listener(); + HttpConnectionManager http_connection_manager; + http_connection_manager.mutable_rds()->set_route_config_name( + kDefaultResourceName); + listener.mutable_api_listener()->mutable_api_listener()->PackFrom( + http_connection_manager); + balancers_[0]->ads_service()->SetLdsResource(listener, kDefaultResourceName); + SetNextResolution({}); + SetNextResolutionForLbChannelAllBalancers(); + CheckRpcSendFailure(); + const auto& response_state = + balancers_[0]->ads_service()->lds_response_state(); + EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); + EXPECT_EQ(response_state.error_message, + "HttpConnectionManager missing config_source for RDS."); +} + +// Tests that LDS client should send a NACK if the rds message in the +// http_connection_manager has a config_source field that does not specify ADS. +TEST_P(LdsTest, RdsConfigSourceDoesNotSpecifyAds) { + auto listener = balancers_[0]->ads_service()->default_listener(); + HttpConnectionManager http_connection_manager; + auto* rds = http_connection_manager.mutable_rds(); + rds->set_route_config_name(kDefaultResourceName); + rds->mutable_config_source()->mutable_self(); + listener.mutable_api_listener()->mutable_api_listener()->PackFrom( + http_connection_manager); + balancers_[0]->ads_service()->SetLdsResource(listener, kDefaultResourceName); + SetNextResolution({}); + SetNextResolutionForLbChannelAllBalancers(); + CheckRpcSendFailure(); + const auto& response_state = + balancers_[0]->ads_service()->lds_response_state(); + EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); + EXPECT_EQ(response_state.error_message, + "HttpConnectionManager ConfigSource for RDS does not specify ADS."); +} + using LdsRdsTest = BasicTest; // Tests that LDS client should send an ACK upon correct LDS response (with