|  | @@ -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;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |