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