Parse FilterChainMatch from LDS response (#25530)

Parse FilterChainMatch from LDS response
reviewable/pr25395/r2
Yash Tibrewal 4 years ago committed by GitHub
parent 4e9206f48c
commit 2794beb89c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 300
      src/core/ext/xds/xds_api.cc
  2. 66
      src/core/ext/xds/xds_api.h
  3. 18
      src/core/ext/xds/xds_server_config_fetcher.cc

@ -447,6 +447,78 @@ std::string XdsApi::LdsUpdate::HttpFilter::ToString() const {
return absl::StrCat("{name=", name, ", config=", config.ToString(), "}");
}
//
// XdsApi::LdsUpdate::FilterChain::FilterChainMatch::CidrRange
//
std::string
XdsApi::LdsUpdate::FilterChain::FilterChainMatch::CidrRange::ToString() const {
return absl::StrCat("{address_prefix=", address_prefix,
" prefix_len=", prefix_len, "}");
}
//
// XdsApi::LdsUpdate::FilterChain::FilterChainMatch
//
std::string XdsApi::LdsUpdate::FilterChain::FilterChainMatch::ToString() const {
absl::InlinedVector<std::string, 8> contents;
if (destination_port != 0) {
contents.push_back(absl::StrCat("destination_port=", destination_port));
}
if (!prefix_ranges.empty()) {
std::vector<std::string> prefix_ranges_content;
for (const auto& range : prefix_ranges) {
prefix_ranges_content.push_back(range.ToString());
}
contents.push_back(absl::StrCat(
"prefix_ranges={", absl::StrJoin(prefix_ranges_content, ", "), "}"));
}
if (source_type == XdsApi::LdsUpdate::FilterChain::FilterChainMatch::
ConnectionSourceType::kSameIpOrLoopback) {
contents.push_back("source_type=SAME_IP_OR_LOOPBACK");
} else if (source_type == XdsApi::LdsUpdate::FilterChain::FilterChainMatch::
ConnectionSourceType::kExternal) {
contents.push_back("source_type=EXTERNAL");
}
if (!source_prefix_ranges.empty()) {
std::vector<std::string> source_prefix_ranges_content;
for (const auto& range : source_prefix_ranges) {
source_prefix_ranges_content.push_back(range.ToString());
}
contents.push_back(
absl::StrCat("source_prefix_ranges={",
absl::StrJoin(source_prefix_ranges_content, ", "), "}"));
}
if (!source_ports.empty()) {
contents.push_back(
absl::StrCat("source_ports={", absl::StrJoin(source_ports, ", "), "}"));
}
if (!server_names.empty()) {
contents.push_back(
absl::StrCat("server_names={", absl::StrJoin(server_names, ", "), "}"));
}
if (!transport_protocol.empty()) {
contents.push_back(absl::StrCat("transport_protocol=", transport_protocol));
}
if (!application_protocols.empty()) {
contents.push_back(absl::StrCat("application_protocols={",
absl::StrJoin(application_protocols, ", "),
"}"));
}
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
//
// XdsApi::LdsUpdate::FilterChain
//
std::string XdsApi::LdsUpdate::FilterChain::ToString() const {
return absl::StrFormat("{filter_chain_match=%s, downstream_tls_context=%s}",
filter_chain_match.ToString(),
downstream_tls_context.ToString());
}
//
// XdsApi::LdsUpdate
//
@ -454,9 +526,15 @@ std::string XdsApi::LdsUpdate::HttpFilter::ToString() const {
std::string XdsApi::LdsUpdate::ToString() const {
absl::InlinedVector<std::string, 3> contents;
if (type == ListenerType::kTcpListener) {
if (!downstream_tls_context.Empty()) {
contents.push_back(absl::StrFormat("downstream_tls_context=%s",
downstream_tls_context.ToString()));
std::vector<std::string> filter_chains_content;
for (const auto& filter_chain : filter_chains) {
filter_chains_content.push_back(filter_chain.ToString());
}
contents.push_back(absl::StrCat(
"filter_chains={", absl::StrJoin(filter_chains_content, ", "), "}"));
if (default_filter_chain.has_value()) {
contents.push_back(absl::StrCat("default_filter_chain=",
default_filter_chain->ToString()));
}
} else if (type == ListenerType::kHttpApiListener) {
contents.push_back(absl::StrFormat(
@ -1677,71 +1755,183 @@ grpc_error* LdsResponseParseClient(
return GRPC_ERROR_NONE;
}
XdsApi::LdsUpdate::FilterChain::FilterChainMatch::CidrRange CidrRangeParse(
const envoy_config_core_v3_CidrRange* cidr_range_proto) {
uint32_t prefix_len = 0;
auto* prefix_len_proto =
envoy_config_core_v3_CidrRange_prefix_len(cidr_range_proto);
if (prefix_len_proto != nullptr) {
prefix_len = google_protobuf_UInt32Value_value(prefix_len_proto);
}
return {UpbStringToStdString(
envoy_config_core_v3_CidrRange_address_prefix(cidr_range_proto)),
prefix_len};
}
XdsApi::LdsUpdate::FilterChain::FilterChainMatch FilterChainMatchParse(
const envoy_config_listener_v3_FilterChainMatch* filter_chain_match_proto) {
XdsApi::LdsUpdate::FilterChain::FilterChainMatch filter_chain_match;
auto* destination_port =
envoy_config_listener_v3_FilterChainMatch_destination_port(
filter_chain_match_proto);
if (destination_port != nullptr) {
filter_chain_match.destination_port =
google_protobuf_UInt32Value_value(destination_port);
}
size_t size = 0;
auto* prefix_ranges = envoy_config_listener_v3_FilterChainMatch_prefix_ranges(
filter_chain_match_proto, &size);
filter_chain_match.prefix_ranges.reserve(size);
for (size_t i = 0; i < size; i++) {
filter_chain_match.prefix_ranges.push_back(
CidrRangeParse(prefix_ranges[i]));
}
filter_chain_match.source_type = static_cast<
XdsApi::LdsUpdate::FilterChain::FilterChainMatch::ConnectionSourceType>(
envoy_config_listener_v3_FilterChainMatch_source_type(
filter_chain_match_proto));
auto* source_prefix_ranges =
envoy_config_listener_v3_FilterChainMatch_source_prefix_ranges(
filter_chain_match_proto, &size);
filter_chain_match.source_prefix_ranges.reserve(size);
for (size_t i = 0; i < size; i++) {
filter_chain_match.source_prefix_ranges.push_back(
CidrRangeParse(source_prefix_ranges[i]));
}
auto* source_ports = envoy_config_listener_v3_FilterChainMatch_source_ports(
filter_chain_match_proto, &size);
filter_chain_match.source_ports.reserve(size);
for (size_t i = 0; i < size; i++) {
filter_chain_match.source_ports.push_back(source_ports[i]);
}
auto* server_names = envoy_config_listener_v3_FilterChainMatch_server_names(
filter_chain_match_proto, &size);
for (size_t i = 0; i < size; i++) {
filter_chain_match.server_names.push_back(
UpbStringToStdString(server_names[i]));
}
filter_chain_match.transport_protocol = UpbStringToStdString(
envoy_config_listener_v3_FilterChainMatch_transport_protocol(
filter_chain_match_proto));
auto* application_protocols =
envoy_config_listener_v3_FilterChainMatch_application_protocols(
filter_chain_match_proto, &size);
for (size_t i = 0; i < size; i++) {
filter_chain_match.application_protocols.push_back(
UpbStringToStdString(application_protocols[i]));
}
return filter_chain_match;
}
grpc_error* DownstreamTlsContextParse(
const EncodingContext& context,
const envoy_config_core_v3_TransportSocket* transport_socket,
XdsApi::DownstreamTlsContext* downstream_tls_context) {
absl::string_view name = UpbStringToAbsl(
envoy_config_core_v3_TransportSocket_name(transport_socket));
if (name == "envoy.transport_sockets.tls") {
auto* typed_config =
envoy_config_core_v3_TransportSocket_typed_config(transport_socket);
if (typed_config != nullptr) {
const upb_strview encoded_downstream_tls_context =
google_protobuf_Any_value(typed_config);
auto* downstream_tls_context_proto =
envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_parse(
encoded_downstream_tls_context.data,
encoded_downstream_tls_context.size, context.arena);
if (downstream_tls_context_proto == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Can't decode downstream tls context.");
}
auto* common_tls_context =
envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_common_tls_context(
downstream_tls_context_proto);
if (common_tls_context != nullptr) {
grpc_error* error = CommonTlsContextParse(
common_tls_context, &downstream_tls_context->common_tls_context);
if (error != GRPC_ERROR_NONE) return error;
}
auto* require_client_certificate =
envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_require_client_certificate(
downstream_tls_context_proto);
if (require_client_certificate != nullptr) {
downstream_tls_context->require_client_certificate =
google_protobuf_BoolValue_value(require_client_certificate);
}
}
if (downstream_tls_context->common_tls_context
.tls_certificate_certificate_provider_instance.instance_name
.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"TLS configuration provided but no "
"tls_certificate_certificate_provider_instance found.");
}
}
return GRPC_ERROR_NONE;
}
XdsApi::LdsUpdate::FilterChain FilterChainParse(
const EncodingContext& context,
const envoy_config_listener_v3_FilterChain* filter_chain_proto,
grpc_error** error) {
XdsApi::LdsUpdate::FilterChain filter_chain;
auto* filter_chain_match =
envoy_config_listener_v3_FilterChain_filter_chain_match(
filter_chain_proto);
if (filter_chain_match != nullptr) {
filter_chain.filter_chain_match = FilterChainMatchParse(filter_chain_match);
}
// Get the DownstreamTlsContext for the filter chain
if (XdsSecurityEnabled()) {
auto* transport_socket =
envoy_config_listener_v3_FilterChain_transport_socket(
filter_chain_proto);
if (transport_socket != nullptr) {
*error = DownstreamTlsContextParse(context, transport_socket,
&filter_chain.downstream_tls_context);
}
}
return filter_chain;
}
grpc_error* LdsResponseParseServer(
const EncodingContext& context,
const envoy_config_listener_v3_Listener* listener,
XdsApi::LdsUpdate* lds_update) {
lds_update->type = XdsApi::LdsUpdate::ListenerType::kTcpListener;
// TODO(yashykt): Support filter chain match.
// Right now, we are supporting and expecting only one entry in filter_chains.
// As part of this, we'll need to refactor the code to process the
// HttpConnectionManager config so that it is shared with the client-side
grpc_error* error = GRPC_ERROR_NONE;
// TODO(yashykt): As part of this, we'll need to refactor the code to process
// the HttpConnectionManager config so that it is shared with the client-side
// parsing.
size_t size = 0;
auto* filter_chains =
envoy_config_listener_v3_Listener_filter_chains(listener, &size);
if (size != 1) {
// TODO(yashykt): Remove following if block when FilterChainMatch
// implementation is in
if (size == 0) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Only one filter_chain supported.");
"At least one filter chain needed.");
}
// Get the DownstreamTlsContext from the match
if (XdsSecurityEnabled()) {
auto* transport_socket =
envoy_config_listener_v3_FilterChain_transport_socket(filter_chains[0]);
if (transport_socket != nullptr) {
absl::string_view name = UpbStringToAbsl(
envoy_config_core_v3_TransportSocket_name(transport_socket));
if (name == "envoy.transport_sockets.tls") {
auto* typed_config =
envoy_config_core_v3_TransportSocket_typed_config(transport_socket);
if (typed_config != nullptr) {
const upb_strview encoded_downstream_tls_context =
google_protobuf_Any_value(typed_config);
auto* downstream_tls_context =
envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_parse(
encoded_downstream_tls_context.data,
encoded_downstream_tls_context.size, context.arena);
if (downstream_tls_context == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Can't decode downstream tls context.");
}
auto* common_tls_context =
envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_common_tls_context(
downstream_tls_context);
if (common_tls_context != nullptr) {
grpc_error* error = CommonTlsContextParse(
common_tls_context,
&lds_update->downstream_tls_context.common_tls_context);
if (error != GRPC_ERROR_NONE) return error;
}
auto* require_client_certificate =
envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_require_client_certificate(
downstream_tls_context);
if (require_client_certificate != nullptr) {
lds_update->downstream_tls_context.require_client_certificate =
google_protobuf_BoolValue_value(require_client_certificate);
}
}
if (lds_update->downstream_tls_context.common_tls_context
.tls_certificate_certificate_provider_instance.instance_name
.empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"TLS configuration provided but no "
"tls_certificate_certificate_provider_instance found.");
}
}
lds_update->filter_chains.reserve(size);
for (size_t i = 0; i < size; i++) {
lds_update->filter_chains.push_back(
FilterChainParse(context, filter_chains[0], &error));
if (error != GRPC_ERROR_NONE) {
return error;
}
}
auto* default_filter_chain =
envoy_config_listener_v3_Listener_default_filter_chain(listener);
if (default_filter_chain != nullptr) {
lds_update->default_filter_chain =
FilterChainParse(context, default_filter_chain, &error);
if (error != GRPC_ERROR_NONE) {
return error;
}
}
if (size == 0 && default_filter_chain == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No filter chain provided.");
}
return GRPC_ERROR_NONE;
}

@ -219,7 +219,6 @@ class XdsApi {
kTcpListener = 0,
kHttpApiListener,
} type;
DownstreamTlsContext downstream_tls_context;
// The name to use in the RDS request.
std::string route_config_name;
// Storing the Http Connection Manager Common Http Protocol Option
@ -239,14 +238,73 @@ class XdsApi {
std::string ToString() const;
};
std::vector<HttpFilter> http_filters;
struct FilterChain {
struct FilterChainMatch {
uint32_t destination_port = 0;
struct CidrRange {
std::string address_prefix;
uint32_t prefix_len;
bool operator==(const CidrRange& other) const {
return address_prefix == other.address_prefix &&
prefix_len == other.prefix_len;
}
std::string ToString() const;
};
std::vector<CidrRange> prefix_ranges;
enum class ConnectionSourceType {
kAny = 0,
kSameIpOrLoopback,
kExternal
} source_type = ConnectionSourceType::kAny;
std::vector<CidrRange> source_prefix_ranges;
std::vector<uint32_t> source_ports;
std::vector<std::string> server_names;
std::string transport_protocol;
std::vector<std::string> application_protocols;
bool operator==(const FilterChainMatch& other) const {
return destination_port == other.destination_port &&
prefix_ranges == other.prefix_ranges &&
source_type == other.source_type &&
source_prefix_ranges == other.source_prefix_ranges &&
source_ports == other.source_ports &&
server_names == other.server_names &&
transport_protocol == other.transport_protocol &&
application_protocols == other.application_protocols;
}
std::string ToString() const;
} filter_chain_match;
DownstreamTlsContext downstream_tls_context;
bool operator==(const FilterChain& other) const {
return filter_chain_match == other.filter_chain_match &&
downstream_tls_context == other.downstream_tls_context;
}
std::string ToString() const;
};
std::vector<FilterChain> filter_chains;
absl::optional<FilterChain> default_filter_chain;
bool operator==(const LdsUpdate& other) const {
return downstream_tls_context == other.downstream_tls_context &&
route_config_name == other.route_config_name &&
return route_config_name == other.route_config_name &&
rds_update == other.rds_update &&
http_max_stream_duration == other.http_max_stream_duration &&
http_filters == other.http_filters;
http_filters == other.http_filters &&
filter_chains == other.filter_chains &&
default_filter_chain == other.default_filter_chain;
}
std::string ToString() const;

@ -154,11 +154,13 @@ class XdsServerConfigFetcher : public grpc_server_config_fetcher {
}
// Configure root cert.
absl::string_view root_provider_instance_name =
listener.downstream_tls_context.common_tls_context
listener.filter_chains[0]
.downstream_tls_context.common_tls_context
.combined_validation_context
.validation_context_certificate_provider_instance.instance_name;
absl::string_view root_provider_cert_name =
listener.downstream_tls_context.common_tls_context
listener.filter_chains[0]
.downstream_tls_context.common_tls_context
.combined_validation_context
.validation_context_certificate_provider_instance
.certificate_name;
@ -177,10 +179,12 @@ class XdsServerConfigFetcher : public grpc_server_config_fetcher {
}
// Configure identity cert.
absl::string_view identity_provider_instance_name =
listener.downstream_tls_context.common_tls_context
listener.filter_chains[0]
.downstream_tls_context.common_tls_context
.tls_certificate_certificate_provider_instance.instance_name;
absl::string_view identity_provider_cert_name =
listener.downstream_tls_context.common_tls_context
listener.filter_chains[0]
.downstream_tls_context.common_tls_context
.tls_certificate_certificate_provider_instance.certificate_name;
RefCountedPtr<grpc_tls_certificate_provider> new_identity_provider;
if (!identity_provider_instance_name.empty()) {
@ -201,7 +205,8 @@ class XdsServerConfigFetcher : public grpc_server_config_fetcher {
(root_certificate_provider_ == nullptr)) ||
((new_identity_provider == nullptr) !=
(identity_certificate_provider_ == nullptr)) ||
(listener.downstream_tls_context.require_client_certificate !=
(listener.filter_chains[0]
.downstream_tls_context.require_client_certificate !=
xds_certificate_provider_->GetRequireClientCertificate(""))) {
security_connector_update_required = true;
}
@ -222,7 +227,8 @@ class XdsServerConfigFetcher : public grpc_server_config_fetcher {
? nullptr
: identity_certificate_provider_->distributor());
xds_certificate_provider_->UpdateRequireClientCertificate(
"", listener.downstream_tls_context.require_client_certificate);
"", listener.filter_chains[0]
.downstream_tls_context.require_client_certificate);
return security_connector_update_required;
}

Loading…
Cancel
Save