Imported Upstream version 1.36.0
[platform/upstream/grpc.git] / src / core / ext / xds / xds_api.cc
1 /*
2  *
3  * Copyright 2018 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #include <grpc/support/port_platform.h>
20
21 #include <algorithm>
22 #include <cctype>
23 #include <cstdint>
24 #include <cstdlib>
25 #include <string>
26
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/str_format.h"
29 #include "absl/strings/str_join.h"
30 #include "absl/strings/str_split.h"
31
32 #include "upb/upb.hpp"
33
34 #include <grpc/impl/codegen/log.h>
35 #include <grpc/support/alloc.h>
36 #include <grpc/support/string_util.h>
37
38 #include "src/core/ext/xds/xds_api.h"
39 #include "src/core/lib/gpr/env.h"
40 #include "src/core/lib/gpr/string.h"
41 #include "src/core/lib/gpr/useful.h"
42 #include "src/core/lib/gprpp/host_port.h"
43 #include "src/core/lib/iomgr/error.h"
44 #include "src/core/lib/iomgr/sockaddr_utils.h"
45 #include "src/core/lib/slice/slice_utils.h"
46
47 #include "envoy/config/cluster/v3/circuit_breaker.upb.h"
48 #include "envoy/config/cluster/v3/cluster.upb.h"
49 #include "envoy/config/cluster/v3/cluster.upbdefs.h"
50 #include "envoy/config/core/v3/address.upb.h"
51 #include "envoy/config/core/v3/base.upb.h"
52 #include "envoy/config/core/v3/config_source.upb.h"
53 #include "envoy/config/core/v3/health_check.upb.h"
54 #include "envoy/config/core/v3/protocol.upb.h"
55 #include "envoy/config/endpoint/v3/endpoint.upb.h"
56 #include "envoy/config/endpoint/v3/endpoint.upbdefs.h"
57 #include "envoy/config/endpoint/v3/endpoint_components.upb.h"
58 #include "envoy/config/endpoint/v3/load_report.upb.h"
59 #include "envoy/config/listener/v3/api_listener.upb.h"
60 #include "envoy/config/listener/v3/listener.upb.h"
61 #include "envoy/config/listener/v3/listener_components.upb.h"
62 #include "envoy/config/route/v3/route.upb.h"
63 #include "envoy/config/route/v3/route.upbdefs.h"
64 #include "envoy/config/route/v3/route_components.upb.h"
65 #include "envoy/extensions/clusters/aggregate/v3/cluster.upb.h"
66 #include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h"
67 #include "envoy/extensions/transport_sockets/tls/v3/common.upb.h"
68 #include "envoy/extensions/transport_sockets/tls/v3/tls.upb.h"
69 #include "envoy/service/cluster/v3/cds.upb.h"
70 #include "envoy/service/cluster/v3/cds.upbdefs.h"
71 #include "envoy/service/discovery/v3/discovery.upb.h"
72 #include "envoy/service/discovery/v3/discovery.upbdefs.h"
73 #include "envoy/service/endpoint/v3/eds.upb.h"
74 #include "envoy/service/endpoint/v3/eds.upbdefs.h"
75 #include "envoy/service/listener/v3/lds.upb.h"
76 #include "envoy/service/load_stats/v3/lrs.upb.h"
77 #include "envoy/service/load_stats/v3/lrs.upbdefs.h"
78 #include "envoy/service/route/v3/rds.upb.h"
79 #include "envoy/service/route/v3/rds.upbdefs.h"
80 #include "envoy/type/matcher/v3/regex.upb.h"
81 #include "envoy/type/matcher/v3/string.upb.h"
82 #include "envoy/type/v3/percent.upb.h"
83 #include "envoy/type/v3/range.upb.h"
84 #include "google/protobuf/any.upb.h"
85 #include "google/protobuf/duration.upb.h"
86 #include "google/protobuf/struct.upb.h"
87 #include "google/protobuf/wrappers.upb.h"
88 #include "google/rpc/status.upb.h"
89 #include "upb/text_encode.h"
90 #include "upb/upb.h"
91
92 namespace grpc_core {
93
94 // TODO(donnadionne): Check to see if timeout is enabled, this will be
95 // removed once timeout feature is fully integration-tested and enabled by
96 // default.
97 bool XdsTimeoutEnabled() {
98   char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_ENABLE_TIMEOUT");
99   bool parsed_value;
100   bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
101   gpr_free(value);
102   return parse_succeeded && parsed_value;
103 }
104
105 // TODO(donnadionne): Check to see if cluster types aggregate_cluster and
106 // logical_dns are enabled, this will be
107 // removed once the cluster types are fully integration-tested and enabled by
108 // default.
109 bool XdsAggregateAndLogicalDnsClusterEnabled() {
110   char* value = gpr_getenv(
111       "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
112   bool parsed_value;
113   bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
114   gpr_free(value);
115   return parse_succeeded && parsed_value;
116 }
117
118 // TODO(donnadionne): Check to see if ring hash policy is enabled, this will be
119 // removed once ring hash policy is fully integration-tested and enabled by
120 // default.
121 bool XdsRingHashEnabled() {
122   char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
123   bool parsed_value;
124   bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
125   gpr_free(value);
126   return parse_succeeded && parsed_value;
127 }
128
129 // TODO(yashykt): Check to see if xDS security is enabled. This will be
130 // removed once this feature is fully integration-tested and enabled by
131 // default.
132 bool XdsSecurityEnabled() {
133   char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT");
134   bool parsed_value;
135   bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
136   gpr_free(value);
137   return parse_succeeded && parsed_value;
138 }
139
140 //
141 // XdsApi::Route
142 //
143
144 std::string XdsApi::Route::Matchers::ToString() const {
145   std::vector<std::string> contents;
146   contents.push_back(
147       absl::StrFormat("PathMatcher{%s}", path_matcher.ToString()));
148   for (const HeaderMatcher& header_matcher : header_matchers) {
149     contents.push_back(header_matcher.ToString());
150   }
151   if (fraction_per_million.has_value()) {
152     contents.push_back(absl::StrFormat("Fraction Per Million %d",
153                                        fraction_per_million.value()));
154   }
155   return absl::StrJoin(contents, "\n");
156 }
157
158 std::string XdsApi::Route::ClusterWeight::ToString() const {
159   return absl::StrFormat("{cluster=%s, weight=%d}", name, weight);
160 }
161
162 std::string XdsApi::Route::ToString() const {
163   std::vector<std::string> contents;
164   contents.push_back(matchers.ToString());
165   if (!cluster_name.empty()) {
166     contents.push_back(absl::StrFormat("Cluster name: %s", cluster_name));
167   }
168   for (const ClusterWeight& cluster_weight : weighted_clusters) {
169     contents.push_back(cluster_weight.ToString());
170   }
171   if (max_stream_duration.has_value()) {
172     contents.push_back(max_stream_duration->ToString());
173   }
174   return absl::StrJoin(contents, "\n");
175 }
176
177 //
178 // XdsApi::RdsUpdate
179 //
180
181 std::string XdsApi::RdsUpdate::ToString() const {
182   std::vector<std::string> vhosts;
183   for (const VirtualHost& vhost : virtual_hosts) {
184     vhosts.push_back(
185         absl::StrCat("vhost={\n"
186                      "  domains=[",
187                      absl::StrJoin(vhost.domains, ", "),
188                      "]\n"
189                      "  routes=[\n"));
190     for (const XdsApi::Route& route : vhost.routes) {
191       vhosts.push_back("    {\n");
192       vhosts.push_back(route.ToString());
193       vhosts.push_back("\n    }\n");
194     }
195     vhosts.push_back("  ]\n");
196     vhosts.push_back("]\n");
197   }
198   return absl::StrJoin(vhosts, "");
199 }
200
201 namespace {
202
203 // Better match type has smaller value.
204 enum MatchType {
205   EXACT_MATCH,
206   SUFFIX_MATCH,
207   PREFIX_MATCH,
208   UNIVERSE_MATCH,
209   INVALID_MATCH,
210 };
211
212 // Returns true if match succeeds.
213 bool DomainMatch(MatchType match_type, const std::string& domain_pattern_in,
214                  const std::string& expected_host_name_in) {
215   // Normalize the args to lower-case. Domain matching is case-insensitive.
216   std::string domain_pattern = domain_pattern_in;
217   std::string expected_host_name = expected_host_name_in;
218   std::transform(domain_pattern.begin(), domain_pattern.end(),
219                  domain_pattern.begin(),
220                  [](unsigned char c) { return std::tolower(c); });
221   std::transform(expected_host_name.begin(), expected_host_name.end(),
222                  expected_host_name.begin(),
223                  [](unsigned char c) { return std::tolower(c); });
224   if (match_type == EXACT_MATCH) {
225     return domain_pattern == expected_host_name;
226   } else if (match_type == SUFFIX_MATCH) {
227     // Asterisk must match at least one char.
228     if (expected_host_name.size() < domain_pattern.size()) return false;
229     absl::string_view pattern_suffix(domain_pattern.c_str() + 1);
230     absl::string_view host_suffix(expected_host_name.c_str() +
231                                   expected_host_name.size() -
232                                   pattern_suffix.size());
233     return pattern_suffix == host_suffix;
234   } else if (match_type == PREFIX_MATCH) {
235     // Asterisk must match at least one char.
236     if (expected_host_name.size() < domain_pattern.size()) return false;
237     absl::string_view pattern_prefix(domain_pattern.c_str(),
238                                      domain_pattern.size() - 1);
239     absl::string_view host_prefix(expected_host_name.c_str(),
240                                   pattern_prefix.size());
241     return pattern_prefix == host_prefix;
242   } else {
243     return match_type == UNIVERSE_MATCH;
244   }
245 }
246
247 MatchType DomainPatternMatchType(const std::string& domain_pattern) {
248   if (domain_pattern.empty()) return INVALID_MATCH;
249   if (domain_pattern.find('*') == std::string::npos) return EXACT_MATCH;
250   if (domain_pattern == "*") return UNIVERSE_MATCH;
251   if (domain_pattern[0] == '*') return SUFFIX_MATCH;
252   if (domain_pattern[domain_pattern.size() - 1] == '*') return PREFIX_MATCH;
253   return INVALID_MATCH;
254 }
255
256 }  // namespace
257
258 XdsApi::RdsUpdate::VirtualHost* XdsApi::RdsUpdate::FindVirtualHostForDomain(
259     const std::string& domain) {
260   // Find the best matched virtual host.
261   // The search order for 4 groups of domain patterns:
262   //   1. Exact match.
263   //   2. Suffix match (e.g., "*ABC").
264   //   3. Prefix match (e.g., "ABC*").
265   //   4. Universe match (i.e., "*").
266   // Within each group, longest match wins.
267   // If the same best matched domain pattern appears in multiple virtual hosts,
268   // the first matched virtual host wins.
269   VirtualHost* target_vhost = nullptr;
270   MatchType best_match_type = INVALID_MATCH;
271   size_t longest_match = 0;
272   // Check each domain pattern in each virtual host to determine the best
273   // matched virtual host.
274   for (VirtualHost& vhost : virtual_hosts) {
275     for (const std::string& domain_pattern : vhost.domains) {
276       // Check the match type first. Skip the pattern if it's not better than
277       // current match.
278       const MatchType match_type = DomainPatternMatchType(domain_pattern);
279       // This should be caught by RouteConfigParse().
280       GPR_ASSERT(match_type != INVALID_MATCH);
281       if (match_type > best_match_type) continue;
282       if (match_type == best_match_type &&
283           domain_pattern.size() <= longest_match) {
284         continue;
285       }
286       // Skip if match fails.
287       if (!DomainMatch(match_type, domain_pattern, domain)) continue;
288       // Choose this match.
289       target_vhost = &vhost;
290       best_match_type = match_type;
291       longest_match = domain_pattern.size();
292       if (best_match_type == EXACT_MATCH) break;
293     }
294     if (best_match_type == EXACT_MATCH) break;
295   }
296   return target_vhost;
297 }
298
299 //
300 // XdsApi::CommonTlsContext::CertificateValidationContext
301 //
302
303 std::string XdsApi::CommonTlsContext::CertificateValidationContext::ToString()
304     const {
305   std::vector<std::string> contents;
306   for (const auto& match : match_subject_alt_names) {
307     contents.push_back(match.ToString());
308   }
309   return absl::StrFormat("{match_subject_alt_names=[%s]}",
310                          absl::StrJoin(contents, ", "));
311 }
312
313 bool XdsApi::CommonTlsContext::CertificateValidationContext::Empty() const {
314   return match_subject_alt_names.empty();
315 }
316
317 //
318 // XdsApi::CommonTlsContext::CertificateValidationContext
319 //
320
321 std::string XdsApi::CommonTlsContext::CertificateProviderInstance::ToString()
322     const {
323   absl::InlinedVector<std::string, 2> contents;
324   if (!instance_name.empty()) {
325     contents.push_back(absl::StrFormat("instance_name=%s", instance_name));
326   }
327   if (!certificate_name.empty()) {
328     contents.push_back(
329         absl::StrFormat("certificate_name=%s", certificate_name));
330   }
331   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
332 }
333
334 bool XdsApi::CommonTlsContext::CertificateProviderInstance::Empty() const {
335   return instance_name.empty() && certificate_name.empty();
336 }
337
338 //
339 // XdsApi::CommonTlsContext::CombinedCertificateValidationContext
340 //
341
342 std::string
343 XdsApi::CommonTlsContext::CombinedCertificateValidationContext::ToString()
344     const {
345   absl::InlinedVector<std::string, 2> contents;
346   if (!default_validation_context.Empty()) {
347     contents.push_back(absl::StrFormat("default_validation_context=%s",
348                                        default_validation_context.ToString()));
349   }
350   if (!validation_context_certificate_provider_instance.Empty()) {
351     contents.push_back(absl::StrFormat(
352         "validation_context_certificate_provider_instance=%s",
353         validation_context_certificate_provider_instance.ToString()));
354   }
355   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
356 }
357
358 bool XdsApi::CommonTlsContext::CombinedCertificateValidationContext::Empty()
359     const {
360   return default_validation_context.Empty() &&
361          validation_context_certificate_provider_instance.Empty();
362 }
363
364 //
365 // XdsApi::CommonTlsContext
366 //
367
368 std::string XdsApi::CommonTlsContext::ToString() const {
369   absl::InlinedVector<std::string, 2> contents;
370   if (!tls_certificate_certificate_provider_instance.Empty()) {
371     contents.push_back(absl::StrFormat(
372         "tls_certificate_certificate_provider_instance=%s",
373         tls_certificate_certificate_provider_instance.ToString()));
374   }
375   if (!combined_validation_context.Empty()) {
376     contents.push_back(absl::StrFormat("combined_validation_context=%s",
377                                        combined_validation_context.ToString()));
378   }
379   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
380 }
381
382 bool XdsApi::CommonTlsContext::Empty() const {
383   return tls_certificate_certificate_provider_instance.Empty() &&
384          combined_validation_context.Empty();
385 }
386
387 //
388 // XdsApi::DownstreamTlsContext
389 //
390
391 std::string XdsApi::DownstreamTlsContext::ToString() const {
392   return absl::StrFormat("common_tls_context=%s, require_client_certificate=%s",
393                          common_tls_context.ToString(),
394                          require_client_certificate ? "true" : "false");
395 }
396
397 bool XdsApi::DownstreamTlsContext::Empty() const {
398   return common_tls_context.Empty();
399 }
400
401 //
402 // XdsApi::LdsUpdate
403 //
404
405 std::string XdsApi::LdsUpdate::ToString() const {
406   absl::InlinedVector<std::string, 3> contents;
407   if (type == ListenerType::kTcpListener) {
408     if (!downstream_tls_context.Empty()) {
409       contents.push_back(absl::StrFormat("downstream_tls_context=%s",
410                                          downstream_tls_context.ToString()));
411     }
412   } else if (type == ListenerType::kHttpApiListener) {
413     contents.push_back(absl::StrFormat(
414         "route_config_name=%s",
415         !route_config_name.empty() ? route_config_name.c_str() : "<inlined>"));
416     contents.push_back(absl::StrFormat("http_max_stream_duration=%s",
417                                        http_max_stream_duration.ToString()));
418     if (rds_update.has_value()) {
419       contents.push_back(
420           absl::StrFormat("rds_update=%s", rds_update->ToString()));
421     }
422   }
423   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
424 }
425
426 //
427 // XdsApi::CdsUpdate
428 //
429
430 std::string XdsApi::CdsUpdate::ToString() const {
431   absl::InlinedVector<std::string, 4> contents;
432   if (!eds_service_name.empty()) {
433     contents.push_back(
434         absl::StrFormat("eds_service_name=%s", eds_service_name));
435   }
436   if (!common_tls_context.Empty()) {
437     contents.push_back(absl::StrFormat("common_tls_context=%s",
438                                        common_tls_context.ToString()));
439   }
440   if (lrs_load_reporting_server_name.has_value()) {
441     contents.push_back(absl::StrFormat("lrs_load_reporting_server_name=%s",
442                                        lrs_load_reporting_server_name.value()));
443   }
444   contents.push_back(
445       absl::StrFormat("max_concurrent_requests=%d", max_concurrent_requests));
446   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
447 }
448
449 //
450 // XdsApi::EdsUpdate
451 //
452
453 std::string XdsApi::EdsUpdate::Priority::Locality::ToString() const {
454   std::vector<std::string> endpoint_strings;
455   for (const ServerAddress& endpoint : endpoints) {
456     endpoint_strings.emplace_back(endpoint.ToString());
457   }
458   return absl::StrCat("{name=", name->AsHumanReadableString(),
459                       ", lb_weight=", lb_weight, ", endpoints=[",
460                       absl::StrJoin(endpoint_strings, ", "), "]}");
461 }
462
463 bool XdsApi::EdsUpdate::Priority::operator==(const Priority& other) const {
464   if (localities.size() != other.localities.size()) return false;
465   auto it1 = localities.begin();
466   auto it2 = other.localities.begin();
467   while (it1 != localities.end()) {
468     if (*it1->first != *it2->first) return false;
469     if (it1->second != it2->second) return false;
470     ++it1;
471     ++it2;
472   }
473   return true;
474 }
475
476 std::string XdsApi::EdsUpdate::Priority::ToString() const {
477   std::vector<std::string> locality_strings;
478   for (const auto& p : localities) {
479     locality_strings.emplace_back(p.second.ToString());
480   }
481   return absl::StrCat("[", absl::StrJoin(locality_strings, ", "), "]");
482 }
483
484 bool XdsApi::EdsUpdate::DropConfig::ShouldDrop(
485     const std::string** category_name) const {
486   for (size_t i = 0; i < drop_category_list_.size(); ++i) {
487     const auto& drop_category = drop_category_list_[i];
488     // Generate a random number in [0, 1000000).
489     const uint32_t random = static_cast<uint32_t>(rand()) % 1000000;
490     if (random < drop_category.parts_per_million) {
491       *category_name = &drop_category.name;
492       return true;
493     }
494   }
495   return false;
496 }
497
498 std::string XdsApi::EdsUpdate::DropConfig::ToString() const {
499   std::vector<std::string> category_strings;
500   for (const DropCategory& category : drop_category_list_) {
501     category_strings.emplace_back(
502         absl::StrCat(category.name, "=", category.parts_per_million));
503   }
504   return absl::StrCat("{[", absl::StrJoin(category_strings, ", "),
505                       "], drop_all=", drop_all_, "}");
506 }
507
508 std::string XdsApi::EdsUpdate::ToString() const {
509   std::vector<std::string> priority_strings;
510   for (size_t i = 0; i < priorities.size(); ++i) {
511     const Priority& priority = priorities[i];
512     priority_strings.emplace_back(
513         absl::StrCat("priority ", i, ": ", priority.ToString()));
514   }
515   return absl::StrCat("priorities=[", absl::StrJoin(priority_strings, ", "),
516                       "], drop_config=", drop_config->ToString());
517 }
518
519 //
520 // XdsApi
521 //
522
523 const char* XdsApi::kLdsTypeUrl =
524     "type.googleapis.com/envoy.config.listener.v3.Listener";
525 const char* XdsApi::kRdsTypeUrl =
526     "type.googleapis.com/envoy.config.route.v3.RouteConfiguration";
527 const char* XdsApi::kCdsTypeUrl =
528     "type.googleapis.com/envoy.config.cluster.v3.Cluster";
529 const char* XdsApi::kEdsTypeUrl =
530     "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment";
531
532 namespace {
533
534 const char* kLdsV2TypeUrl = "type.googleapis.com/envoy.api.v2.Listener";
535 const char* kRdsV2TypeUrl =
536     "type.googleapis.com/envoy.api.v2.RouteConfiguration";
537 const char* kCdsV2TypeUrl = "type.googleapis.com/envoy.api.v2.Cluster";
538 const char* kEdsV2TypeUrl =
539     "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment";
540
541 bool IsLds(absl::string_view type_url) {
542   return type_url == XdsApi::kLdsTypeUrl || type_url == kLdsV2TypeUrl;
543 }
544
545 bool IsRds(absl::string_view type_url) {
546   return type_url == XdsApi::kRdsTypeUrl || type_url == kRdsV2TypeUrl;
547 }
548
549 bool IsCds(absl::string_view type_url) {
550   return type_url == XdsApi::kCdsTypeUrl || type_url == kCdsV2TypeUrl;
551 }
552
553 bool IsEds(absl::string_view type_url) {
554   return type_url == XdsApi::kEdsTypeUrl || type_url == kEdsV2TypeUrl;
555 }
556
557 }  // namespace
558
559 XdsApi::XdsApi(XdsClient* client, TraceFlag* tracer,
560                const XdsBootstrap::Node* node)
561     : client_(client),
562       tracer_(tracer),
563       node_(node),
564       build_version_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING, " ",
565                                   grpc_version_string())),
566       user_agent_name_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING)) {}
567
568 namespace {
569
570 // Works for both std::string and absl::string_view.
571 template <typename T>
572 inline upb_strview StdStringToUpbString(const T& str) {
573   return upb_strview_make(str.data(), str.size());
574 }
575
576 void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
577                            const Json& value);
578
579 void PopulateListValue(upb_arena* arena, google_protobuf_ListValue* list_value,
580                        const Json::Array& values) {
581   for (const auto& value : values) {
582     auto* value_pb = google_protobuf_ListValue_add_values(list_value, arena);
583     PopulateMetadataValue(arena, value_pb, value);
584   }
585 }
586
587 void PopulateMetadata(upb_arena* arena, google_protobuf_Struct* metadata_pb,
588                       const Json::Object& metadata) {
589   for (const auto& p : metadata) {
590     google_protobuf_Value* value = google_protobuf_Value_new(arena);
591     PopulateMetadataValue(arena, value, p.second);
592     google_protobuf_Struct_fields_set(
593         metadata_pb, StdStringToUpbString(p.first), value, arena);
594   }
595 }
596
597 void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
598                            const Json& value) {
599   switch (value.type()) {
600     case Json::Type::JSON_NULL:
601       google_protobuf_Value_set_null_value(value_pb, 0);
602       break;
603     case Json::Type::NUMBER:
604       google_protobuf_Value_set_number_value(
605           value_pb, strtod(value.string_value().c_str(), nullptr));
606       break;
607     case Json::Type::STRING:
608       google_protobuf_Value_set_string_value(
609           value_pb, StdStringToUpbString(value.string_value()));
610       break;
611     case Json::Type::JSON_TRUE:
612       google_protobuf_Value_set_bool_value(value_pb, true);
613       break;
614     case Json::Type::JSON_FALSE:
615       google_protobuf_Value_set_bool_value(value_pb, false);
616       break;
617     case Json::Type::OBJECT: {
618       google_protobuf_Struct* struct_value =
619           google_protobuf_Value_mutable_struct_value(value_pb, arena);
620       PopulateMetadata(arena, struct_value, value.object_value());
621       break;
622     }
623     case Json::Type::ARRAY: {
624       google_protobuf_ListValue* list_value =
625           google_protobuf_Value_mutable_list_value(value_pb, arena);
626       PopulateListValue(arena, list_value, value.array_value());
627       break;
628     }
629   }
630 }
631
632 // Helper functions to manually do protobuf string encoding, so that we
633 // can populate the node build_version field that was removed in v3.
634 std::string EncodeVarint(uint64_t val) {
635   std::string data;
636   do {
637     uint8_t byte = val & 0x7fU;
638     val >>= 7;
639     if (val) byte |= 0x80U;
640     data += byte;
641   } while (val);
642   return data;
643 }
644 std::string EncodeTag(uint32_t field_number, uint8_t wire_type) {
645   return EncodeVarint((field_number << 3) | wire_type);
646 }
647 std::string EncodeStringField(uint32_t field_number, const std::string& str) {
648   static const uint8_t kDelimitedWireType = 2;
649   return EncodeTag(field_number, kDelimitedWireType) +
650          EncodeVarint(str.size()) + str;
651 }
652
653 void PopulateBuildVersion(upb_arena* arena, envoy_config_core_v3_Node* node_msg,
654                           const std::string& build_version) {
655   std::string encoded_build_version = EncodeStringField(5, build_version);
656   // TODO(roth): This should use upb_msg_addunknown(), but that API is
657   // broken in the current version of upb, so we're using the internal
658   // API for now.  Change this once we upgrade to a version of upb that
659   // fixes this bug.
660   _upb_msg_addunknown(node_msg, encoded_build_version.data(),
661                       encoded_build_version.size(), arena);
662 }
663
664 void PopulateNode(upb_arena* arena, const XdsBootstrap::Node* node, bool use_v3,
665                   const std::string& build_version,
666                   const std::string& user_agent_name,
667                   envoy_config_core_v3_Node* node_msg) {
668   if (node != nullptr) {
669     if (!node->id.empty()) {
670       envoy_config_core_v3_Node_set_id(node_msg,
671                                        StdStringToUpbString(node->id));
672     }
673     if (!node->cluster.empty()) {
674       envoy_config_core_v3_Node_set_cluster(
675           node_msg, StdStringToUpbString(node->cluster));
676     }
677     if (!node->metadata.object_value().empty()) {
678       google_protobuf_Struct* metadata =
679           envoy_config_core_v3_Node_mutable_metadata(node_msg, arena);
680       PopulateMetadata(arena, metadata, node->metadata.object_value());
681     }
682     if (!node->locality_region.empty() || !node->locality_zone.empty() ||
683         !node->locality_subzone.empty()) {
684       envoy_config_core_v3_Locality* locality =
685           envoy_config_core_v3_Node_mutable_locality(node_msg, arena);
686       if (!node->locality_region.empty()) {
687         envoy_config_core_v3_Locality_set_region(
688             locality, StdStringToUpbString(node->locality_region));
689       }
690       if (!node->locality_zone.empty()) {
691         envoy_config_core_v3_Locality_set_zone(
692             locality, StdStringToUpbString(node->locality_zone));
693       }
694       if (!node->locality_subzone.empty()) {
695         envoy_config_core_v3_Locality_set_sub_zone(
696             locality, StdStringToUpbString(node->locality_subzone));
697       }
698     }
699   }
700   if (!use_v3) {
701     PopulateBuildVersion(arena, node_msg, build_version);
702   }
703   envoy_config_core_v3_Node_set_user_agent_name(
704       node_msg, StdStringToUpbString(user_agent_name));
705   envoy_config_core_v3_Node_set_user_agent_version(
706       node_msg, upb_strview_makez(grpc_version_string()));
707   envoy_config_core_v3_Node_add_client_features(
708       node_msg, upb_strview_makez("envoy.lb.does_not_support_overprovisioning"),
709       arena);
710 }
711
712 inline absl::string_view UpbStringToAbsl(const upb_strview& str) {
713   return absl::string_view(str.data, str.size);
714 }
715
716 inline std::string UpbStringToStdString(const upb_strview& str) {
717   return std::string(str.data, str.size);
718 }
719
720 void MaybeLogDiscoveryRequest(
721     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
722     const envoy_service_discovery_v3_DiscoveryRequest* request) {
723   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
724       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
725     const upb_msgdef* msg_type =
726         envoy_service_discovery_v3_DiscoveryRequest_getmsgdef(symtab);
727     char buf[10240];
728     upb_text_encode(request, msg_type, nullptr, 0, buf, sizeof(buf));
729     gpr_log(GPR_DEBUG, "[xds_client %p] constructed ADS request: %s", client,
730             buf);
731   }
732 }
733
734 grpc_slice SerializeDiscoveryRequest(
735     upb_arena* arena, envoy_service_discovery_v3_DiscoveryRequest* request) {
736   size_t output_length;
737   char* output = envoy_service_discovery_v3_DiscoveryRequest_serialize(
738       request, arena, &output_length);
739   return grpc_slice_from_copied_buffer(output, output_length);
740 }
741
742 absl::string_view TypeUrlExternalToInternal(bool use_v3,
743                                             const std::string& type_url) {
744   if (!use_v3) {
745     if (type_url == XdsApi::kLdsTypeUrl) {
746       return kLdsV2TypeUrl;
747     }
748     if (type_url == XdsApi::kRdsTypeUrl) {
749       return kRdsV2TypeUrl;
750     }
751     if (type_url == XdsApi::kCdsTypeUrl) {
752       return kCdsV2TypeUrl;
753     }
754     if (type_url == XdsApi::kEdsTypeUrl) {
755       return kEdsV2TypeUrl;
756     }
757   }
758   return type_url;
759 }
760
761 }  // namespace
762
763 grpc_slice XdsApi::CreateAdsRequest(
764     const XdsBootstrap::XdsServer& server, const std::string& type_url,
765     const std::set<absl::string_view>& resource_names,
766     const std::string& version, const std::string& nonce, grpc_error* error,
767     bool populate_node) {
768   upb::Arena arena;
769   // Create a request.
770   envoy_service_discovery_v3_DiscoveryRequest* request =
771       envoy_service_discovery_v3_DiscoveryRequest_new(arena.ptr());
772   // Set type_url.
773   absl::string_view real_type_url =
774       TypeUrlExternalToInternal(server.ShouldUseV3(), type_url);
775   envoy_service_discovery_v3_DiscoveryRequest_set_type_url(
776       request, StdStringToUpbString(real_type_url));
777   // Set version_info.
778   if (!version.empty()) {
779     envoy_service_discovery_v3_DiscoveryRequest_set_version_info(
780         request, StdStringToUpbString(version));
781   }
782   // Set nonce.
783   if (!nonce.empty()) {
784     envoy_service_discovery_v3_DiscoveryRequest_set_response_nonce(
785         request, StdStringToUpbString(nonce));
786   }
787   // Set error_detail if it's a NACK.
788   if (error != GRPC_ERROR_NONE) {
789     google_rpc_Status* error_detail =
790         envoy_service_discovery_v3_DiscoveryRequest_mutable_error_detail(
791             request, arena.ptr());
792     // Hard-code INVALID_ARGUMENT as the status code.
793     // TODO(roth): If at some point we decide we care about this value,
794     // we could attach a status code to the individual errors where we
795     // generate them in the parsing code, and then use that here.
796     google_rpc_Status_set_code(error_detail, GRPC_STATUS_INVALID_ARGUMENT);
797     // Error description comes from the error that was passed in.
798     upb_strview error_description =
799         StdStringToUpbString(absl::string_view(grpc_error_string(error)));
800     google_rpc_Status_set_message(error_detail, error_description);
801     GRPC_ERROR_UNREF(error);
802   }
803   // Populate node.
804   if (populate_node) {
805     envoy_config_core_v3_Node* node_msg =
806         envoy_service_discovery_v3_DiscoveryRequest_mutable_node(request,
807                                                                  arena.ptr());
808     PopulateNode(arena.ptr(), node_, server.ShouldUseV3(), build_version_,
809                  user_agent_name_, node_msg);
810   }
811   // Add resource_names.
812   for (const auto& resource_name : resource_names) {
813     envoy_service_discovery_v3_DiscoveryRequest_add_resource_names(
814         request, StdStringToUpbString(resource_name), arena.ptr());
815   }
816   MaybeLogDiscoveryRequest(client_, tracer_, symtab_.ptr(), request);
817   return SerializeDiscoveryRequest(arena.ptr(), request);
818 }
819
820 namespace {
821
822 void MaybeLogDiscoveryResponse(
823     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
824     const envoy_service_discovery_v3_DiscoveryResponse* response) {
825   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
826       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
827     const upb_msgdef* msg_type =
828         envoy_service_discovery_v3_DiscoveryResponse_getmsgdef(symtab);
829     char buf[10240];
830     upb_text_encode(response, msg_type, nullptr, 0, buf, sizeof(buf));
831     gpr_log(GPR_DEBUG, "[xds_client %p] received response: %s", client, buf);
832   }
833 }
834
835 void MaybeLogRouteConfiguration(
836     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
837     const envoy_config_route_v3_RouteConfiguration* route_config) {
838   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
839       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
840     const upb_msgdef* msg_type =
841         envoy_config_route_v3_RouteConfiguration_getmsgdef(symtab);
842     char buf[10240];
843     upb_text_encode(route_config, msg_type, nullptr, 0, buf, sizeof(buf));
844     gpr_log(GPR_DEBUG, "[xds_client %p] RouteConfiguration: %s", client, buf);
845   }
846 }
847
848 void MaybeLogCluster(XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
849                      const envoy_config_cluster_v3_Cluster* cluster) {
850   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
851       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
852     const upb_msgdef* msg_type =
853         envoy_config_cluster_v3_Cluster_getmsgdef(symtab);
854     char buf[10240];
855     upb_text_encode(cluster, msg_type, nullptr, 0, buf, sizeof(buf));
856     gpr_log(GPR_DEBUG, "[xds_client %p] Cluster: %s", client, buf);
857   }
858 }
859
860 void MaybeLogClusterLoadAssignment(
861     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
862     const envoy_config_endpoint_v3_ClusterLoadAssignment* cla) {
863   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
864       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
865     const upb_msgdef* msg_type =
866         envoy_config_endpoint_v3_ClusterLoadAssignment_getmsgdef(symtab);
867     char buf[10240];
868     upb_text_encode(cla, msg_type, nullptr, 0, buf, sizeof(buf));
869     gpr_log(GPR_DEBUG, "[xds_client %p] ClusterLoadAssignment: %s", client,
870             buf);
871   }
872 }
873
874 grpc_error* RoutePathMatchParse(const envoy_config_route_v3_RouteMatch* match,
875                                 XdsApi::Route* route, bool* ignore_route) {
876   auto* case_sensitive_ptr =
877       envoy_config_route_v3_RouteMatch_case_sensitive(match);
878   bool case_sensitive = true;
879   if (case_sensitive_ptr != nullptr) {
880     case_sensitive = google_protobuf_BoolValue_value(case_sensitive_ptr);
881   }
882   StringMatcher::Type type;
883   std::string match_string;
884   if (envoy_config_route_v3_RouteMatch_has_prefix(match)) {
885     absl::string_view prefix =
886         UpbStringToAbsl(envoy_config_route_v3_RouteMatch_prefix(match));
887     // Empty prefix "" is accepted.
888     if (!prefix.empty()) {
889       // Prefix "/" is accepted.
890       if (prefix[0] != '/') {
891         // Prefix which does not start with a / will never match anything, so
892         // ignore this route.
893         *ignore_route = true;
894         return GRPC_ERROR_NONE;
895       }
896       std::vector<absl::string_view> prefix_elements =
897           absl::StrSplit(prefix.substr(1), absl::MaxSplits('/', 2));
898       if (prefix_elements.size() > 2) {
899         // Prefix cannot have more than 2 slashes.
900         *ignore_route = true;
901         return GRPC_ERROR_NONE;
902       } else if (prefix_elements.size() == 2 && prefix_elements[0].empty()) {
903         // Prefix contains empty string between the 2 slashes
904         *ignore_route = true;
905         return GRPC_ERROR_NONE;
906       }
907     }
908     type = StringMatcher::Type::PREFIX;
909     match_string = std::string(prefix);
910   } else if (envoy_config_route_v3_RouteMatch_has_path(match)) {
911     absl::string_view path =
912         UpbStringToAbsl(envoy_config_route_v3_RouteMatch_path(match));
913     if (path.empty()) {
914       // Path that is empty will never match anything, so ignore this route.
915       *ignore_route = true;
916       return GRPC_ERROR_NONE;
917     }
918     if (path[0] != '/') {
919       // Path which does not start with a / will never match anything, so
920       // ignore this route.
921       *ignore_route = true;
922       return GRPC_ERROR_NONE;
923     }
924     std::vector<absl::string_view> path_elements =
925         absl::StrSplit(path.substr(1), absl::MaxSplits('/', 2));
926     if (path_elements.size() != 2) {
927       // Path not in the required format of /service/method will never match
928       // anything, so ignore this route.
929       *ignore_route = true;
930       return GRPC_ERROR_NONE;
931     } else if (path_elements[0].empty()) {
932       // Path contains empty service name will never match anything, so ignore
933       // this route.
934       *ignore_route = true;
935       return GRPC_ERROR_NONE;
936     } else if (path_elements[1].empty()) {
937       // Path contains empty method name will never match anything, so ignore
938       // this route.
939       *ignore_route = true;
940       return GRPC_ERROR_NONE;
941     }
942     type = StringMatcher::Type::EXACT;
943     match_string = std::string(path);
944   } else if (envoy_config_route_v3_RouteMatch_has_safe_regex(match)) {
945     const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
946         envoy_config_route_v3_RouteMatch_safe_regex(match);
947     GPR_ASSERT(regex_matcher != nullptr);
948     type = StringMatcher::Type::SAFE_REGEX;
949     match_string = UpbStringToStdString(
950         envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
951   } else {
952     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
953         "Invalid route path specifier specified.");
954   }
955   absl::StatusOr<StringMatcher> string_matcher =
956       StringMatcher::Create(type, match_string, case_sensitive);
957   if (!string_matcher.ok()) {
958     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
959         absl::StrCat("path matcher: ", string_matcher.status().message())
960             .c_str());
961     ;
962   }
963   route->matchers.path_matcher = std::move(string_matcher.value());
964   return GRPC_ERROR_NONE;
965 }
966
967 grpc_error* RouteHeaderMatchersParse(
968     const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route) {
969   size_t size;
970   const envoy_config_route_v3_HeaderMatcher* const* headers =
971       envoy_config_route_v3_RouteMatch_headers(match, &size);
972   for (size_t i = 0; i < size; ++i) {
973     const envoy_config_route_v3_HeaderMatcher* header = headers[i];
974     const std::string name =
975         UpbStringToStdString(envoy_config_route_v3_HeaderMatcher_name(header));
976     HeaderMatcher::Type type;
977     std::string match_string;
978     int64_t range_start = 0;
979     int64_t range_end = 0;
980     bool present_match = false;
981     if (envoy_config_route_v3_HeaderMatcher_has_exact_match(header)) {
982       type = HeaderMatcher::Type::EXACT;
983       match_string = UpbStringToStdString(
984           envoy_config_route_v3_HeaderMatcher_exact_match(header));
985     } else if (envoy_config_route_v3_HeaderMatcher_has_safe_regex_match(
986                    header)) {
987       const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
988           envoy_config_route_v3_HeaderMatcher_safe_regex_match(header);
989       GPR_ASSERT(regex_matcher != nullptr);
990       type = HeaderMatcher::Type::SAFE_REGEX;
991       match_string = UpbStringToStdString(
992           envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
993     } else if (envoy_config_route_v3_HeaderMatcher_has_range_match(header)) {
994       type = HeaderMatcher::Type::RANGE;
995       const envoy_type_v3_Int64Range* range_matcher =
996           envoy_config_route_v3_HeaderMatcher_range_match(header);
997       range_start = envoy_type_v3_Int64Range_start(range_matcher);
998       range_end = envoy_type_v3_Int64Range_end(range_matcher);
999     } else if (envoy_config_route_v3_HeaderMatcher_has_present_match(header)) {
1000       type = HeaderMatcher::Type::PRESENT;
1001       present_match = envoy_config_route_v3_HeaderMatcher_present_match(header);
1002     } else if (envoy_config_route_v3_HeaderMatcher_has_prefix_match(header)) {
1003       type = HeaderMatcher::Type::PREFIX;
1004       match_string = UpbStringToStdString(
1005           envoy_config_route_v3_HeaderMatcher_prefix_match(header));
1006     } else if (envoy_config_route_v3_HeaderMatcher_has_suffix_match(header)) {
1007       type = HeaderMatcher::Type::SUFFIX;
1008       match_string = UpbStringToStdString(
1009           envoy_config_route_v3_HeaderMatcher_suffix_match(header));
1010     } else if (envoy_config_route_v3_HeaderMatcher_has_contains_match(header)) {
1011       type = HeaderMatcher::Type::CONTAINS;
1012       match_string = UpbStringToStdString(
1013           envoy_config_route_v3_HeaderMatcher_contains_match(header));
1014     } else {
1015       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1016           "Invalid route header matcher specified.");
1017     }
1018     bool invert_match =
1019         envoy_config_route_v3_HeaderMatcher_invert_match(header);
1020     absl::StatusOr<HeaderMatcher> header_matcher =
1021         HeaderMatcher::Create(name, type, match_string, range_start, range_end,
1022                               present_match, invert_match);
1023     if (!header_matcher.ok()) {
1024       return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1025           absl::StrCat("header matcher: ", header_matcher.status().message())
1026               .c_str());
1027     }
1028     route->matchers.header_matchers.emplace_back(
1029         std::move(header_matcher.value()));
1030   }
1031   return GRPC_ERROR_NONE;
1032 }
1033
1034 grpc_error* RouteRuntimeFractionParse(
1035     const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route) {
1036   const envoy_config_core_v3_RuntimeFractionalPercent* runtime_fraction =
1037       envoy_config_route_v3_RouteMatch_runtime_fraction(match);
1038   if (runtime_fraction != nullptr) {
1039     const envoy_type_v3_FractionalPercent* fraction =
1040         envoy_config_core_v3_RuntimeFractionalPercent_default_value(
1041             runtime_fraction);
1042     if (fraction != nullptr) {
1043       uint32_t numerator = envoy_type_v3_FractionalPercent_numerator(fraction);
1044       const auto denominator =
1045           static_cast<envoy_type_v3_FractionalPercent_DenominatorType>(
1046               envoy_type_v3_FractionalPercent_denominator(fraction));
1047       // Normalize to million.
1048       switch (denominator) {
1049         case envoy_type_v3_FractionalPercent_HUNDRED:
1050           numerator *= 10000;
1051           break;
1052         case envoy_type_v3_FractionalPercent_TEN_THOUSAND:
1053           numerator *= 100;
1054           break;
1055         case envoy_type_v3_FractionalPercent_MILLION:
1056           break;
1057         default:
1058           return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1059               "Unknown denominator type");
1060       }
1061       route->matchers.fraction_per_million = numerator;
1062     }
1063   }
1064   return GRPC_ERROR_NONE;
1065 }
1066
1067 grpc_error* RouteActionParse(const envoy_config_route_v3_Route* route_msg,
1068                              XdsApi::Route* route, bool* ignore_route) {
1069   if (!envoy_config_route_v3_Route_has_route(route_msg)) {
1070     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1071         "No RouteAction found in route.");
1072   }
1073   const envoy_config_route_v3_RouteAction* route_action =
1074       envoy_config_route_v3_Route_route(route_msg);
1075   // Get the cluster or weighted_clusters in the RouteAction.
1076   if (envoy_config_route_v3_RouteAction_has_cluster(route_action)) {
1077     route->cluster_name = UpbStringToStdString(
1078         envoy_config_route_v3_RouteAction_cluster(route_action));
1079     if (route->cluster_name.empty()) {
1080       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1081           "RouteAction cluster contains empty cluster name.");
1082     }
1083   } else if (envoy_config_route_v3_RouteAction_has_weighted_clusters(
1084                  route_action)) {
1085     const envoy_config_route_v3_WeightedCluster* weighted_cluster =
1086         envoy_config_route_v3_RouteAction_weighted_clusters(route_action);
1087     uint32_t total_weight = 100;
1088     const google_protobuf_UInt32Value* weight =
1089         envoy_config_route_v3_WeightedCluster_total_weight(weighted_cluster);
1090     if (weight != nullptr) {
1091       total_weight = google_protobuf_UInt32Value_value(weight);
1092     }
1093     size_t clusters_size;
1094     const envoy_config_route_v3_WeightedCluster_ClusterWeight* const* clusters =
1095         envoy_config_route_v3_WeightedCluster_clusters(weighted_cluster,
1096                                                        &clusters_size);
1097     uint32_t sum_of_weights = 0;
1098     for (size_t j = 0; j < clusters_size; ++j) {
1099       const envoy_config_route_v3_WeightedCluster_ClusterWeight*
1100           cluster_weight = clusters[j];
1101       XdsApi::Route::ClusterWeight cluster;
1102       cluster.name = UpbStringToStdString(
1103           envoy_config_route_v3_WeightedCluster_ClusterWeight_name(
1104               cluster_weight));
1105       if (cluster.name.empty()) {
1106         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1107             "RouteAction weighted_cluster cluster contains empty cluster "
1108             "name.");
1109       }
1110       const google_protobuf_UInt32Value* weight =
1111           envoy_config_route_v3_WeightedCluster_ClusterWeight_weight(
1112               cluster_weight);
1113       if (weight == nullptr) {
1114         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1115             "RouteAction weighted_cluster cluster missing weight");
1116       }
1117       cluster.weight = google_protobuf_UInt32Value_value(weight);
1118       if (cluster.weight == 0) continue;
1119       sum_of_weights += cluster.weight;
1120       route->weighted_clusters.emplace_back(std::move(cluster));
1121     }
1122     if (total_weight != sum_of_weights) {
1123       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1124           "RouteAction weighted_cluster has incorrect total weight");
1125     }
1126     if (route->weighted_clusters.empty()) {
1127       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1128           "RouteAction weighted_cluster has no valid clusters specified.");
1129     }
1130   } else {
1131     // No cluster or weighted_clusters found in RouteAction, ignore this route.
1132     *ignore_route = true;
1133   }
1134   if (XdsTimeoutEnabled() && !*ignore_route) {
1135     const envoy_config_route_v3_RouteAction_MaxStreamDuration*
1136         max_stream_duration =
1137             envoy_config_route_v3_RouteAction_max_stream_duration(route_action);
1138     if (max_stream_duration != nullptr) {
1139       const google_protobuf_Duration* duration =
1140           envoy_config_route_v3_RouteAction_MaxStreamDuration_grpc_timeout_header_max(
1141               max_stream_duration);
1142       if (duration == nullptr) {
1143         duration =
1144             envoy_config_route_v3_RouteAction_MaxStreamDuration_max_stream_duration(
1145                 max_stream_duration);
1146       }
1147       if (duration != nullptr) {
1148         XdsApi::Duration duration_in_route;
1149         duration_in_route.seconds = google_protobuf_Duration_seconds(duration);
1150         duration_in_route.nanos = google_protobuf_Duration_nanos(duration);
1151         route->max_stream_duration = duration_in_route;
1152       }
1153     }
1154   }
1155   return GRPC_ERROR_NONE;
1156 }
1157
1158 grpc_error* RouteConfigParse(
1159     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1160     const envoy_config_route_v3_RouteConfiguration* route_config,
1161     XdsApi::RdsUpdate* rds_update) {
1162   MaybeLogRouteConfiguration(client, tracer, symtab, route_config);
1163   // Get the virtual hosts.
1164   size_t size;
1165   const envoy_config_route_v3_VirtualHost* const* virtual_hosts =
1166       envoy_config_route_v3_RouteConfiguration_virtual_hosts(route_config,
1167                                                              &size);
1168   for (size_t i = 0; i < size; ++i) {
1169     rds_update->virtual_hosts.emplace_back();
1170     XdsApi::RdsUpdate::VirtualHost& vhost = rds_update->virtual_hosts.back();
1171     // Parse domains.
1172     size_t domain_size;
1173     upb_strview const* domains = envoy_config_route_v3_VirtualHost_domains(
1174         virtual_hosts[i], &domain_size);
1175     for (size_t j = 0; j < domain_size; ++j) {
1176       std::string domain_pattern = UpbStringToStdString(domains[j]);
1177       const MatchType match_type = DomainPatternMatchType(domain_pattern);
1178       if (match_type == INVALID_MATCH) {
1179         return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1180             absl::StrCat("Invalid domain pattern \"", domain_pattern, "\".")
1181                 .c_str());
1182       }
1183       vhost.domains.emplace_back(std::move(domain_pattern));
1184     }
1185     if (vhost.domains.empty()) {
1186       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("VirtualHost has no domains");
1187     }
1188     // Parse routes.
1189     size_t num_routes;
1190     const envoy_config_route_v3_Route* const* routes =
1191         envoy_config_route_v3_VirtualHost_routes(virtual_hosts[i], &num_routes);
1192     if (num_routes < 1) {
1193       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1194           "No route found in the virtual host.");
1195     }
1196     // Loop over the whole list of routes
1197     for (size_t j = 0; j < num_routes; ++j) {
1198       const envoy_config_route_v3_RouteMatch* match =
1199           envoy_config_route_v3_Route_match(routes[j]);
1200       size_t query_parameters_size;
1201       static_cast<void>(envoy_config_route_v3_RouteMatch_query_parameters(
1202           match, &query_parameters_size));
1203       if (query_parameters_size > 0) {
1204         continue;
1205       }
1206       XdsApi::Route route;
1207       bool ignore_route = false;
1208       grpc_error* error = RoutePathMatchParse(match, &route, &ignore_route);
1209       if (error != GRPC_ERROR_NONE) return error;
1210       if (ignore_route) continue;
1211       error = RouteHeaderMatchersParse(match, &route);
1212       if (error != GRPC_ERROR_NONE) return error;
1213       error = RouteRuntimeFractionParse(match, &route);
1214       if (error != GRPC_ERROR_NONE) return error;
1215       error = RouteActionParse(routes[j], &route, &ignore_route);
1216       if (error != GRPC_ERROR_NONE) return error;
1217       if (ignore_route) continue;
1218       vhost.routes.emplace_back(std::move(route));
1219     }
1220     if (vhost.routes.empty()) {
1221       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No valid routes specified.");
1222     }
1223   }
1224   return GRPC_ERROR_NONE;
1225 }
1226
1227 XdsApi::CommonTlsContext::CertificateProviderInstance
1228 CertificateProviderInstanceParse(
1229     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance*
1230         certificate_provider_instance_proto) {
1231   return {
1232       UpbStringToStdString(
1233           envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance_instance_name(
1234               certificate_provider_instance_proto)),
1235       UpbStringToStdString(
1236           envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance_certificate_name(
1237               certificate_provider_instance_proto))};
1238 }
1239
1240 grpc_error* CommonTlsContextParse(
1241     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
1242         common_tls_context_proto,
1243     XdsApi::CommonTlsContext* common_tls_context) GRPC_MUST_USE_RESULT;
1244 grpc_error* CommonTlsContextParse(
1245     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
1246         common_tls_context_proto,
1247     XdsApi::CommonTlsContext* common_tls_context) {
1248   auto* combined_validation_context =
1249       envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_combined_validation_context(
1250           common_tls_context_proto);
1251   if (combined_validation_context != nullptr) {
1252     auto* default_validation_context =
1253         envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CombinedCertificateValidationContext_default_validation_context(
1254             combined_validation_context);
1255     if (default_validation_context != nullptr) {
1256       size_t len = 0;
1257       auto* subject_alt_names_matchers =
1258           envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_match_subject_alt_names(
1259               default_validation_context, &len);
1260       for (size_t i = 0; i < len; ++i) {
1261         StringMatcher::Type type;
1262         std::string matcher;
1263         if (envoy_type_matcher_v3_StringMatcher_has_exact(
1264                 subject_alt_names_matchers[i])) {
1265           type = StringMatcher::Type::EXACT;
1266           matcher =
1267               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_exact(
1268                   subject_alt_names_matchers[i]));
1269         } else if (envoy_type_matcher_v3_StringMatcher_has_prefix(
1270                        subject_alt_names_matchers[i])) {
1271           type = StringMatcher::Type::PREFIX;
1272           matcher =
1273               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_prefix(
1274                   subject_alt_names_matchers[i]));
1275         } else if (envoy_type_matcher_v3_StringMatcher_has_suffix(
1276                        subject_alt_names_matchers[i])) {
1277           type = StringMatcher::Type::SUFFIX;
1278           matcher =
1279               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_suffix(
1280                   subject_alt_names_matchers[i]));
1281         } else if (envoy_type_matcher_v3_StringMatcher_has_contains(
1282                        subject_alt_names_matchers[i])) {
1283           type = StringMatcher::Type::CONTAINS;
1284           matcher =
1285               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_contains(
1286                   subject_alt_names_matchers[i]));
1287         } else if (envoy_type_matcher_v3_StringMatcher_has_safe_regex(
1288                        subject_alt_names_matchers[i])) {
1289           type = StringMatcher::Type::SAFE_REGEX;
1290           auto* regex_matcher = envoy_type_matcher_v3_StringMatcher_safe_regex(
1291               subject_alt_names_matchers[i]);
1292           matcher = UpbStringToStdString(
1293               envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
1294         } else {
1295           return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1296               "Invalid StringMatcher specified");
1297         }
1298         bool ignore_case = envoy_type_matcher_v3_StringMatcher_ignore_case(
1299             subject_alt_names_matchers[i]);
1300         absl::StatusOr<StringMatcher> string_matcher =
1301             StringMatcher::Create(type, matcher,
1302                                   /*case_sensitive=*/!ignore_case);
1303         if (!string_matcher.ok()) {
1304           return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1305               absl::StrCat("string matcher: ",
1306                            string_matcher.status().message())
1307                   .c_str());
1308         }
1309         if (type == StringMatcher::Type::SAFE_REGEX && ignore_case) {
1310           return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1311               "StringMatcher: ignore_case has no effect for SAFE_REGEX.");
1312         }
1313         common_tls_context->combined_validation_context
1314             .default_validation_context.match_subject_alt_names.push_back(
1315                 std::move(string_matcher.value()));
1316       }
1317     }
1318     auto* validation_context_certificate_provider_instance =
1319         envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CombinedCertificateValidationContext_validation_context_certificate_provider_instance(
1320             combined_validation_context);
1321     if (validation_context_certificate_provider_instance != nullptr) {
1322       common_tls_context->combined_validation_context
1323           .validation_context_certificate_provider_instance =
1324           CertificateProviderInstanceParse(
1325               validation_context_certificate_provider_instance);
1326     }
1327   }
1328   auto* tls_certificate_certificate_provider_instance =
1329       envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_tls_certificate_certificate_provider_instance(
1330           common_tls_context_proto);
1331   if (tls_certificate_certificate_provider_instance != nullptr) {
1332     common_tls_context->tls_certificate_certificate_provider_instance =
1333         CertificateProviderInstanceParse(
1334             tls_certificate_certificate_provider_instance);
1335   }
1336   return GRPC_ERROR_NONE;
1337 }
1338
1339 grpc_error* LdsResponseParseClient(
1340     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab, upb_arena* arena,
1341     const envoy_config_listener_v3_ApiListener* api_listener,
1342     XdsApi::LdsUpdate* lds_update) {
1343   lds_update->type = XdsApi::LdsUpdate::ListenerType::kHttpApiListener;
1344   const upb_strview encoded_api_listener = google_protobuf_Any_value(
1345       envoy_config_listener_v3_ApiListener_api_listener(api_listener));
1346   const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager*
1347       http_connection_manager =
1348           envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_parse(
1349               encoded_api_listener.data, encoded_api_listener.size, arena);
1350   if (http_connection_manager == nullptr) {
1351     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1352         "Could not parse HttpConnectionManager config from ApiListener");
1353   }
1354   if (XdsTimeoutEnabled()) {
1355     // Obtain max_stream_duration from Http Protocol Options.
1356     const envoy_config_core_v3_HttpProtocolOptions* options =
1357         envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_common_http_protocol_options(
1358             http_connection_manager);
1359     if (options != nullptr) {
1360       const google_protobuf_Duration* duration =
1361           envoy_config_core_v3_HttpProtocolOptions_max_stream_duration(options);
1362       if (duration != nullptr) {
1363         lds_update->http_max_stream_duration.seconds =
1364             google_protobuf_Duration_seconds(duration);
1365         lds_update->http_max_stream_duration.nanos =
1366             google_protobuf_Duration_nanos(duration);
1367       }
1368     }
1369   }
1370   // Found inlined route_config. Parse it to find the cluster_name.
1371   if (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_route_config(
1372           http_connection_manager)) {
1373     const envoy_config_route_v3_RouteConfiguration* route_config =
1374         envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_config(
1375             http_connection_manager);
1376     XdsApi::RdsUpdate rds_update;
1377     grpc_error* error =
1378         RouteConfigParse(client, tracer, symtab, route_config, &rds_update);
1379     if (error != GRPC_ERROR_NONE) return error;
1380     lds_update->rds_update = std::move(rds_update);
1381     return GRPC_ERROR_NONE;
1382   }
1383   // Validate that RDS must be used to get the route_config dynamically.
1384   if (!envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_rds(
1385           http_connection_manager)) {
1386     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1387         "HttpConnectionManager neither has inlined route_config nor RDS.");
1388   }
1389   const envoy_extensions_filters_network_http_connection_manager_v3_Rds* rds =
1390       envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_rds(
1391           http_connection_manager);
1392   // Check that the ConfigSource specifies ADS.
1393   const envoy_config_core_v3_ConfigSource* config_source =
1394       envoy_extensions_filters_network_http_connection_manager_v3_Rds_config_source(
1395           rds);
1396   if (config_source == nullptr) {
1397     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1398         "HttpConnectionManager missing config_source for RDS.");
1399   }
1400   if (!envoy_config_core_v3_ConfigSource_has_ads(config_source)) {
1401     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1402         "HttpConnectionManager ConfigSource for RDS does not specify ADS.");
1403   }
1404   // Get the route_config_name.
1405   lds_update->route_config_name = UpbStringToStdString(
1406       envoy_extensions_filters_network_http_connection_manager_v3_Rds_route_config_name(
1407           rds));
1408   return GRPC_ERROR_NONE;
1409 }
1410
1411 grpc_error* LdsResponseParseServer(
1412     upb_arena* arena, const envoy_config_listener_v3_Listener* listener,
1413     const std::string& /*listener_name*/,
1414     const envoy_config_core_v3_Address* /*address*/,
1415     XdsApi::LdsUpdate* lds_update) {
1416   lds_update->type = XdsApi::LdsUpdate::ListenerType::kTcpListener;
1417   // TODO(yashykt): Support filter chain match.
1418   // Right now, we are supporting and expecting only one entry in filter_chains.
1419   size_t size = 0;
1420   auto* filter_chains =
1421       envoy_config_listener_v3_Listener_filter_chains(listener, &size);
1422   if (size != 1) {
1423     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1424         "Only one filter_chain supported.");
1425   }
1426   // Get the DownstreamTlsContext from the match
1427   if (XdsSecurityEnabled()) {
1428     auto* transport_socket =
1429         envoy_config_listener_v3_FilterChain_transport_socket(filter_chains[0]);
1430     if (transport_socket != nullptr) {
1431       absl::string_view name = UpbStringToAbsl(
1432           envoy_config_core_v3_TransportSocket_name(transport_socket));
1433       if (name == "envoy.transport_sockets.tls") {
1434         auto* typed_config =
1435             envoy_config_core_v3_TransportSocket_typed_config(transport_socket);
1436         if (typed_config != nullptr) {
1437           const upb_strview encoded_downstream_tls_context =
1438               google_protobuf_Any_value(typed_config);
1439           auto* downstream_tls_context =
1440               envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_parse(
1441                   encoded_downstream_tls_context.data,
1442                   encoded_downstream_tls_context.size, arena);
1443           if (downstream_tls_context == nullptr) {
1444             return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1445                 "Can't decode downstream tls context.");
1446           }
1447           auto* common_tls_context =
1448               envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_common_tls_context(
1449                   downstream_tls_context);
1450           if (common_tls_context != nullptr) {
1451             grpc_error* error = CommonTlsContextParse(
1452                 common_tls_context,
1453                 &lds_update->downstream_tls_context.common_tls_context);
1454             if (error != GRPC_ERROR_NONE) return error;
1455           }
1456           auto* require_client_certificate =
1457               envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_require_client_certificate(
1458                   downstream_tls_context);
1459           if (require_client_certificate != nullptr) {
1460             lds_update->downstream_tls_context.require_client_certificate =
1461                 google_protobuf_BoolValue_value(require_client_certificate);
1462           }
1463         }
1464         if (lds_update->downstream_tls_context.common_tls_context
1465                 .tls_certificate_certificate_provider_instance.instance_name
1466                 .empty()) {
1467           return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1468               "TLS configuration provided but no "
1469               "tls_certificate_certificate_provider_instance found.");
1470         }
1471       }
1472     }
1473   }
1474   return GRPC_ERROR_NONE;
1475 }
1476
1477 grpc_error* LdsResponseParse(
1478     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1479     const envoy_service_discovery_v3_DiscoveryResponse* response,
1480     const std::set<absl::string_view>& expected_listener_names,
1481     XdsApi::LdsUpdateMap* lds_update_map,
1482     std::set<std::string>* resource_names_failed, upb_arena* arena) {
1483   std::vector<grpc_error*> errors;
1484   // Get the resources from the response.
1485   size_t size;
1486   const google_protobuf_Any* const* resources =
1487       envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
1488   for (size_t i = 0; i < size; ++i) {
1489     // Check the type_url of the resource.
1490     absl::string_view type_url =
1491         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
1492     if (!IsLds(type_url)) {
1493       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1494           absl::StrCat("resource index ", i, ": Resource is not LDS.")
1495               .c_str()));
1496       continue;
1497     }
1498     // Decode the listener.
1499     const upb_strview encoded_listener =
1500         google_protobuf_Any_value(resources[i]);
1501     const envoy_config_listener_v3_Listener* listener =
1502         envoy_config_listener_v3_Listener_parse(encoded_listener.data,
1503                                                 encoded_listener.size, arena);
1504     if (listener == nullptr) {
1505       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1506           absl::StrCat("resource index ", i, ": Can't decode listener.")
1507               .c_str()));
1508       continue;
1509     }
1510     // Check listener name. Ignore unexpected listeners.
1511     std::string listener_name =
1512         UpbStringToStdString(envoy_config_listener_v3_Listener_name(listener));
1513     if (expected_listener_names.find(listener_name) ==
1514         expected_listener_names.end()) {
1515       continue;
1516     }
1517     // Fail if listener name is duplicated.
1518     if (lds_update_map->find(listener_name) != lds_update_map->end()) {
1519       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1520           absl::StrCat("duplicate listener name \"", listener_name, "\"")
1521               .c_str()));
1522       resource_names_failed->insert(listener_name);
1523       continue;
1524     }
1525     XdsApi::LdsUpdate& lds_update = (*lds_update_map)[listener_name];
1526     // Check whether it's a client or server listener.
1527     const envoy_config_listener_v3_ApiListener* api_listener =
1528         envoy_config_listener_v3_Listener_api_listener(listener);
1529     const envoy_config_core_v3_Address* address =
1530         envoy_config_listener_v3_Listener_address(listener);
1531     if (api_listener != nullptr && address != nullptr) {
1532       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1533           absl::StrCat(listener_name,
1534                        ": Listener has both address and ApiListener")
1535               .c_str()));
1536       resource_names_failed->insert(listener_name);
1537       continue;
1538     }
1539     if (api_listener == nullptr && address == nullptr) {
1540       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1541           absl::StrCat(listener_name,
1542                        ": Listener has neither address nor ApiListener")
1543               .c_str()));
1544       resource_names_failed->insert(listener_name);
1545       continue;
1546     }
1547     grpc_error* error = GRPC_ERROR_NONE;
1548     if (api_listener != nullptr) {
1549       error = LdsResponseParseClient(client, tracer, symtab, arena,
1550                                      api_listener, &lds_update);
1551     } else {
1552       error = LdsResponseParseServer(arena, listener, listener_name, address,
1553                                      &lds_update);
1554     }
1555     if (error != GRPC_ERROR_NONE) {
1556       errors.push_back(grpc_error_add_child(
1557           GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1558               absl::StrCat(listener_name, ": validation error").c_str()),
1559           error));
1560       resource_names_failed->insert(listener_name);
1561     }
1562   }
1563   return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing LDS response", &errors);
1564 }
1565
1566 grpc_error* RdsResponseParse(
1567     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1568     const envoy_service_discovery_v3_DiscoveryResponse* response,
1569     const std::set<absl::string_view>& expected_route_configuration_names,
1570     XdsApi::RdsUpdateMap* rds_update_map,
1571     std::set<std::string>* resource_names_failed, upb_arena* arena) {
1572   std::vector<grpc_error*> errors;
1573   // Get the resources from the response.
1574   size_t size;
1575   const google_protobuf_Any* const* resources =
1576       envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
1577   for (size_t i = 0; i < size; ++i) {
1578     // Check the type_url of the resource.
1579     absl::string_view type_url =
1580         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
1581     if (!IsRds(type_url)) {
1582       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1583           absl::StrCat("resource index ", i, ": Resource is not RDS.")
1584               .c_str()));
1585       continue;
1586     }
1587     // Decode the route_config.
1588     const upb_strview encoded_route_config =
1589         google_protobuf_Any_value(resources[i]);
1590     const envoy_config_route_v3_RouteConfiguration* route_config =
1591         envoy_config_route_v3_RouteConfiguration_parse(
1592             encoded_route_config.data, encoded_route_config.size, arena);
1593     if (route_config == nullptr) {
1594       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1595           absl::StrCat("resource index ", i, ": Can't decode route_config.")
1596               .c_str()));
1597       continue;
1598     }
1599     // Check route_config_name. Ignore unexpected route_config.
1600     std::string route_config_name = UpbStringToStdString(
1601         envoy_config_route_v3_RouteConfiguration_name(route_config));
1602     if (expected_route_configuration_names.find(route_config_name) ==
1603         expected_route_configuration_names.end()) {
1604       continue;
1605     }
1606     // Fail if route config name is duplicated.
1607     if (rds_update_map->find(route_config_name) != rds_update_map->end()) {
1608       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1609           absl::StrCat("duplicate route config name \"", route_config_name,
1610                        "\"")
1611               .c_str()));
1612       resource_names_failed->insert(route_config_name);
1613       continue;
1614     }
1615     // Parse the route_config.
1616     XdsApi::RdsUpdate& rds_update = (*rds_update_map)[route_config_name];
1617     grpc_error* error =
1618         RouteConfigParse(client, tracer, symtab, route_config, &rds_update);
1619     if (error != GRPC_ERROR_NONE) {
1620       errors.push_back(grpc_error_add_child(
1621           GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1622               absl::StrCat(route_config_name, ": validation error").c_str()),
1623           error));
1624       resource_names_failed->insert(route_config_name);
1625     }
1626   }
1627   return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing RDS response", &errors);
1628 }
1629
1630 grpc_error* CdsResponseParse(
1631     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1632     const envoy_service_discovery_v3_DiscoveryResponse* response,
1633     const std::set<absl::string_view>& expected_cluster_names,
1634     XdsApi::CdsUpdateMap* cds_update_map,
1635     std::set<std::string>* resource_names_failed, upb_arena* arena) {
1636   std::vector<grpc_error*> errors;
1637   // Get the resources from the response.
1638   size_t size;
1639   const google_protobuf_Any* const* resources =
1640       envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
1641   // Parse all the resources in the CDS response.
1642   for (size_t i = 0; i < size; ++i) {
1643     // Check the type_url of the resource.
1644     absl::string_view type_url =
1645         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
1646     if (!IsCds(type_url)) {
1647       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1648           absl::StrCat("resource index ", i, ": Resource is not CDS.")
1649               .c_str()));
1650       continue;
1651     }
1652     // Decode the cluster.
1653     const upb_strview encoded_cluster = google_protobuf_Any_value(resources[i]);
1654     const envoy_config_cluster_v3_Cluster* cluster =
1655         envoy_config_cluster_v3_Cluster_parse(encoded_cluster.data,
1656                                               encoded_cluster.size, arena);
1657     if (cluster == nullptr) {
1658       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1659           absl::StrCat("resource index ", i, ": Can't decode cluster.")
1660               .c_str()));
1661       continue;
1662     }
1663     MaybeLogCluster(client, tracer, symtab, cluster);
1664     // Ignore unexpected cluster names.
1665     std::string cluster_name =
1666         UpbStringToStdString(envoy_config_cluster_v3_Cluster_name(cluster));
1667     if (expected_cluster_names.find(cluster_name) ==
1668         expected_cluster_names.end()) {
1669       continue;
1670     }
1671     // Fail on duplicate resources.
1672     if (cds_update_map->find(cluster_name) != cds_update_map->end()) {
1673       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1674           absl::StrCat("duplicate resource name \"", cluster_name, "\"")
1675               .c_str()));
1676       resource_names_failed->insert(cluster_name);
1677       continue;
1678     }
1679     XdsApi::CdsUpdate& cds_update = (*cds_update_map)[cluster_name];
1680     // Check the cluster_discovery_type.
1681     if (!envoy_config_cluster_v3_Cluster_has_type(cluster) &&
1682         !envoy_config_cluster_v3_Cluster_has_cluster_type(cluster)) {
1683       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1684           absl::StrCat(cluster_name, ": DiscoveryType not found.").c_str()));
1685       resource_names_failed->insert(cluster_name);
1686       continue;
1687     }
1688     if (envoy_config_cluster_v3_Cluster_type(cluster) ==
1689         envoy_config_cluster_v3_Cluster_EDS) {
1690       cds_update.cluster_type = XdsApi::CdsUpdate::ClusterType::EDS;
1691       // Check the EDS config source.
1692       const envoy_config_cluster_v3_Cluster_EdsClusterConfig*
1693           eds_cluster_config =
1694               envoy_config_cluster_v3_Cluster_eds_cluster_config(cluster);
1695       const envoy_config_core_v3_ConfigSource* eds_config =
1696           envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_config(
1697               eds_cluster_config);
1698       if (!envoy_config_core_v3_ConfigSource_has_ads(eds_config)) {
1699         errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1700             absl::StrCat(cluster_name, ": EDS ConfigSource is not ADS.")
1701                 .c_str()));
1702         resource_names_failed->insert(cluster_name);
1703         continue;
1704       }
1705       // Record EDS service_name (if any).
1706       upb_strview service_name =
1707           envoy_config_cluster_v3_Cluster_EdsClusterConfig_service_name(
1708               eds_cluster_config);
1709       if (service_name.size != 0) {
1710         cds_update.eds_service_name = UpbStringToStdString(service_name);
1711       }
1712     } else if (!XdsAggregateAndLogicalDnsClusterEnabled()) {
1713       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1714           absl::StrCat(cluster_name, ": DiscoveryType is not valid.").c_str()));
1715       resource_names_failed->insert(cluster_name);
1716       continue;
1717     } else if (envoy_config_cluster_v3_Cluster_type(cluster) ==
1718                envoy_config_cluster_v3_Cluster_LOGICAL_DNS) {
1719       cds_update.cluster_type = XdsApi::CdsUpdate::ClusterType::LOGICAL_DNS;
1720     } else {
1721       if (envoy_config_cluster_v3_Cluster_has_cluster_type(cluster)) {
1722         const envoy_config_cluster_v3_Cluster_CustomClusterType*
1723             custom_cluster_type =
1724                 envoy_config_cluster_v3_Cluster_cluster_type(cluster);
1725         upb_strview type_name =
1726             envoy_config_cluster_v3_Cluster_CustomClusterType_name(
1727                 custom_cluster_type);
1728         if (UpbStringToAbsl(type_name) == "envoy.clusters.aggregate") {
1729           cds_update.cluster_type = XdsApi::CdsUpdate::ClusterType::AGGREGATE;
1730           // Retrieve aggregate clusters.
1731           const google_protobuf_Any* typed_config =
1732               envoy_config_cluster_v3_Cluster_CustomClusterType_typed_config(
1733                   custom_cluster_type);
1734           const upb_strview aggregate_cluster_config_upb_strview =
1735               google_protobuf_Any_value(typed_config);
1736           const envoy_extensions_clusters_aggregate_v3_ClusterConfig*
1737               aggregate_cluster_config =
1738                   envoy_extensions_clusters_aggregate_v3_ClusterConfig_parse(
1739                       aggregate_cluster_config_upb_strview.data,
1740                       aggregate_cluster_config_upb_strview.size, arena);
1741           if (aggregate_cluster_config == nullptr) {
1742             errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1743                 absl::StrCat(cluster_name, ": Can't parse aggregate cluster.")
1744                     .c_str()));
1745             resource_names_failed->insert(cluster_name);
1746             continue;
1747           }
1748           size_t size;
1749           const upb_strview* clusters =
1750               envoy_extensions_clusters_aggregate_v3_ClusterConfig_clusters(
1751                   aggregate_cluster_config, &size);
1752           for (size_t i = 0; i < size; ++i) {
1753             const upb_strview cluster = clusters[i];
1754             cds_update.prioritized_cluster_names.emplace_back(
1755                 UpbStringToStdString(cluster));
1756           }
1757         } else {
1758           errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1759               absl::StrCat(cluster_name, ": DiscoveryType is not valid.")
1760                   .c_str()));
1761           resource_names_failed->insert(cluster_name);
1762           continue;
1763         }
1764       } else {
1765         errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1766             absl::StrCat(cluster_name, ": DiscoveryType is not valid.")
1767                 .c_str()));
1768         resource_names_failed->insert(cluster_name);
1769         continue;
1770       }
1771     }
1772     // Check the LB policy.
1773     if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
1774         envoy_config_cluster_v3_Cluster_ROUND_ROBIN) {
1775       cds_update.lb_policy = "ROUND_ROBIN";
1776     } else if (XdsRingHashEnabled() &&
1777                envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
1778                    envoy_config_cluster_v3_Cluster_RING_HASH) {
1779       cds_update.lb_policy = "RING_HASH";
1780       // Record ring hash lb config
1781       auto* ring_hash_config =
1782           envoy_config_cluster_v3_Cluster_ring_hash_lb_config(cluster);
1783       if (ring_hash_config == nullptr) {
1784         errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1785             absl::StrCat(cluster_name,
1786                          ": ring hash lb config required but not present.")
1787                 .c_str()));
1788         resource_names_failed->insert(cluster_name);
1789         continue;
1790       }
1791       const google_protobuf_UInt64Value* max_ring_size =
1792           envoy_config_cluster_v3_Cluster_RingHashLbConfig_maximum_ring_size(
1793               ring_hash_config);
1794       if (max_ring_size != nullptr) {
1795         cds_update.max_ring_size =
1796             google_protobuf_UInt64Value_value(max_ring_size);
1797         if (cds_update.max_ring_size > 8388608 ||
1798             cds_update.max_ring_size == 0) {
1799           errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1800               absl::StrCat(
1801                   cluster_name,
1802                   ": max_ring_size is not in the range of 1 to 8388608.")
1803                   .c_str()));
1804           resource_names_failed->insert(cluster_name);
1805           continue;
1806         }
1807       }
1808       const google_protobuf_UInt64Value* min_ring_size =
1809           envoy_config_cluster_v3_Cluster_RingHashLbConfig_minimum_ring_size(
1810               ring_hash_config);
1811       if (min_ring_size != nullptr) {
1812         cds_update.min_ring_size =
1813             google_protobuf_UInt64Value_value(min_ring_size);
1814         if (cds_update.min_ring_size > 8388608 ||
1815             cds_update.min_ring_size == 0) {
1816           errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1817               absl::StrCat(
1818                   cluster_name,
1819                   ": min_ring_size is not in the range of 1 to 8388608.")
1820                   .c_str()));
1821           resource_names_failed->insert(cluster_name);
1822           continue;
1823         }
1824         if (cds_update.min_ring_size > cds_update.max_ring_size) {
1825           errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1826               absl::StrCat(
1827                   cluster_name,
1828                   ": min_ring_size cannot be greater than max_ring_size.")
1829                   .c_str()));
1830           resource_names_failed->insert(cluster_name);
1831           continue;
1832         }
1833       }
1834       if (envoy_config_cluster_v3_Cluster_RingHashLbConfig_hash_function(
1835               ring_hash_config) ==
1836           envoy_config_cluster_v3_Cluster_RingHashLbConfig_XX_HASH) {
1837         cds_update.hash_function = XdsApi::CdsUpdate::HashFunction::XX_HASH;
1838       } else if (
1839           envoy_config_cluster_v3_Cluster_RingHashLbConfig_hash_function(
1840               ring_hash_config) ==
1841           envoy_config_cluster_v3_Cluster_RingHashLbConfig_MURMUR_HASH_2) {
1842         cds_update.hash_function =
1843             XdsApi::CdsUpdate::HashFunction::MURMUR_HASH_2;
1844       } else {
1845         errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1846             absl::StrCat(cluster_name,
1847                          ": ring hash lb config has invalid hash function.")
1848                 .c_str()));
1849         resource_names_failed->insert(cluster_name);
1850         continue;
1851       }
1852     } else {
1853       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1854           absl::StrCat(cluster_name, ": LB policy is not supported.").c_str()));
1855       resource_names_failed->insert(cluster_name);
1856       continue;
1857     }
1858     if (XdsSecurityEnabled()) {
1859       // Record Upstream tls context
1860       auto* transport_socket =
1861           envoy_config_cluster_v3_Cluster_transport_socket(cluster);
1862       if (transport_socket != nullptr) {
1863         absl::string_view name = UpbStringToAbsl(
1864             envoy_config_core_v3_TransportSocket_name(transport_socket));
1865         if (name == "envoy.transport_sockets.tls") {
1866           auto* typed_config =
1867               envoy_config_core_v3_TransportSocket_typed_config(
1868                   transport_socket);
1869           if (typed_config != nullptr) {
1870             const upb_strview encoded_upstream_tls_context =
1871                 google_protobuf_Any_value(typed_config);
1872             auto* upstream_tls_context =
1873                 envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_parse(
1874                     encoded_upstream_tls_context.data,
1875                     encoded_upstream_tls_context.size, arena);
1876             if (upstream_tls_context == nullptr) {
1877               errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1878                   absl::StrCat(cluster_name,
1879                                ": Can't decode upstream tls context.")
1880                       .c_str()));
1881               resource_names_failed->insert(cluster_name);
1882               continue;
1883             }
1884             auto* common_tls_context =
1885                 envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_common_tls_context(
1886                     upstream_tls_context);
1887             if (common_tls_context != nullptr) {
1888               grpc_error* error = CommonTlsContextParse(
1889                   common_tls_context, &cds_update.common_tls_context);
1890               if (error != GRPC_ERROR_NONE) {
1891                 errors.push_back(grpc_error_add_child(
1892                     GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1893                         absl::StrCat(cluster_name, ": error in TLS context")
1894                             .c_str()),
1895                     error));
1896                 resource_names_failed->insert(cluster_name);
1897                 continue;
1898               }
1899             }
1900           }
1901           if (cds_update.common_tls_context.combined_validation_context
1902                   .validation_context_certificate_provider_instance
1903                   .instance_name.empty()) {
1904             errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1905                 absl::StrCat(cluster_name,
1906                              "TLS configuration provided but no "
1907                              "validation_context_certificate_provider_instance "
1908                              "found.")
1909                     .c_str()));
1910             resource_names_failed->insert(cluster_name);
1911             continue;
1912           }
1913         }
1914       }
1915     }
1916     // Record LRS server name (if any).
1917     const envoy_config_core_v3_ConfigSource* lrs_server =
1918         envoy_config_cluster_v3_Cluster_lrs_server(cluster);
1919     if (lrs_server != nullptr) {
1920       if (!envoy_config_core_v3_ConfigSource_has_self(lrs_server)) {
1921         errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1922             absl::StrCat(cluster_name, ": LRS ConfigSource is not self.")
1923                 .c_str()));
1924         resource_names_failed->insert(cluster_name);
1925         continue;
1926       }
1927       cds_update.lrs_load_reporting_server_name.emplace("");
1928     }
1929     // The Cluster resource encodes the circuit breaking parameters in a list of
1930     // Thresholds messages, where each message specifies the parameters for a
1931     // particular RoutingPriority. we will look only at the first entry in the
1932     // list for priority DEFAULT and default to 1024 if not found.
1933     if (envoy_config_cluster_v3_Cluster_has_circuit_breakers(cluster)) {
1934       const envoy_config_cluster_v3_CircuitBreakers* circuit_breakers =
1935           envoy_config_cluster_v3_Cluster_circuit_breakers(cluster);
1936       size_t num_thresholds;
1937       const envoy_config_cluster_v3_CircuitBreakers_Thresholds* const*
1938           thresholds = envoy_config_cluster_v3_CircuitBreakers_thresholds(
1939               circuit_breakers, &num_thresholds);
1940       for (size_t i = 0; i < num_thresholds; ++i) {
1941         const auto* threshold = thresholds[i];
1942         if (envoy_config_cluster_v3_CircuitBreakers_Thresholds_priority(
1943                 threshold) == envoy_config_core_v3_DEFAULT) {
1944           const google_protobuf_UInt32Value* max_requests =
1945               envoy_config_cluster_v3_CircuitBreakers_Thresholds_max_requests(
1946                   threshold);
1947           if (max_requests != nullptr) {
1948             cds_update.max_concurrent_requests =
1949                 google_protobuf_UInt32Value_value(max_requests);
1950           }
1951           break;
1952         }
1953       }
1954     }
1955   }
1956   return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing CDS response", &errors);
1957 }
1958
1959 grpc_error* ServerAddressParseAndAppend(
1960     const envoy_config_endpoint_v3_LbEndpoint* lb_endpoint,
1961     ServerAddressList* list) {
1962   // If health_status is not HEALTHY or UNKNOWN, skip this endpoint.
1963   const int32_t health_status =
1964       envoy_config_endpoint_v3_LbEndpoint_health_status(lb_endpoint);
1965   if (health_status != envoy_config_core_v3_UNKNOWN &&
1966       health_status != envoy_config_core_v3_HEALTHY) {
1967     return GRPC_ERROR_NONE;
1968   }
1969   // Find the ip:port.
1970   const envoy_config_endpoint_v3_Endpoint* endpoint =
1971       envoy_config_endpoint_v3_LbEndpoint_endpoint(lb_endpoint);
1972   const envoy_config_core_v3_Address* address =
1973       envoy_config_endpoint_v3_Endpoint_address(endpoint);
1974   const envoy_config_core_v3_SocketAddress* socket_address =
1975       envoy_config_core_v3_Address_socket_address(address);
1976   std::string address_str = UpbStringToStdString(
1977       envoy_config_core_v3_SocketAddress_address(socket_address));
1978   uint32_t port = envoy_config_core_v3_SocketAddress_port_value(socket_address);
1979   if (GPR_UNLIKELY(port >> 16) != 0) {
1980     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid port.");
1981   }
1982   // Populate grpc_resolved_address.
1983   grpc_resolved_address addr;
1984   grpc_string_to_sockaddr(&addr, address_str.c_str(), port);
1985   // Append the address to the list.
1986   list->emplace_back(addr, nullptr);
1987   return GRPC_ERROR_NONE;
1988 }
1989
1990 grpc_error* LocalityParse(
1991     const envoy_config_endpoint_v3_LocalityLbEndpoints* locality_lb_endpoints,
1992     XdsApi::EdsUpdate::Priority::Locality* output_locality, size_t* priority) {
1993   // Parse LB weight.
1994   const google_protobuf_UInt32Value* lb_weight =
1995       envoy_config_endpoint_v3_LocalityLbEndpoints_load_balancing_weight(
1996           locality_lb_endpoints);
1997   // If LB weight is not specified, it means this locality is assigned no load.
1998   // TODO(juanlishen): When we support CDS to configure the inter-locality
1999   // policy, we should change the LB weight handling.
2000   output_locality->lb_weight =
2001       lb_weight != nullptr ? google_protobuf_UInt32Value_value(lb_weight) : 0;
2002   if (output_locality->lb_weight == 0) return GRPC_ERROR_NONE;
2003   // Parse locality name.
2004   const envoy_config_core_v3_Locality* locality =
2005       envoy_config_endpoint_v3_LocalityLbEndpoints_locality(
2006           locality_lb_endpoints);
2007   std::string region =
2008       UpbStringToStdString(envoy_config_core_v3_Locality_region(locality));
2009   std::string zone =
2010       UpbStringToStdString(envoy_config_core_v3_Locality_region(locality));
2011   std::string sub_zone =
2012       UpbStringToStdString(envoy_config_core_v3_Locality_sub_zone(locality));
2013   output_locality->name = MakeRefCounted<XdsLocalityName>(
2014       std::move(region), std::move(zone), std::move(sub_zone));
2015   // Parse the addresses.
2016   size_t size;
2017   const envoy_config_endpoint_v3_LbEndpoint* const* lb_endpoints =
2018       envoy_config_endpoint_v3_LocalityLbEndpoints_lb_endpoints(
2019           locality_lb_endpoints, &size);
2020   for (size_t i = 0; i < size; ++i) {
2021     grpc_error* error = ServerAddressParseAndAppend(
2022         lb_endpoints[i], &output_locality->endpoints);
2023     if (error != GRPC_ERROR_NONE) return error;
2024   }
2025   // Parse the priority.
2026   *priority = envoy_config_endpoint_v3_LocalityLbEndpoints_priority(
2027       locality_lb_endpoints);
2028   return GRPC_ERROR_NONE;
2029 }
2030
2031 grpc_error* DropParseAndAppend(
2032     const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload*
2033         drop_overload,
2034     XdsApi::EdsUpdate::DropConfig* drop_config) {
2035   // Get the category.
2036   std::string category = UpbStringToStdString(
2037       envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload_category(
2038           drop_overload));
2039   if (category.empty()) {
2040     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty drop category name");
2041   }
2042   // Get the drop rate (per million).
2043   const envoy_type_v3_FractionalPercent* drop_percentage =
2044       envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload_drop_percentage(
2045           drop_overload);
2046   uint32_t numerator =
2047       envoy_type_v3_FractionalPercent_numerator(drop_percentage);
2048   const auto denominator =
2049       static_cast<envoy_type_v3_FractionalPercent_DenominatorType>(
2050           envoy_type_v3_FractionalPercent_denominator(drop_percentage));
2051   // Normalize to million.
2052   switch (denominator) {
2053     case envoy_type_v3_FractionalPercent_HUNDRED:
2054       numerator *= 10000;
2055       break;
2056     case envoy_type_v3_FractionalPercent_TEN_THOUSAND:
2057       numerator *= 100;
2058       break;
2059     case envoy_type_v3_FractionalPercent_MILLION:
2060       break;
2061     default:
2062       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unknown denominator type");
2063   }
2064   // Cap numerator to 1000000.
2065   numerator = GPR_MIN(numerator, 1000000);
2066   drop_config->AddCategory(std::move(category), numerator);
2067   return GRPC_ERROR_NONE;
2068 }
2069
2070 grpc_error* EdsResponseParse(
2071     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
2072     const envoy_service_discovery_v3_DiscoveryResponse* response,
2073     const std::set<absl::string_view>& expected_eds_service_names,
2074     XdsApi::EdsUpdateMap* eds_update_map,
2075     std::set<std::string>* resource_names_failed, upb_arena* arena) {
2076   std::vector<grpc_error*> errors;
2077   // Get the resources from the response.
2078   size_t size;
2079   const google_protobuf_Any* const* resources =
2080       envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
2081   for (size_t i = 0; i < size; ++i) {
2082     // Check the type_url of the resource.
2083     absl::string_view type_url =
2084         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
2085     if (!IsEds(type_url)) {
2086       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
2087           absl::StrCat("resource index ", i, ": Resource is not EDS.")
2088               .c_str()));
2089       continue;
2090     }
2091     // Get the cluster_load_assignment.
2092     upb_strview encoded_cluster_load_assignment =
2093         google_protobuf_Any_value(resources[i]);
2094     envoy_config_endpoint_v3_ClusterLoadAssignment* cluster_load_assignment =
2095         envoy_config_endpoint_v3_ClusterLoadAssignment_parse(
2096             encoded_cluster_load_assignment.data,
2097             encoded_cluster_load_assignment.size, arena);
2098     if (cluster_load_assignment == nullptr) {
2099       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
2100           absl::StrCat("resource index ", i,
2101                        ": Can't parse cluster_load_assignment.")
2102               .c_str()));
2103       continue;
2104     }
2105     MaybeLogClusterLoadAssignment(client, tracer, symtab,
2106                                   cluster_load_assignment);
2107     // Check the EDS service name.  Ignore unexpected names.
2108     std::string eds_service_name = UpbStringToStdString(
2109         envoy_config_endpoint_v3_ClusterLoadAssignment_cluster_name(
2110             cluster_load_assignment));
2111     if (expected_eds_service_names.find(eds_service_name) ==
2112         expected_eds_service_names.end()) {
2113       continue;
2114     }
2115     // Fail on duplicate resources.
2116     if (eds_update_map->find(eds_service_name) != eds_update_map->end()) {
2117       errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
2118           absl::StrCat("duplicate resource name \"", eds_service_name, "\"")
2119               .c_str()));
2120       resource_names_failed->insert(eds_service_name);
2121       continue;
2122     }
2123     XdsApi::EdsUpdate& eds_update = (*eds_update_map)[eds_service_name];
2124     // Get the endpoints.
2125     size_t locality_size;
2126     const envoy_config_endpoint_v3_LocalityLbEndpoints* const* endpoints =
2127         envoy_config_endpoint_v3_ClusterLoadAssignment_endpoints(
2128             cluster_load_assignment, &locality_size);
2129     grpc_error* error = GRPC_ERROR_NONE;
2130     for (size_t j = 0; j < locality_size; ++j) {
2131       size_t priority;
2132       XdsApi::EdsUpdate::Priority::Locality locality;
2133       error = LocalityParse(endpoints[j], &locality, &priority);
2134       if (error != GRPC_ERROR_NONE) break;
2135       // Filter out locality with weight 0.
2136       if (locality.lb_weight == 0) continue;
2137       // Make sure prorities is big enough. Note that they might not
2138       // arrive in priority order.
2139       while (eds_update.priorities.size() < priority + 1) {
2140         eds_update.priorities.emplace_back();
2141       }
2142       eds_update.priorities[priority].localities.emplace(locality.name.get(),
2143                                                          std::move(locality));
2144     }
2145     if (error != GRPC_ERROR_NONE) {
2146       errors.push_back(grpc_error_add_child(
2147           GRPC_ERROR_CREATE_FROM_COPIED_STRING(
2148               absl::StrCat(eds_service_name, ": locality validation error")
2149                   .c_str()),
2150           error));
2151       resource_names_failed->insert(eds_service_name);
2152       continue;
2153     }
2154     for (const auto& priority : eds_update.priorities) {
2155       if (priority.localities.empty()) {
2156         errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
2157             absl::StrCat(eds_service_name, ": sparse priority list").c_str()));
2158         resource_names_failed->insert(eds_service_name);
2159         continue;
2160       }
2161     }
2162     // Get the drop config.
2163     eds_update.drop_config = MakeRefCounted<XdsApi::EdsUpdate::DropConfig>();
2164     const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy* policy =
2165         envoy_config_endpoint_v3_ClusterLoadAssignment_policy(
2166             cluster_load_assignment);
2167     if (policy != nullptr) {
2168       size_t drop_size;
2169       const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload* const*
2170           drop_overload =
2171               envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_drop_overloads(
2172                   policy, &drop_size);
2173       for (size_t j = 0; j < drop_size; ++j) {
2174         error =
2175             DropParseAndAppend(drop_overload[j], eds_update.drop_config.get());
2176         if (error != GRPC_ERROR_NONE) break;
2177       }
2178       if (error != GRPC_ERROR_NONE) {
2179         errors.push_back(grpc_error_add_child(
2180             GRPC_ERROR_CREATE_FROM_COPIED_STRING(
2181                 absl::StrCat(eds_service_name, ": drop config validation error")
2182                     .c_str()),
2183             error));
2184         resource_names_failed->insert(eds_service_name);
2185         continue;
2186       }
2187     }
2188   }
2189   return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing EDS response", &errors);
2190 }
2191
2192 std::string TypeUrlInternalToExternal(absl::string_view type_url) {
2193   if (type_url == kLdsV2TypeUrl) {
2194     return XdsApi::kLdsTypeUrl;
2195   } else if (type_url == kRdsV2TypeUrl) {
2196     return XdsApi::kRdsTypeUrl;
2197   } else if (type_url == kCdsV2TypeUrl) {
2198     return XdsApi::kCdsTypeUrl;
2199   } else if (type_url == kEdsV2TypeUrl) {
2200     return XdsApi::kEdsTypeUrl;
2201   }
2202   return std::string(type_url);
2203 }
2204
2205 template <typename UpdateMap>
2206 void MoveUpdatesToFailedSet(UpdateMap* update_map,
2207                             std::set<std::string>* resource_names_failed) {
2208   for (const auto& p : *update_map) {
2209     resource_names_failed->insert(p.first);
2210   }
2211   update_map->clear();
2212 }
2213
2214 }  // namespace
2215
2216 XdsApi::AdsParseResult XdsApi::ParseAdsResponse(
2217     const grpc_slice& encoded_response,
2218     const std::set<absl::string_view>& expected_listener_names,
2219     const std::set<absl::string_view>& expected_route_configuration_names,
2220     const std::set<absl::string_view>& expected_cluster_names,
2221     const std::set<absl::string_view>& expected_eds_service_names) {
2222   AdsParseResult result;
2223   upb::Arena arena;
2224   // Decode the response.
2225   const envoy_service_discovery_v3_DiscoveryResponse* response =
2226       envoy_service_discovery_v3_DiscoveryResponse_parse(
2227           reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(encoded_response)),
2228           GRPC_SLICE_LENGTH(encoded_response), arena.ptr());
2229   // If decoding fails, output an empty type_url and return.
2230   if (response == nullptr) {
2231     result.parse_error =
2232         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode DiscoveryResponse.");
2233     return result;
2234   }
2235   MaybeLogDiscoveryResponse(client_, tracer_, symtab_.ptr(), response);
2236   // Record the type_url, the version_info, and the nonce of the response.
2237   result.type_url = TypeUrlInternalToExternal(UpbStringToAbsl(
2238       envoy_service_discovery_v3_DiscoveryResponse_type_url(response)));
2239   result.version = UpbStringToStdString(
2240       envoy_service_discovery_v3_DiscoveryResponse_version_info(response));
2241   result.nonce = UpbStringToStdString(
2242       envoy_service_discovery_v3_DiscoveryResponse_nonce(response));
2243   // Parse the response according to the resource type.
2244   if (IsLds(result.type_url)) {
2245     result.parse_error = LdsResponseParse(
2246         client_, tracer_, symtab_.ptr(), response, expected_listener_names,
2247         &result.lds_update_map, &result.resource_names_failed, arena.ptr());
2248     if (result.parse_error != GRPC_ERROR_NONE) {
2249       MoveUpdatesToFailedSet(&result.lds_update_map,
2250                              &result.resource_names_failed);
2251     }
2252   } else if (IsRds(result.type_url)) {
2253     result.parse_error = RdsResponseParse(
2254         client_, tracer_, symtab_.ptr(), response,
2255         expected_route_configuration_names, &result.rds_update_map,
2256         &result.resource_names_failed, arena.ptr());
2257     if (result.parse_error != GRPC_ERROR_NONE) {
2258       MoveUpdatesToFailedSet(&result.rds_update_map,
2259                              &result.resource_names_failed);
2260     }
2261   } else if (IsCds(result.type_url)) {
2262     result.parse_error = CdsResponseParse(
2263         client_, tracer_, symtab_.ptr(), response, expected_cluster_names,
2264         &result.cds_update_map, &result.resource_names_failed, arena.ptr());
2265     if (result.parse_error != GRPC_ERROR_NONE) {
2266       MoveUpdatesToFailedSet(&result.cds_update_map,
2267                              &result.resource_names_failed);
2268     }
2269   } else if (IsEds(result.type_url)) {
2270     result.parse_error = EdsResponseParse(
2271         client_, tracer_, symtab_.ptr(), response, expected_eds_service_names,
2272         &result.eds_update_map, &result.resource_names_failed, arena.ptr());
2273     if (result.parse_error != GRPC_ERROR_NONE) {
2274       MoveUpdatesToFailedSet(&result.eds_update_map,
2275                              &result.resource_names_failed);
2276     }
2277   }
2278   return result;
2279 }
2280
2281 namespace {
2282
2283 void MaybeLogLrsRequest(
2284     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
2285     const envoy_service_load_stats_v3_LoadStatsRequest* request) {
2286   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
2287       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
2288     const upb_msgdef* msg_type =
2289         envoy_service_load_stats_v3_LoadStatsRequest_getmsgdef(symtab);
2290     char buf[10240];
2291     upb_text_encode(request, msg_type, nullptr, 0, buf, sizeof(buf));
2292     gpr_log(GPR_DEBUG, "[xds_client %p] constructed LRS request: %s", client,
2293             buf);
2294   }
2295 }
2296
2297 grpc_slice SerializeLrsRequest(
2298     const envoy_service_load_stats_v3_LoadStatsRequest* request,
2299     upb_arena* arena) {
2300   size_t output_length;
2301   char* output = envoy_service_load_stats_v3_LoadStatsRequest_serialize(
2302       request, arena, &output_length);
2303   return grpc_slice_from_copied_buffer(output, output_length);
2304 }
2305
2306 }  // namespace
2307
2308 grpc_slice XdsApi::CreateLrsInitialRequest(
2309     const XdsBootstrap::XdsServer& server) {
2310   upb::Arena arena;
2311   // Create a request.
2312   envoy_service_load_stats_v3_LoadStatsRequest* request =
2313       envoy_service_load_stats_v3_LoadStatsRequest_new(arena.ptr());
2314   // Populate node.
2315   envoy_config_core_v3_Node* node_msg =
2316       envoy_service_load_stats_v3_LoadStatsRequest_mutable_node(request,
2317                                                                 arena.ptr());
2318   PopulateNode(arena.ptr(), node_, server.ShouldUseV3(), build_version_,
2319                user_agent_name_, node_msg);
2320   envoy_config_core_v3_Node_add_client_features(
2321       node_msg, upb_strview_makez("envoy.lrs.supports_send_all_clusters"),
2322       arena.ptr());
2323   MaybeLogLrsRequest(client_, tracer_, symtab_.ptr(), request);
2324   return SerializeLrsRequest(request, arena.ptr());
2325 }
2326
2327 namespace {
2328
2329 void LocalityStatsPopulate(
2330     envoy_config_endpoint_v3_UpstreamLocalityStats* output,
2331     const XdsLocalityName& locality_name,
2332     const XdsClusterLocalityStats::Snapshot& snapshot, upb_arena* arena) {
2333   // Set locality.
2334   envoy_config_core_v3_Locality* locality =
2335       envoy_config_endpoint_v3_UpstreamLocalityStats_mutable_locality(output,
2336                                                                       arena);
2337   if (!locality_name.region().empty()) {
2338     envoy_config_core_v3_Locality_set_region(
2339         locality, StdStringToUpbString(locality_name.region()));
2340   }
2341   if (!locality_name.zone().empty()) {
2342     envoy_config_core_v3_Locality_set_zone(
2343         locality, StdStringToUpbString(locality_name.zone()));
2344   }
2345   if (!locality_name.sub_zone().empty()) {
2346     envoy_config_core_v3_Locality_set_sub_zone(
2347         locality, StdStringToUpbString(locality_name.sub_zone()));
2348   }
2349   // Set total counts.
2350   envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_successful_requests(
2351       output, snapshot.total_successful_requests);
2352   envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_requests_in_progress(
2353       output, snapshot.total_requests_in_progress);
2354   envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_error_requests(
2355       output, snapshot.total_error_requests);
2356   envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_issued_requests(
2357       output, snapshot.total_issued_requests);
2358   // Add backend metrics.
2359   for (const auto& p : snapshot.backend_metrics) {
2360     const std::string& metric_name = p.first;
2361     const XdsClusterLocalityStats::BackendMetric& metric_value = p.second;
2362     envoy_config_endpoint_v3_EndpointLoadMetricStats* load_metric =
2363         envoy_config_endpoint_v3_UpstreamLocalityStats_add_load_metric_stats(
2364             output, arena);
2365     envoy_config_endpoint_v3_EndpointLoadMetricStats_set_metric_name(
2366         load_metric, StdStringToUpbString(metric_name));
2367     envoy_config_endpoint_v3_EndpointLoadMetricStats_set_num_requests_finished_with_metric(
2368         load_metric, metric_value.num_requests_finished_with_metric);
2369     envoy_config_endpoint_v3_EndpointLoadMetricStats_set_total_metric_value(
2370         load_metric, metric_value.total_metric_value);
2371   }
2372 }
2373
2374 }  // namespace
2375
2376 grpc_slice XdsApi::CreateLrsRequest(
2377     ClusterLoadReportMap cluster_load_report_map) {
2378   upb::Arena arena;
2379   // Create a request.
2380   envoy_service_load_stats_v3_LoadStatsRequest* request =
2381       envoy_service_load_stats_v3_LoadStatsRequest_new(arena.ptr());
2382   for (auto& p : cluster_load_report_map) {
2383     const std::string& cluster_name = p.first.first;
2384     const std::string& eds_service_name = p.first.second;
2385     const ClusterLoadReport& load_report = p.second;
2386     // Add cluster stats.
2387     envoy_config_endpoint_v3_ClusterStats* cluster_stats =
2388         envoy_service_load_stats_v3_LoadStatsRequest_add_cluster_stats(
2389             request, arena.ptr());
2390     // Set the cluster name.
2391     envoy_config_endpoint_v3_ClusterStats_set_cluster_name(
2392         cluster_stats, StdStringToUpbString(cluster_name));
2393     // Set EDS service name, if non-empty.
2394     if (!eds_service_name.empty()) {
2395       envoy_config_endpoint_v3_ClusterStats_set_cluster_service_name(
2396           cluster_stats, StdStringToUpbString(eds_service_name));
2397     }
2398     // Add locality stats.
2399     for (const auto& p : load_report.locality_stats) {
2400       const XdsLocalityName& locality_name = *p.first;
2401       const auto& snapshot = p.second;
2402       envoy_config_endpoint_v3_UpstreamLocalityStats* locality_stats =
2403           envoy_config_endpoint_v3_ClusterStats_add_upstream_locality_stats(
2404               cluster_stats, arena.ptr());
2405       LocalityStatsPopulate(locality_stats, locality_name, snapshot,
2406                             arena.ptr());
2407     }
2408     // Add dropped requests.
2409     uint64_t total_dropped_requests = 0;
2410     for (const auto& p : load_report.dropped_requests.categorized_drops) {
2411       const std::string& category = p.first;
2412       const uint64_t count = p.second;
2413       envoy_config_endpoint_v3_ClusterStats_DroppedRequests* dropped_requests =
2414           envoy_config_endpoint_v3_ClusterStats_add_dropped_requests(
2415               cluster_stats, arena.ptr());
2416       envoy_config_endpoint_v3_ClusterStats_DroppedRequests_set_category(
2417           dropped_requests, StdStringToUpbString(category));
2418       envoy_config_endpoint_v3_ClusterStats_DroppedRequests_set_dropped_count(
2419           dropped_requests, count);
2420       total_dropped_requests += count;
2421     }
2422     total_dropped_requests += load_report.dropped_requests.uncategorized_drops;
2423     // Set total dropped requests.
2424     envoy_config_endpoint_v3_ClusterStats_set_total_dropped_requests(
2425         cluster_stats, total_dropped_requests);
2426     // Set real load report interval.
2427     gpr_timespec timespec =
2428         grpc_millis_to_timespec(load_report.load_report_interval, GPR_TIMESPAN);
2429     google_protobuf_Duration* load_report_interval =
2430         envoy_config_endpoint_v3_ClusterStats_mutable_load_report_interval(
2431             cluster_stats, arena.ptr());
2432     google_protobuf_Duration_set_seconds(load_report_interval, timespec.tv_sec);
2433     google_protobuf_Duration_set_nanos(load_report_interval, timespec.tv_nsec);
2434   }
2435   MaybeLogLrsRequest(client_, tracer_, symtab_.ptr(), request);
2436   return SerializeLrsRequest(request, arena.ptr());
2437 }
2438
2439 grpc_error* XdsApi::ParseLrsResponse(const grpc_slice& encoded_response,
2440                                      bool* send_all_clusters,
2441                                      std::set<std::string>* cluster_names,
2442                                      grpc_millis* load_reporting_interval) {
2443   upb::Arena arena;
2444   // Decode the response.
2445   const envoy_service_load_stats_v3_LoadStatsResponse* decoded_response =
2446       envoy_service_load_stats_v3_LoadStatsResponse_parse(
2447           reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(encoded_response)),
2448           GRPC_SLICE_LENGTH(encoded_response), arena.ptr());
2449   // Parse the response.
2450   if (decoded_response == nullptr) {
2451     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode response.");
2452   }
2453   // Check send_all_clusters.
2454   if (envoy_service_load_stats_v3_LoadStatsResponse_send_all_clusters(
2455           decoded_response)) {
2456     *send_all_clusters = true;
2457   } else {
2458     // Store the cluster names.
2459     size_t size;
2460     const upb_strview* clusters =
2461         envoy_service_load_stats_v3_LoadStatsResponse_clusters(decoded_response,
2462                                                                &size);
2463     for (size_t i = 0; i < size; ++i) {
2464       cluster_names->emplace(UpbStringToStdString(clusters[i]));
2465     }
2466   }
2467   // Get the load report interval.
2468   const google_protobuf_Duration* load_reporting_interval_duration =
2469       envoy_service_load_stats_v3_LoadStatsResponse_load_reporting_interval(
2470           decoded_response);
2471   gpr_timespec timespec{
2472       google_protobuf_Duration_seconds(load_reporting_interval_duration),
2473       google_protobuf_Duration_nanos(load_reporting_interval_duration),
2474       GPR_TIMESPAN};
2475   *load_reporting_interval = gpr_time_to_millis(timespec);
2476   return GRPC_ERROR_NONE;
2477 }
2478
2479 }  // namespace grpc_core