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.
XdsTimeoutEnabled()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.
XdsSecurityEnabled()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 
PathMatcher(const PathMatcher & other)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::
operator =(const PathMatcher & other)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 
operator ==(const PathMatcher & other) const144 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 
ToString() const158 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 
HeaderMatcher(const HeaderMatcher & other)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::
operator =(const HeaderMatcher & other)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 
operator ==(const HeaderMatcher & other) const225 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 
ToString() const242 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 
ToString() const274 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 
ToString() const287 std::string XdsApi::Route::ClusterWeight::ToString() const {
288   return absl::StrFormat("{cluster=%s, weight=%d}", name, weight);
289 }
290 
ToString() const291 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 
ToString() const310 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.
DomainMatch(MatchType match_type,const std::string & domain_pattern_in,const std::string & expected_host_name_in)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 
DomainPatternMatchType(const std::string & domain_pattern)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 
FindVirtualHostForDomain(const std::string & domain)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 
StringMatcher(StringMatcherType type,const std::string & matcher,bool ignore_case)432 XdsApi::StringMatcher::StringMatcher(StringMatcherType type,
433                                      const std::string& matcher,
434                                      bool ignore_case)
435     : type_(type), ignore_case_(ignore_case) {
436   if (type_ == StringMatcherType::SAFE_REGEX) {
437     regex_matcher_ = absl::make_unique<RE2>(matcher);
438   } else {
439     string_matcher_ = matcher;
440   }
441 }
442 
StringMatcher(const StringMatcher & other)443 XdsApi::StringMatcher::StringMatcher(const StringMatcher& other)
444     : type_(other.type_), ignore_case_(other.ignore_case_) {
445   switch (type_) {
446     case StringMatcherType::SAFE_REGEX:
447       regex_matcher_ = absl::make_unique<RE2>(other.regex_matcher_->pattern());
448       break;
449     default:
450       string_matcher_ = other.string_matcher_;
451   }
452 }
453 
operator =(const StringMatcher & other)454 XdsApi::StringMatcher& XdsApi::StringMatcher::operator=(
455     const StringMatcher& other) {
456   type_ = other.type_;
457   switch (type_) {
458     case StringMatcherType::SAFE_REGEX:
459       regex_matcher_ = absl::make_unique<RE2>(other.regex_matcher_->pattern());
460       break;
461     default:
462       string_matcher_ = other.string_matcher_;
463   }
464   ignore_case_ = other.ignore_case_;
465   return *this;
466 }
467 
operator ==(const StringMatcher & other) const468 bool XdsApi::StringMatcher::operator==(const StringMatcher& other) const {
469   if (type_ != other.type_ || ignore_case_ != other.ignore_case_) return false;
470   switch (type_) {
471     case StringMatcherType::SAFE_REGEX:
472       return regex_matcher_->pattern() == other.regex_matcher_->pattern();
473     default:
474       return string_matcher_ == other.string_matcher_;
475   }
476 }
477 
Match(absl::string_view value) const478 bool XdsApi::StringMatcher::Match(absl::string_view value) const {
479   switch (type_) {
480     case XdsApi::StringMatcher::StringMatcherType::EXACT:
481       return ignore_case_ ? absl::EqualsIgnoreCase(value, string_matcher_)
482                           : value == string_matcher_;
483     case XdsApi::StringMatcher::StringMatcherType::PREFIX:
484       return ignore_case_ ? absl::StartsWithIgnoreCase(value, string_matcher_)
485                           : absl::StartsWith(value, string_matcher_);
486     case XdsApi::StringMatcher::StringMatcherType::SUFFIX:
487       return ignore_case_ ? absl::EndsWithIgnoreCase(value, string_matcher_)
488                           : absl::EndsWith(value, string_matcher_);
489     case XdsApi::StringMatcher::StringMatcherType::CONTAINS:
490       return ignore_case_
491                  ? absl::StrContains(absl::AsciiStrToLower(value),
492                                      absl::AsciiStrToLower(string_matcher_))
493                  : absl::StrContains(value, string_matcher_);
494     case XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX:
495       // ignore_case_ is ignored for SAFE_REGEX
496       return RE2::FullMatch(std::string(value), *regex_matcher_);
497     default:
498       return false;
499   }
500 }
501 
ToString() const502 std::string XdsApi::StringMatcher::ToString() const {
503   switch (type_) {
504     case StringMatcherType::EXACT:
505       return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_,
506                              ignore_case_ ? ", ignore_case" : "");
507     case StringMatcherType::PREFIX:
508       return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_,
509                              ignore_case_ ? ", ignore_case" : "");
510     case StringMatcherType::SUFFIX:
511       return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_,
512                              ignore_case_ ? ", ignore_case" : "");
513     case StringMatcherType::CONTAINS:
514       return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_,
515                              ignore_case_ ? ", ignore_case" : "");
516     case StringMatcherType::SAFE_REGEX:
517       return absl::StrFormat("StringMatcher{safe_regex=%s}",
518                              regex_matcher_->pattern());
519     default:
520       return "";
521   }
522 }
523 
524 //
525 // XdsApi::CommonTlsContext::CertificateValidationContext
526 //
527 
ToString() const528 std::string XdsApi::CommonTlsContext::CertificateValidationContext::ToString()
529     const {
530   std::vector<std::string> contents;
531   for (const auto& match : match_subject_alt_names) {
532     contents.push_back(match.ToString());
533   }
534   return absl::StrFormat("{match_subject_alt_names=[%s]}",
535                          absl::StrJoin(contents, ", "));
536 }
537 
Empty() const538 bool XdsApi::CommonTlsContext::CertificateValidationContext::Empty() const {
539   return match_subject_alt_names.empty();
540 }
541 
542 //
543 // XdsApi::CommonTlsContext::CertificateValidationContext
544 //
545 
ToString() const546 std::string XdsApi::CommonTlsContext::CertificateProviderInstance::ToString()
547     const {
548   absl::InlinedVector<std::string, 2> contents;
549   if (!instance_name.empty()) {
550     contents.push_back(absl::StrFormat("instance_name=%s", instance_name));
551   }
552   if (!certificate_name.empty()) {
553     contents.push_back(
554         absl::StrFormat("certificate_name=%s", certificate_name));
555   }
556   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
557 }
558 
Empty() const559 bool XdsApi::CommonTlsContext::CertificateProviderInstance::Empty() const {
560   return instance_name.empty() && certificate_name.empty();
561 }
562 
563 //
564 // XdsApi::CommonTlsContext::CombinedCertificateValidationContext
565 //
566 
567 std::string
ToString() const568 XdsApi::CommonTlsContext::CombinedCertificateValidationContext::ToString()
569     const {
570   absl::InlinedVector<std::string, 2> contents;
571   if (!default_validation_context.Empty()) {
572     contents.push_back(absl::StrFormat("default_validation_context=%s",
573                                        default_validation_context.ToString()));
574   }
575   if (!validation_context_certificate_provider_instance.Empty()) {
576     contents.push_back(absl::StrFormat(
577         "validation_context_certificate_provider_instance=%s",
578         validation_context_certificate_provider_instance.ToString()));
579   }
580   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
581 }
582 
Empty() const583 bool XdsApi::CommonTlsContext::CombinedCertificateValidationContext::Empty()
584     const {
585   return default_validation_context.Empty() &&
586          validation_context_certificate_provider_instance.Empty();
587 }
588 
589 //
590 // XdsApi::CommonTlsContext
591 //
592 
ToString() const593 std::string XdsApi::CommonTlsContext::ToString() const {
594   absl::InlinedVector<std::string, 2> contents;
595   if (!tls_certificate_certificate_provider_instance.Empty()) {
596     contents.push_back(absl::StrFormat(
597         "tls_certificate_certificate_provider_instance=%s",
598         tls_certificate_certificate_provider_instance.ToString()));
599   }
600   if (!combined_validation_context.Empty()) {
601     contents.push_back(absl::StrFormat("combined_validation_context=%s",
602                                        combined_validation_context.ToString()));
603   }
604   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
605 }
606 
Empty() const607 bool XdsApi::CommonTlsContext::Empty() const {
608   return tls_certificate_certificate_provider_instance.Empty() &&
609          combined_validation_context.Empty();
610 }
611 
612 //
613 // XdsApi::CdsUpdate
614 //
615 
ToString() const616 std::string XdsApi::CdsUpdate::ToString() const {
617   absl::InlinedVector<std::string, 4> contents;
618   if (!eds_service_name.empty()) {
619     contents.push_back(
620         absl::StrFormat("eds_service_name=%s", eds_service_name));
621   }
622   if (!common_tls_context.Empty()) {
623     contents.push_back(absl::StrFormat("common_tls_context=%s",
624                                        common_tls_context.ToString()));
625   }
626   if (lrs_load_reporting_server_name.has_value()) {
627     contents.push_back(absl::StrFormat("lrs_load_reporting_server_name=%s",
628                                        lrs_load_reporting_server_name.value()));
629   }
630   contents.push_back(
631       absl::StrFormat("max_concurrent_requests=%d", max_concurrent_requests));
632   return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
633 }
634 
635 //
636 // XdsApi::EdsUpdate
637 //
638 
ToString() const639 std::string XdsApi::EdsUpdate::Priority::Locality::ToString() const {
640   std::vector<std::string> endpoint_strings;
641   for (const ServerAddress& endpoint : endpoints) {
642     endpoint_strings.emplace_back(endpoint.ToString());
643   }
644   return absl::StrCat("{name=", name->AsHumanReadableString(),
645                       ", lb_weight=", lb_weight, ", endpoints=[",
646                       absl::StrJoin(endpoint_strings, ", "), "]}");
647 }
648 
operator ==(const Priority & other) const649 bool XdsApi::EdsUpdate::Priority::operator==(const Priority& other) const {
650   if (localities.size() != other.localities.size()) return false;
651   auto it1 = localities.begin();
652   auto it2 = other.localities.begin();
653   while (it1 != localities.end()) {
654     if (*it1->first != *it2->first) return false;
655     if (it1->second != it2->second) return false;
656     ++it1;
657     ++it2;
658   }
659   return true;
660 }
661 
ToString() const662 std::string XdsApi::EdsUpdate::Priority::ToString() const {
663   std::vector<std::string> locality_strings;
664   for (const auto& p : localities) {
665     locality_strings.emplace_back(p.second.ToString());
666   }
667   return absl::StrCat("[", absl::StrJoin(locality_strings, ", "), "]");
668 }
669 
ShouldDrop(const std::string ** category_name) const670 bool XdsApi::EdsUpdate::DropConfig::ShouldDrop(
671     const std::string** category_name) const {
672   for (size_t i = 0; i < drop_category_list_.size(); ++i) {
673     const auto& drop_category = drop_category_list_[i];
674     // Generate a random number in [0, 1000000).
675     const uint32_t random = static_cast<uint32_t>(rand()) % 1000000;
676     if (random < drop_category.parts_per_million) {
677       *category_name = &drop_category.name;
678       return true;
679     }
680   }
681   return false;
682 }
683 
ToString() const684 std::string XdsApi::EdsUpdate::DropConfig::ToString() const {
685   std::vector<std::string> category_strings;
686   for (const DropCategory& category : drop_category_list_) {
687     category_strings.emplace_back(
688         absl::StrCat(category.name, "=", category.parts_per_million));
689   }
690   return absl::StrCat("{[", absl::StrJoin(category_strings, ", "),
691                       "], drop_all=", drop_all_, "}");
692 }
693 
ToString() const694 std::string XdsApi::EdsUpdate::ToString() const {
695   std::vector<std::string> priority_strings;
696   for (size_t i = 0; i < priorities.size(); ++i) {
697     const Priority& priority = priorities[i];
698     priority_strings.emplace_back(
699         absl::StrCat("priority ", i, ": ", priority.ToString()));
700   }
701   return absl::StrCat("priorities=[", absl::StrJoin(priority_strings, ", "),
702                       "], drop_config=", drop_config->ToString());
703 }
704 
705 //
706 // XdsApi
707 //
708 
709 const char* XdsApi::kLdsTypeUrl =
710     "type.googleapis.com/envoy.config.listener.v3.Listener";
711 const char* XdsApi::kRdsTypeUrl =
712     "type.googleapis.com/envoy.config.route.v3.RouteConfiguration";
713 const char* XdsApi::kCdsTypeUrl =
714     "type.googleapis.com/envoy.config.cluster.v3.Cluster";
715 const char* XdsApi::kEdsTypeUrl =
716     "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment";
717 
718 namespace {
719 
720 const char* kLdsV2TypeUrl = "type.googleapis.com/envoy.api.v2.Listener";
721 const char* kRdsV2TypeUrl =
722     "type.googleapis.com/envoy.api.v2.RouteConfiguration";
723 const char* kCdsV2TypeUrl = "type.googleapis.com/envoy.api.v2.Cluster";
724 const char* kEdsV2TypeUrl =
725     "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment";
726 
IsLds(absl::string_view type_url)727 bool IsLds(absl::string_view type_url) {
728   return type_url == XdsApi::kLdsTypeUrl || type_url == kLdsV2TypeUrl;
729 }
730 
IsRds(absl::string_view type_url)731 bool IsRds(absl::string_view type_url) {
732   return type_url == XdsApi::kRdsTypeUrl || type_url == kRdsV2TypeUrl;
733 }
734 
IsCds(absl::string_view type_url)735 bool IsCds(absl::string_view type_url) {
736   return type_url == XdsApi::kCdsTypeUrl || type_url == kCdsV2TypeUrl;
737 }
738 
IsEds(absl::string_view type_url)739 bool IsEds(absl::string_view type_url) {
740   return type_url == XdsApi::kEdsTypeUrl || type_url == kEdsV2TypeUrl;
741 }
742 
743 }  // namespace
744 
XdsApi(XdsClient * client,TraceFlag * tracer,const XdsBootstrap::Node * node)745 XdsApi::XdsApi(XdsClient* client, TraceFlag* tracer,
746                const XdsBootstrap::Node* node)
747     : client_(client),
748       tracer_(tracer),
749       node_(node),
750       build_version_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING, " ",
751                                   grpc_version_string())),
752       user_agent_name_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING)) {}
753 
754 namespace {
755 
756 // Works for both std::string and absl::string_view.
757 template <typename T>
StdStringToUpbString(const T & str)758 inline upb_strview StdStringToUpbString(const T& str) {
759   return upb_strview_make(str.data(), str.size());
760 }
761 
762 void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
763                            const Json& value);
764 
PopulateListValue(upb_arena * arena,google_protobuf_ListValue * list_value,const Json::Array & values)765 void PopulateListValue(upb_arena* arena, google_protobuf_ListValue* list_value,
766                        const Json::Array& values) {
767   for (const auto& value : values) {
768     auto* value_pb = google_protobuf_ListValue_add_values(list_value, arena);
769     PopulateMetadataValue(arena, value_pb, value);
770   }
771 }
772 
PopulateMetadata(upb_arena * arena,google_protobuf_Struct * metadata_pb,const Json::Object & metadata)773 void PopulateMetadata(upb_arena* arena, google_protobuf_Struct* metadata_pb,
774                       const Json::Object& metadata) {
775   for (const auto& p : metadata) {
776     google_protobuf_Value* value = google_protobuf_Value_new(arena);
777     PopulateMetadataValue(arena, value, p.second);
778     google_protobuf_Struct_fields_set(
779         metadata_pb, StdStringToUpbString(p.first), value, arena);
780   }
781 }
782 
PopulateMetadataValue(upb_arena * arena,google_protobuf_Value * value_pb,const Json & value)783 void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
784                            const Json& value) {
785   switch (value.type()) {
786     case Json::Type::JSON_NULL:
787       google_protobuf_Value_set_null_value(value_pb, 0);
788       break;
789     case Json::Type::NUMBER:
790       google_protobuf_Value_set_number_value(
791           value_pb, strtod(value.string_value().c_str(), nullptr));
792       break;
793     case Json::Type::STRING:
794       google_protobuf_Value_set_string_value(
795           value_pb, StdStringToUpbString(value.string_value()));
796       break;
797     case Json::Type::JSON_TRUE:
798       google_protobuf_Value_set_bool_value(value_pb, true);
799       break;
800     case Json::Type::JSON_FALSE:
801       google_protobuf_Value_set_bool_value(value_pb, false);
802       break;
803     case Json::Type::OBJECT: {
804       google_protobuf_Struct* struct_value =
805           google_protobuf_Value_mutable_struct_value(value_pb, arena);
806       PopulateMetadata(arena, struct_value, value.object_value());
807       break;
808     }
809     case Json::Type::ARRAY: {
810       google_protobuf_ListValue* list_value =
811           google_protobuf_Value_mutable_list_value(value_pb, arena);
812       PopulateListValue(arena, list_value, value.array_value());
813       break;
814     }
815   }
816 }
817 
818 // Helper functions to manually do protobuf string encoding, so that we
819 // can populate the node build_version field that was removed in v3.
EncodeVarint(uint64_t val)820 std::string EncodeVarint(uint64_t val) {
821   std::string data;
822   do {
823     uint8_t byte = val & 0x7fU;
824     val >>= 7;
825     if (val) byte |= 0x80U;
826     data += byte;
827   } while (val);
828   return data;
829 }
EncodeTag(uint32_t field_number,uint8_t wire_type)830 std::string EncodeTag(uint32_t field_number, uint8_t wire_type) {
831   return EncodeVarint((field_number << 3) | wire_type);
832 }
EncodeStringField(uint32_t field_number,const std::string & str)833 std::string EncodeStringField(uint32_t field_number, const std::string& str) {
834   static const uint8_t kDelimitedWireType = 2;
835   return EncodeTag(field_number, kDelimitedWireType) +
836          EncodeVarint(str.size()) + str;
837 }
838 
PopulateBuildVersion(upb_arena * arena,envoy_config_core_v3_Node * node_msg,const std::string & build_version)839 void PopulateBuildVersion(upb_arena* arena, envoy_config_core_v3_Node* node_msg,
840                           const std::string& build_version) {
841   std::string encoded_build_version = EncodeStringField(5, build_version);
842   // TODO(roth): This should use upb_msg_addunknown(), but that API is
843   // broken in the current version of upb, so we're using the internal
844   // API for now.  Change this once we upgrade to a version of upb that
845   // fixes this bug.
846   _upb_msg_addunknown(node_msg, encoded_build_version.data(),
847                       encoded_build_version.size(), arena);
848 }
849 
PopulateNode(upb_arena * arena,const XdsBootstrap::Node * node,bool use_v3,const std::string & build_version,const std::string & user_agent_name,envoy_config_core_v3_Node * node_msg)850 void PopulateNode(upb_arena* arena, const XdsBootstrap::Node* node, bool use_v3,
851                   const std::string& build_version,
852                   const std::string& user_agent_name,
853                   envoy_config_core_v3_Node* node_msg) {
854   if (node != nullptr) {
855     if (!node->id.empty()) {
856       envoy_config_core_v3_Node_set_id(node_msg,
857                                        StdStringToUpbString(node->id));
858     }
859     if (!node->cluster.empty()) {
860       envoy_config_core_v3_Node_set_cluster(
861           node_msg, StdStringToUpbString(node->cluster));
862     }
863     if (!node->metadata.object_value().empty()) {
864       google_protobuf_Struct* metadata =
865           envoy_config_core_v3_Node_mutable_metadata(node_msg, arena);
866       PopulateMetadata(arena, metadata, node->metadata.object_value());
867     }
868     if (!node->locality_region.empty() || !node->locality_zone.empty() ||
869         !node->locality_subzone.empty()) {
870       envoy_config_core_v3_Locality* locality =
871           envoy_config_core_v3_Node_mutable_locality(node_msg, arena);
872       if (!node->locality_region.empty()) {
873         envoy_config_core_v3_Locality_set_region(
874             locality, StdStringToUpbString(node->locality_region));
875       }
876       if (!node->locality_zone.empty()) {
877         envoy_config_core_v3_Locality_set_zone(
878             locality, StdStringToUpbString(node->locality_zone));
879       }
880       if (!node->locality_subzone.empty()) {
881         envoy_config_core_v3_Locality_set_sub_zone(
882             locality, StdStringToUpbString(node->locality_subzone));
883       }
884     }
885   }
886   if (!use_v3) {
887     PopulateBuildVersion(arena, node_msg, build_version);
888   }
889   envoy_config_core_v3_Node_set_user_agent_name(
890       node_msg, StdStringToUpbString(user_agent_name));
891   envoy_config_core_v3_Node_set_user_agent_version(
892       node_msg, upb_strview_makez(grpc_version_string()));
893   envoy_config_core_v3_Node_add_client_features(
894       node_msg, upb_strview_makez("envoy.lb.does_not_support_overprovisioning"),
895       arena);
896 }
897 
UpbStringToAbsl(const upb_strview & str)898 inline absl::string_view UpbStringToAbsl(const upb_strview& str) {
899   return absl::string_view(str.data, str.size);
900 }
901 
UpbStringToStdString(const upb_strview & str)902 inline std::string UpbStringToStdString(const upb_strview& str) {
903   return std::string(str.data, str.size);
904 }
905 
MaybeLogDiscoveryRequest(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_service_discovery_v3_DiscoveryRequest * request)906 void MaybeLogDiscoveryRequest(
907     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
908     const envoy_service_discovery_v3_DiscoveryRequest* request) {
909   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
910       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
911     const upb_msgdef* msg_type =
912         envoy_service_discovery_v3_DiscoveryRequest_getmsgdef(symtab);
913     char buf[10240];
914     upb_text_encode(request, msg_type, nullptr, 0, buf, sizeof(buf));
915     gpr_log(GPR_DEBUG, "[xds_client %p] constructed ADS request: %s", client,
916             buf);
917   }
918 }
919 
SerializeDiscoveryRequest(upb_arena * arena,envoy_service_discovery_v3_DiscoveryRequest * request)920 grpc_slice SerializeDiscoveryRequest(
921     upb_arena* arena, envoy_service_discovery_v3_DiscoveryRequest* request) {
922   size_t output_length;
923   char* output = envoy_service_discovery_v3_DiscoveryRequest_serialize(
924       request, arena, &output_length);
925   return grpc_slice_from_copied_buffer(output, output_length);
926 }
927 
TypeUrlExternalToInternal(bool use_v3,const std::string & type_url)928 absl::string_view TypeUrlExternalToInternal(bool use_v3,
929                                             const std::string& type_url) {
930   if (!use_v3) {
931     if (type_url == XdsApi::kLdsTypeUrl) {
932       return kLdsV2TypeUrl;
933     }
934     if (type_url == XdsApi::kRdsTypeUrl) {
935       return kRdsV2TypeUrl;
936     }
937     if (type_url == XdsApi::kCdsTypeUrl) {
938       return kCdsV2TypeUrl;
939     }
940     if (type_url == XdsApi::kEdsTypeUrl) {
941       return kEdsV2TypeUrl;
942     }
943   }
944   return type_url;
945 }
946 
947 }  // namespace
948 
CreateAdsRequest(const XdsBootstrap::XdsServer & server,const std::string & type_url,const std::set<absl::string_view> & resource_names,const std::string & version,const std::string & nonce,grpc_error * error,bool populate_node)949 grpc_slice XdsApi::CreateAdsRequest(
950     const XdsBootstrap::XdsServer& server, const std::string& type_url,
951     const std::set<absl::string_view>& resource_names,
952     const std::string& version, const std::string& nonce, grpc_error* error,
953     bool populate_node) {
954   upb::Arena arena;
955   // Create a request.
956   envoy_service_discovery_v3_DiscoveryRequest* request =
957       envoy_service_discovery_v3_DiscoveryRequest_new(arena.ptr());
958   // Set type_url.
959   absl::string_view real_type_url =
960       TypeUrlExternalToInternal(server.ShouldUseV3(), type_url);
961   envoy_service_discovery_v3_DiscoveryRequest_set_type_url(
962       request, StdStringToUpbString(real_type_url));
963   // Set version_info.
964   if (!version.empty()) {
965     envoy_service_discovery_v3_DiscoveryRequest_set_version_info(
966         request, StdStringToUpbString(version));
967   }
968   // Set nonce.
969   if (!nonce.empty()) {
970     envoy_service_discovery_v3_DiscoveryRequest_set_response_nonce(
971         request, StdStringToUpbString(nonce));
972   }
973   // Set error_detail if it's a NACK.
974   if (error != GRPC_ERROR_NONE) {
975     google_rpc_Status* error_detail =
976         envoy_service_discovery_v3_DiscoveryRequest_mutable_error_detail(
977             request, arena.ptr());
978     // Hard-code INVALID_ARGUMENT as the status code.
979     // TODO(roth): If at some point we decide we care about this value,
980     // we could attach a status code to the individual errors where we
981     // generate them in the parsing code, and then use that here.
982     google_rpc_Status_set_code(error_detail, GRPC_STATUS_INVALID_ARGUMENT);
983     // Error description comes from the error that was passed in.
984     grpc_slice error_description_slice;
985     GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
986                                   &error_description_slice));
987     upb_strview error_description_strview =
988         StdStringToUpbString(StringViewFromSlice(error_description_slice));
989     google_rpc_Status_set_message(error_detail, error_description_strview);
990     GRPC_ERROR_UNREF(error);
991   }
992   // Populate node.
993   if (populate_node) {
994     envoy_config_core_v3_Node* node_msg =
995         envoy_service_discovery_v3_DiscoveryRequest_mutable_node(request,
996                                                                  arena.ptr());
997     PopulateNode(arena.ptr(), node_, server.ShouldUseV3(), build_version_,
998                  user_agent_name_, node_msg);
999   }
1000   // Add resource_names.
1001   for (const auto& resource_name : resource_names) {
1002     envoy_service_discovery_v3_DiscoveryRequest_add_resource_names(
1003         request, StdStringToUpbString(resource_name), arena.ptr());
1004   }
1005   MaybeLogDiscoveryRequest(client_, tracer_, symtab_.ptr(), request);
1006   return SerializeDiscoveryRequest(arena.ptr(), request);
1007 }
1008 
1009 namespace {
1010 
MaybeLogDiscoveryResponse(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_service_discovery_v3_DiscoveryResponse * response)1011 void MaybeLogDiscoveryResponse(
1012     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1013     const envoy_service_discovery_v3_DiscoveryResponse* response) {
1014   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
1015       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
1016     const upb_msgdef* msg_type =
1017         envoy_service_discovery_v3_DiscoveryResponse_getmsgdef(symtab);
1018     char buf[10240];
1019     upb_text_encode(response, msg_type, nullptr, 0, buf, sizeof(buf));
1020     gpr_log(GPR_DEBUG, "[xds_client %p] received response: %s", client, buf);
1021   }
1022 }
1023 
MaybeLogRouteConfiguration(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_config_route_v3_RouteConfiguration * route_config)1024 void MaybeLogRouteConfiguration(
1025     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1026     const envoy_config_route_v3_RouteConfiguration* route_config) {
1027   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
1028       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
1029     const upb_msgdef* msg_type =
1030         envoy_config_route_v3_RouteConfiguration_getmsgdef(symtab);
1031     char buf[10240];
1032     upb_text_encode(route_config, msg_type, nullptr, 0, buf, sizeof(buf));
1033     gpr_log(GPR_DEBUG, "[xds_client %p] RouteConfiguration: %s", client, buf);
1034   }
1035 }
1036 
MaybeLogCluster(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_config_cluster_v3_Cluster * cluster)1037 void MaybeLogCluster(XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1038                      const envoy_config_cluster_v3_Cluster* cluster) {
1039   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
1040       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
1041     const upb_msgdef* msg_type =
1042         envoy_config_cluster_v3_Cluster_getmsgdef(symtab);
1043     char buf[10240];
1044     upb_text_encode(cluster, msg_type, nullptr, 0, buf, sizeof(buf));
1045     gpr_log(GPR_DEBUG, "[xds_client %p] Cluster: %s", client, buf);
1046   }
1047 }
1048 
MaybeLogClusterLoadAssignment(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_config_endpoint_v3_ClusterLoadAssignment * cla)1049 void MaybeLogClusterLoadAssignment(
1050     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1051     const envoy_config_endpoint_v3_ClusterLoadAssignment* cla) {
1052   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
1053       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
1054     const upb_msgdef* msg_type =
1055         envoy_config_endpoint_v3_ClusterLoadAssignment_getmsgdef(symtab);
1056     char buf[10240];
1057     upb_text_encode(cla, msg_type, nullptr, 0, buf, sizeof(buf));
1058     gpr_log(GPR_DEBUG, "[xds_client %p] ClusterLoadAssignment: %s", client,
1059             buf);
1060   }
1061 }
1062 
RoutePathMatchParse(const envoy_config_route_v3_RouteMatch * match,XdsApi::Route * route,bool * ignore_route)1063 grpc_error* RoutePathMatchParse(const envoy_config_route_v3_RouteMatch* match,
1064                                 XdsApi::Route* route, bool* ignore_route) {
1065   auto* case_sensitive = envoy_config_route_v3_RouteMatch_case_sensitive(match);
1066   if (case_sensitive != nullptr) {
1067     route->matchers.path_matcher.case_sensitive =
1068         google_protobuf_BoolValue_value(case_sensitive);
1069   }
1070   if (envoy_config_route_v3_RouteMatch_has_prefix(match)) {
1071     absl::string_view prefix =
1072         UpbStringToAbsl(envoy_config_route_v3_RouteMatch_prefix(match));
1073     // Empty prefix "" is accepted.
1074     if (!prefix.empty()) {
1075       // Prefix "/" is accepted.
1076       if (prefix[0] != '/') {
1077         // Prefix which does not start with a / will never match anything, so
1078         // ignore this route.
1079         *ignore_route = true;
1080         return GRPC_ERROR_NONE;
1081       }
1082       std::vector<absl::string_view> prefix_elements =
1083           absl::StrSplit(prefix.substr(1), absl::MaxSplits('/', 2));
1084       if (prefix_elements.size() > 2) {
1085         // Prefix cannot have more than 2 slashes.
1086         *ignore_route = true;
1087         return GRPC_ERROR_NONE;
1088       } else if (prefix_elements.size() == 2 && prefix_elements[0].empty()) {
1089         // Prefix contains empty string between the 2 slashes
1090         *ignore_route = true;
1091         return GRPC_ERROR_NONE;
1092       }
1093     }
1094     route->matchers.path_matcher.type =
1095         XdsApi::Route::Matchers::PathMatcher::PathMatcherType::PREFIX;
1096     route->matchers.path_matcher.string_matcher = std::string(prefix);
1097   } else if (envoy_config_route_v3_RouteMatch_has_path(match)) {
1098     absl::string_view path =
1099         UpbStringToAbsl(envoy_config_route_v3_RouteMatch_path(match));
1100     if (path.empty()) {
1101       // Path that is empty will never match anything, so ignore this route.
1102       *ignore_route = true;
1103       return GRPC_ERROR_NONE;
1104     }
1105     if (path[0] != '/') {
1106       // Path which does not start with a / will never match anything, so
1107       // ignore this route.
1108       *ignore_route = true;
1109       return GRPC_ERROR_NONE;
1110     }
1111     std::vector<absl::string_view> path_elements =
1112         absl::StrSplit(path.substr(1), absl::MaxSplits('/', 2));
1113     if (path_elements.size() != 2) {
1114       // Path not in the required format of /service/method will never match
1115       // anything, so ignore this route.
1116       *ignore_route = true;
1117       return GRPC_ERROR_NONE;
1118     } else if (path_elements[0].empty()) {
1119       // Path contains empty service name will never match anything, so ignore
1120       // this route.
1121       *ignore_route = true;
1122       return GRPC_ERROR_NONE;
1123     } else if (path_elements[1].empty()) {
1124       // Path contains empty method name will never match anything, so ignore
1125       // this route.
1126       *ignore_route = true;
1127       return GRPC_ERROR_NONE;
1128     }
1129     route->matchers.path_matcher.type =
1130         XdsApi::Route::Matchers::PathMatcher::PathMatcherType::PATH;
1131     route->matchers.path_matcher.string_matcher = std::string(path);
1132   } else if (envoy_config_route_v3_RouteMatch_has_safe_regex(match)) {
1133     const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
1134         envoy_config_route_v3_RouteMatch_safe_regex(match);
1135     GPR_ASSERT(regex_matcher != nullptr);
1136     std::string matcher = UpbStringToStdString(
1137         envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
1138     RE2::Options options;
1139     options.set_case_sensitive(route->matchers.path_matcher.case_sensitive);
1140     auto regex = absl::make_unique<RE2>(std::move(matcher), options);
1141     if (!regex->ok()) {
1142       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1143           "Invalid regex string specified in path matcher.");
1144     }
1145     route->matchers.path_matcher.type =
1146         XdsApi::Route::Matchers::PathMatcher::PathMatcherType::REGEX;
1147     route->matchers.path_matcher.regex_matcher = std::move(regex);
1148   } else {
1149     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1150         "Invalid route path specifier specified.");
1151   }
1152   return GRPC_ERROR_NONE;
1153 }
1154 
RouteHeaderMatchersParse(const envoy_config_route_v3_RouteMatch * match,XdsApi::Route * route)1155 grpc_error* RouteHeaderMatchersParse(
1156     const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route) {
1157   size_t size;
1158   const envoy_config_route_v3_HeaderMatcher* const* headers =
1159       envoy_config_route_v3_RouteMatch_headers(match, &size);
1160   for (size_t i = 0; i < size; ++i) {
1161     const envoy_config_route_v3_HeaderMatcher* header = headers[i];
1162     XdsApi::Route::Matchers::HeaderMatcher header_matcher;
1163     header_matcher.name =
1164         UpbStringToStdString(envoy_config_route_v3_HeaderMatcher_name(header));
1165     if (envoy_config_route_v3_HeaderMatcher_has_exact_match(header)) {
1166       header_matcher.type =
1167           XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::EXACT;
1168       header_matcher.string_matcher = UpbStringToStdString(
1169           envoy_config_route_v3_HeaderMatcher_exact_match(header));
1170     } else if (envoy_config_route_v3_HeaderMatcher_has_safe_regex_match(
1171                    header)) {
1172       const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
1173           envoy_config_route_v3_HeaderMatcher_safe_regex_match(header);
1174       GPR_ASSERT(regex_matcher != nullptr);
1175       const std::string matcher = UpbStringToStdString(
1176           envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
1177       std::unique_ptr<RE2> regex = absl::make_unique<RE2>(matcher);
1178       if (!regex->ok()) {
1179         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1180             "Invalid regex string specified in header matcher.");
1181       }
1182       header_matcher.type =
1183           XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::REGEX;
1184       header_matcher.regex_match = std::move(regex);
1185     } else if (envoy_config_route_v3_HeaderMatcher_has_range_match(header)) {
1186       header_matcher.type =
1187           XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::RANGE;
1188       const envoy_type_v3_Int64Range* range_matcher =
1189           envoy_config_route_v3_HeaderMatcher_range_match(header);
1190       header_matcher.range_start =
1191           envoy_type_v3_Int64Range_start(range_matcher);
1192       header_matcher.range_end = envoy_type_v3_Int64Range_end(range_matcher);
1193       if (header_matcher.range_end < header_matcher.range_start) {
1194         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1195             "Invalid range header matcher specifier specified: end "
1196             "cannot be smaller than start.");
1197       }
1198     } else if (envoy_config_route_v3_HeaderMatcher_has_present_match(header)) {
1199       header_matcher.type =
1200           XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::PRESENT;
1201       header_matcher.present_match =
1202           envoy_config_route_v3_HeaderMatcher_present_match(header);
1203     } else if (envoy_config_route_v3_HeaderMatcher_has_prefix_match(header)) {
1204       header_matcher.type =
1205           XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::PREFIX;
1206       header_matcher.string_matcher = UpbStringToStdString(
1207           envoy_config_route_v3_HeaderMatcher_prefix_match(header));
1208     } else if (envoy_config_route_v3_HeaderMatcher_has_suffix_match(header)) {
1209       header_matcher.type =
1210           XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::SUFFIX;
1211       header_matcher.string_matcher = UpbStringToStdString(
1212           envoy_config_route_v3_HeaderMatcher_suffix_match(header));
1213     } else {
1214       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1215           "Invalid route header matcher specified.");
1216     }
1217     header_matcher.invert_match =
1218         envoy_config_route_v3_HeaderMatcher_invert_match(header);
1219     route->matchers.header_matchers.emplace_back(std::move(header_matcher));
1220   }
1221   return GRPC_ERROR_NONE;
1222 }
1223 
RouteRuntimeFractionParse(const envoy_config_route_v3_RouteMatch * match,XdsApi::Route * route)1224 grpc_error* RouteRuntimeFractionParse(
1225     const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route) {
1226   const envoy_config_core_v3_RuntimeFractionalPercent* runtime_fraction =
1227       envoy_config_route_v3_RouteMatch_runtime_fraction(match);
1228   if (runtime_fraction != nullptr) {
1229     const envoy_type_v3_FractionalPercent* fraction =
1230         envoy_config_core_v3_RuntimeFractionalPercent_default_value(
1231             runtime_fraction);
1232     if (fraction != nullptr) {
1233       uint32_t numerator = envoy_type_v3_FractionalPercent_numerator(fraction);
1234       const auto denominator =
1235           static_cast<envoy_type_v3_FractionalPercent_DenominatorType>(
1236               envoy_type_v3_FractionalPercent_denominator(fraction));
1237       // Normalize to million.
1238       switch (denominator) {
1239         case envoy_type_v3_FractionalPercent_HUNDRED:
1240           numerator *= 10000;
1241           break;
1242         case envoy_type_v3_FractionalPercent_TEN_THOUSAND:
1243           numerator *= 100;
1244           break;
1245         case envoy_type_v3_FractionalPercent_MILLION:
1246           break;
1247         default:
1248           return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1249               "Unknown denominator type");
1250       }
1251       route->matchers.fraction_per_million = numerator;
1252     }
1253   }
1254   return GRPC_ERROR_NONE;
1255 }
1256 
RouteActionParse(const envoy_config_route_v3_Route * route_msg,XdsApi::Route * route,bool * ignore_route)1257 grpc_error* RouteActionParse(const envoy_config_route_v3_Route* route_msg,
1258                              XdsApi::Route* route, bool* ignore_route) {
1259   if (!envoy_config_route_v3_Route_has_route(route_msg)) {
1260     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1261         "No RouteAction found in route.");
1262   }
1263   const envoy_config_route_v3_RouteAction* route_action =
1264       envoy_config_route_v3_Route_route(route_msg);
1265   // Get the cluster or weighted_clusters in the RouteAction.
1266   if (envoy_config_route_v3_RouteAction_has_cluster(route_action)) {
1267     route->cluster_name = UpbStringToStdString(
1268         envoy_config_route_v3_RouteAction_cluster(route_action));
1269     if (route->cluster_name.empty()) {
1270       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1271           "RouteAction cluster contains empty cluster name.");
1272     }
1273   } else if (envoy_config_route_v3_RouteAction_has_weighted_clusters(
1274                  route_action)) {
1275     const envoy_config_route_v3_WeightedCluster* weighted_cluster =
1276         envoy_config_route_v3_RouteAction_weighted_clusters(route_action);
1277     uint32_t total_weight = 100;
1278     const google_protobuf_UInt32Value* weight =
1279         envoy_config_route_v3_WeightedCluster_total_weight(weighted_cluster);
1280     if (weight != nullptr) {
1281       total_weight = google_protobuf_UInt32Value_value(weight);
1282     }
1283     size_t clusters_size;
1284     const envoy_config_route_v3_WeightedCluster_ClusterWeight* const* clusters =
1285         envoy_config_route_v3_WeightedCluster_clusters(weighted_cluster,
1286                                                        &clusters_size);
1287     uint32_t sum_of_weights = 0;
1288     for (size_t j = 0; j < clusters_size; ++j) {
1289       const envoy_config_route_v3_WeightedCluster_ClusterWeight*
1290           cluster_weight = clusters[j];
1291       XdsApi::Route::ClusterWeight cluster;
1292       cluster.name = UpbStringToStdString(
1293           envoy_config_route_v3_WeightedCluster_ClusterWeight_name(
1294               cluster_weight));
1295       if (cluster.name.empty()) {
1296         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1297             "RouteAction weighted_cluster cluster contains empty cluster "
1298             "name.");
1299       }
1300       const google_protobuf_UInt32Value* weight =
1301           envoy_config_route_v3_WeightedCluster_ClusterWeight_weight(
1302               cluster_weight);
1303       if (weight == nullptr) {
1304         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1305             "RouteAction weighted_cluster cluster missing weight");
1306       }
1307       cluster.weight = google_protobuf_UInt32Value_value(weight);
1308       if (cluster.weight == 0) continue;
1309       sum_of_weights += cluster.weight;
1310       route->weighted_clusters.emplace_back(std::move(cluster));
1311     }
1312     if (total_weight != sum_of_weights) {
1313       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1314           "RouteAction weighted_cluster has incorrect total weight");
1315     }
1316     if (route->weighted_clusters.empty()) {
1317       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1318           "RouteAction weighted_cluster has no valid clusters specified.");
1319     }
1320   } else {
1321     // No cluster or weighted_clusters found in RouteAction, ignore this route.
1322     *ignore_route = true;
1323   }
1324   if (XdsTimeoutEnabled() && !*ignore_route) {
1325     const envoy_config_route_v3_RouteAction_MaxStreamDuration*
1326         max_stream_duration =
1327             envoy_config_route_v3_RouteAction_max_stream_duration(route_action);
1328     if (max_stream_duration != nullptr) {
1329       const google_protobuf_Duration* duration =
1330           envoy_config_route_v3_RouteAction_MaxStreamDuration_grpc_timeout_header_max(
1331               max_stream_duration);
1332       if (duration == nullptr) {
1333         duration =
1334             envoy_config_route_v3_RouteAction_MaxStreamDuration_max_stream_duration(
1335                 max_stream_duration);
1336       }
1337       if (duration != nullptr) {
1338         XdsApi::Duration duration_in_route;
1339         duration_in_route.seconds = google_protobuf_Duration_seconds(duration);
1340         duration_in_route.nanos = google_protobuf_Duration_nanos(duration);
1341         route->max_stream_duration = duration_in_route;
1342       }
1343     }
1344   }
1345   return GRPC_ERROR_NONE;
1346 }
1347 
RouteConfigParse(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_config_route_v3_RouteConfiguration * route_config,XdsApi::RdsUpdate * rds_update)1348 grpc_error* RouteConfigParse(
1349     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1350     const envoy_config_route_v3_RouteConfiguration* route_config,
1351     XdsApi::RdsUpdate* rds_update) {
1352   MaybeLogRouteConfiguration(client, tracer, symtab, route_config);
1353   // Get the virtual hosts.
1354   size_t size;
1355   const envoy_config_route_v3_VirtualHost* const* virtual_hosts =
1356       envoy_config_route_v3_RouteConfiguration_virtual_hosts(route_config,
1357                                                              &size);
1358   for (size_t i = 0; i < size; ++i) {
1359     rds_update->virtual_hosts.emplace_back();
1360     XdsApi::RdsUpdate::VirtualHost& vhost = rds_update->virtual_hosts.back();
1361     // Parse domains.
1362     size_t domain_size;
1363     upb_strview const* domains = envoy_config_route_v3_VirtualHost_domains(
1364         virtual_hosts[i], &domain_size);
1365     for (size_t j = 0; j < domain_size; ++j) {
1366       std::string domain_pattern = UpbStringToStdString(domains[j]);
1367       const MatchType match_type = DomainPatternMatchType(domain_pattern);
1368       if (match_type == INVALID_MATCH) {
1369         return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1370             absl::StrCat("Invalid domain pattern \"", domain_pattern, "\".")
1371                 .c_str());
1372       }
1373       vhost.domains.emplace_back(std::move(domain_pattern));
1374     }
1375     if (vhost.domains.empty()) {
1376       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("VirtualHost has no domains");
1377     }
1378     // Parse routes.
1379     size_t num_routes;
1380     const envoy_config_route_v3_Route* const* routes =
1381         envoy_config_route_v3_VirtualHost_routes(virtual_hosts[i], &num_routes);
1382     if (num_routes < 1) {
1383       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1384           "No route found in the virtual host.");
1385     }
1386     // Loop over the whole list of routes
1387     for (size_t j = 0; j < num_routes; ++j) {
1388       const envoy_config_route_v3_RouteMatch* match =
1389           envoy_config_route_v3_Route_match(routes[j]);
1390       size_t query_parameters_size;
1391       static_cast<void>(envoy_config_route_v3_RouteMatch_query_parameters(
1392           match, &query_parameters_size));
1393       if (query_parameters_size > 0) {
1394         continue;
1395       }
1396       XdsApi::Route route;
1397       bool ignore_route = false;
1398       grpc_error* error = RoutePathMatchParse(match, &route, &ignore_route);
1399       if (error != GRPC_ERROR_NONE) return error;
1400       if (ignore_route) continue;
1401       error = RouteHeaderMatchersParse(match, &route);
1402       if (error != GRPC_ERROR_NONE) return error;
1403       error = RouteRuntimeFractionParse(match, &route);
1404       if (error != GRPC_ERROR_NONE) return error;
1405       error = RouteActionParse(routes[j], &route, &ignore_route);
1406       if (error != GRPC_ERROR_NONE) return error;
1407       if (ignore_route) continue;
1408       vhost.routes.emplace_back(std::move(route));
1409     }
1410     if (vhost.routes.empty()) {
1411       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No valid routes specified.");
1412     }
1413   }
1414   return GRPC_ERROR_NONE;
1415 }
1416 
LdsResponseParse(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_service_discovery_v3_DiscoveryResponse * response,const std::set<absl::string_view> & expected_listener_names,XdsApi::LdsUpdateMap * lds_update_map,upb_arena * arena)1417 grpc_error* LdsResponseParse(
1418     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1419     const envoy_service_discovery_v3_DiscoveryResponse* response,
1420     const std::set<absl::string_view>& expected_listener_names,
1421     XdsApi::LdsUpdateMap* lds_update_map, upb_arena* arena) {
1422   // Get the resources from the response.
1423   size_t size;
1424   const google_protobuf_Any* const* resources =
1425       envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
1426   for (size_t i = 0; i < size; ++i) {
1427     // Check the type_url of the resource.
1428     absl::string_view type_url =
1429         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
1430     if (!IsLds(type_url)) {
1431       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not LDS.");
1432     }
1433     // Decode the listener.
1434     const upb_strview encoded_listener =
1435         google_protobuf_Any_value(resources[i]);
1436     const envoy_config_listener_v3_Listener* listener =
1437         envoy_config_listener_v3_Listener_parse(encoded_listener.data,
1438                                                 encoded_listener.size, arena);
1439     if (listener == nullptr) {
1440       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode listener.");
1441     }
1442     // Check listener name. Ignore unexpected listeners.
1443     std::string listener_name =
1444         UpbStringToStdString(envoy_config_listener_v3_Listener_name(listener));
1445     if (expected_listener_names.find(listener_name) ==
1446         expected_listener_names.end()) {
1447       continue;
1448     }
1449     // Fail if listener name is duplicated.
1450     if (lds_update_map->find(listener_name) != lds_update_map->end()) {
1451       return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1452           absl::StrCat("duplicate listener name \"", listener_name, "\"")
1453               .c_str());
1454     }
1455     XdsApi::LdsUpdate& lds_update = (*lds_update_map)[listener_name];
1456     // Get api_listener and decode it to http_connection_manager.
1457     const envoy_config_listener_v3_ApiListener* api_listener =
1458         envoy_config_listener_v3_Listener_api_listener(listener);
1459     if (api_listener == nullptr) {
1460       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1461           "Listener has no ApiListener.");
1462     }
1463     const upb_strview encoded_api_listener = google_protobuf_Any_value(
1464         envoy_config_listener_v3_ApiListener_api_listener(api_listener));
1465     const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager*
1466         http_connection_manager =
1467             envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_parse(
1468                 encoded_api_listener.data, encoded_api_listener.size, arena);
1469     if (http_connection_manager == nullptr) {
1470       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1471           "Could not parse HttpConnectionManager config from ApiListener");
1472     }
1473     if (XdsTimeoutEnabled()) {
1474       // Obtain max_stream_duration from Http Protocol Options.
1475       const envoy_config_core_v3_HttpProtocolOptions* options =
1476           envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_common_http_protocol_options(
1477               http_connection_manager);
1478       if (options != nullptr) {
1479         const google_protobuf_Duration* duration =
1480             envoy_config_core_v3_HttpProtocolOptions_max_stream_duration(
1481                 options);
1482         if (duration != nullptr) {
1483           lds_update.http_max_stream_duration.seconds =
1484               google_protobuf_Duration_seconds(duration);
1485           lds_update.http_max_stream_duration.nanos =
1486               google_protobuf_Duration_nanos(duration);
1487         }
1488       }
1489     }
1490     // Found inlined route_config. Parse it to find the cluster_name.
1491     if (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_route_config(
1492             http_connection_manager)) {
1493       const envoy_config_route_v3_RouteConfiguration* route_config =
1494           envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_config(
1495               http_connection_manager);
1496       XdsApi::RdsUpdate rds_update;
1497       grpc_error* error =
1498           RouteConfigParse(client, tracer, symtab, route_config, &rds_update);
1499       if (error != GRPC_ERROR_NONE) return error;
1500       lds_update.rds_update = std::move(rds_update);
1501       continue;
1502     }
1503     // Validate that RDS must be used to get the route_config dynamically.
1504     if (!envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_rds(
1505             http_connection_manager)) {
1506       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1507           "HttpConnectionManager neither has inlined route_config nor RDS.");
1508     }
1509     const envoy_extensions_filters_network_http_connection_manager_v3_Rds* rds =
1510         envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_rds(
1511             http_connection_manager);
1512     // Check that the ConfigSource specifies ADS.
1513     const envoy_config_core_v3_ConfigSource* config_source =
1514         envoy_extensions_filters_network_http_connection_manager_v3_Rds_config_source(
1515             rds);
1516     if (config_source == nullptr) {
1517       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1518           "HttpConnectionManager missing config_source for RDS.");
1519     }
1520     if (!envoy_config_core_v3_ConfigSource_has_ads(config_source)) {
1521       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1522           "HttpConnectionManager ConfigSource for RDS does not specify ADS.");
1523     }
1524     // Get the route_config_name.
1525     lds_update.route_config_name = UpbStringToStdString(
1526         envoy_extensions_filters_network_http_connection_manager_v3_Rds_route_config_name(
1527             rds));
1528   }
1529   return GRPC_ERROR_NONE;
1530 }
1531 
RdsResponseParse(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_service_discovery_v3_DiscoveryResponse * response,const std::set<absl::string_view> & expected_route_configuration_names,XdsApi::RdsUpdateMap * rds_update_map,upb_arena * arena)1532 grpc_error* RdsResponseParse(
1533     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1534     const envoy_service_discovery_v3_DiscoveryResponse* response,
1535     const std::set<absl::string_view>& expected_route_configuration_names,
1536     XdsApi::RdsUpdateMap* rds_update_map, upb_arena* arena) {
1537   // Get the resources from the response.
1538   size_t size;
1539   const google_protobuf_Any* const* resources =
1540       envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
1541   for (size_t i = 0; i < size; ++i) {
1542     // Check the type_url of the resource.
1543     absl::string_view type_url =
1544         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
1545     if (!IsRds(type_url)) {
1546       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not RDS.");
1547     }
1548     // Decode the route_config.
1549     const upb_strview encoded_route_config =
1550         google_protobuf_Any_value(resources[i]);
1551     const envoy_config_route_v3_RouteConfiguration* route_config =
1552         envoy_config_route_v3_RouteConfiguration_parse(
1553             encoded_route_config.data, encoded_route_config.size, arena);
1554     if (route_config == nullptr) {
1555       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode route_config.");
1556     }
1557     // Check route_config_name. Ignore unexpected route_config.
1558     std::string route_config_name = UpbStringToStdString(
1559         envoy_config_route_v3_RouteConfiguration_name(route_config));
1560     if (expected_route_configuration_names.find(route_config_name) ==
1561         expected_route_configuration_names.end()) {
1562       continue;
1563     }
1564     // Fail if route config name is duplicated.
1565     if (rds_update_map->find(route_config_name) != rds_update_map->end()) {
1566       return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1567           absl::StrCat("duplicate route config name \"", route_config_name,
1568                        "\"")
1569               .c_str());
1570     }
1571     // Parse the route_config.
1572     XdsApi::RdsUpdate& rds_update =
1573         (*rds_update_map)[std::move(route_config_name)];
1574     grpc_error* error =
1575         RouteConfigParse(client, tracer, symtab, route_config, &rds_update);
1576     if (error != GRPC_ERROR_NONE) return error;
1577   }
1578   return GRPC_ERROR_NONE;
1579 }
1580 
1581 XdsApi::CommonTlsContext::CertificateProviderInstance
CertificateProviderInstanceParse(const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance * certificate_provider_instance_proto)1582 CertificateProviderInstanceParse(
1583     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance*
1584         certificate_provider_instance_proto) {
1585   return {
1586       UpbStringToStdString(
1587           envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance_instance_name(
1588               certificate_provider_instance_proto)),
1589       UpbStringToStdString(
1590           envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance_certificate_name(
1591               certificate_provider_instance_proto))};
1592 }
1593 
1594 grpc_error* CommonTlsContextParse(
1595     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
1596         common_tls_context_proto,
1597     XdsApi::CommonTlsContext* common_tls_context) GRPC_MUST_USE_RESULT;
CommonTlsContextParse(const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext * common_tls_context_proto,XdsApi::CommonTlsContext * common_tls_context)1598 grpc_error* CommonTlsContextParse(
1599     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
1600         common_tls_context_proto,
1601     XdsApi::CommonTlsContext* common_tls_context) {
1602   auto* combined_validation_context =
1603       envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_combined_validation_context(
1604           common_tls_context_proto);
1605   if (combined_validation_context != nullptr) {
1606     auto* default_validation_context =
1607         envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CombinedCertificateValidationContext_default_validation_context(
1608             combined_validation_context);
1609     if (default_validation_context != nullptr) {
1610       size_t len = 0;
1611       auto* subject_alt_names_matchers =
1612           envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_match_subject_alt_names(
1613               default_validation_context, &len);
1614       for (size_t i = 0; i < len; ++i) {
1615         XdsApi::StringMatcher::StringMatcherType type;
1616         std::string matcher;
1617         if (envoy_type_matcher_v3_StringMatcher_has_exact(
1618                 subject_alt_names_matchers[i])) {
1619           type = XdsApi::StringMatcher::StringMatcherType::EXACT;
1620           matcher =
1621               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_exact(
1622                   subject_alt_names_matchers[i]));
1623         } else if (envoy_type_matcher_v3_StringMatcher_has_prefix(
1624                        subject_alt_names_matchers[i])) {
1625           type = XdsApi::StringMatcher::StringMatcherType::PREFIX;
1626           matcher =
1627               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_prefix(
1628                   subject_alt_names_matchers[i]));
1629         } else if (envoy_type_matcher_v3_StringMatcher_has_suffix(
1630                        subject_alt_names_matchers[i])) {
1631           type = XdsApi::StringMatcher::StringMatcherType::SUFFIX;
1632           matcher =
1633               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_suffix(
1634                   subject_alt_names_matchers[i]));
1635         } else if (envoy_type_matcher_v3_StringMatcher_has_contains(
1636                        subject_alt_names_matchers[i])) {
1637           type = XdsApi::StringMatcher::StringMatcherType::CONTAINS;
1638           matcher =
1639               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_contains(
1640                   subject_alt_names_matchers[i]));
1641         } else if (envoy_type_matcher_v3_StringMatcher_has_safe_regex(
1642                        subject_alt_names_matchers[i])) {
1643           type = XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX;
1644           auto* regex_matcher = envoy_type_matcher_v3_StringMatcher_safe_regex(
1645               subject_alt_names_matchers[i]);
1646           matcher = UpbStringToStdString(
1647               envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
1648         } else {
1649           return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1650               "Invalid StringMatcher specified");
1651         }
1652         bool ignore_case = envoy_type_matcher_v3_StringMatcher_ignore_case(
1653             subject_alt_names_matchers[i]);
1654         XdsApi::StringMatcher string_matcher(type, matcher, ignore_case);
1655         if (type == XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX) {
1656           if (!string_matcher.regex_matcher()->ok()) {
1657             return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1658                 "Invalid regex string specified in string matcher.");
1659           }
1660           if (ignore_case) {
1661             return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1662                 "StringMatcher: ignore_case has no effect for SAFE_REGEX.");
1663           }
1664         }
1665         common_tls_context->combined_validation_context
1666             .default_validation_context.match_subject_alt_names.push_back(
1667                 std::move(string_matcher));
1668       }
1669     }
1670     auto* validation_context_certificate_provider_instance =
1671         envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CombinedCertificateValidationContext_validation_context_certificate_provider_instance(
1672             combined_validation_context);
1673     if (validation_context_certificate_provider_instance != nullptr) {
1674       common_tls_context->combined_validation_context
1675           .validation_context_certificate_provider_instance =
1676           CertificateProviderInstanceParse(
1677               validation_context_certificate_provider_instance);
1678     }
1679   }
1680   auto* tls_certificate_certificate_provider_instance =
1681       envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_tls_certificate_certificate_provider_instance(
1682           common_tls_context_proto);
1683   if (tls_certificate_certificate_provider_instance != nullptr) {
1684     common_tls_context->tls_certificate_certificate_provider_instance =
1685         CertificateProviderInstanceParse(
1686             tls_certificate_certificate_provider_instance);
1687   }
1688   return GRPC_ERROR_NONE;
1689 }
1690 
CdsResponseParse(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_service_discovery_v3_DiscoveryResponse * response,const std::set<absl::string_view> & expected_cluster_names,XdsApi::CdsUpdateMap * cds_update_map,upb_arena * arena)1691 grpc_error* CdsResponseParse(
1692     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1693     const envoy_service_discovery_v3_DiscoveryResponse* response,
1694     const std::set<absl::string_view>& expected_cluster_names,
1695     XdsApi::CdsUpdateMap* cds_update_map, upb_arena* arena) {
1696   // Get the resources from the response.
1697   size_t size;
1698   const google_protobuf_Any* const* resources =
1699       envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
1700   // Parse all the resources in the CDS response.
1701   for (size_t i = 0; i < size; ++i) {
1702     // Check the type_url of the resource.
1703     absl::string_view type_url =
1704         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
1705     if (!IsCds(type_url)) {
1706       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not CDS.");
1707     }
1708     // Decode the cluster.
1709     const upb_strview encoded_cluster = google_protobuf_Any_value(resources[i]);
1710     const envoy_config_cluster_v3_Cluster* cluster =
1711         envoy_config_cluster_v3_Cluster_parse(encoded_cluster.data,
1712                                               encoded_cluster.size, arena);
1713     if (cluster == nullptr) {
1714       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode cluster.");
1715     }
1716     MaybeLogCluster(client, tracer, symtab, cluster);
1717     // Ignore unexpected cluster names.
1718     std::string cluster_name =
1719         UpbStringToStdString(envoy_config_cluster_v3_Cluster_name(cluster));
1720     if (expected_cluster_names.find(cluster_name) ==
1721         expected_cluster_names.end()) {
1722       continue;
1723     }
1724     // Fail on duplicate resources.
1725     if (cds_update_map->find(cluster_name) != cds_update_map->end()) {
1726       return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1727           absl::StrCat("duplicate resource name \"", cluster_name, "\"")
1728               .c_str());
1729     }
1730     XdsApi::CdsUpdate& cds_update = (*cds_update_map)[std::move(cluster_name)];
1731     // Check the cluster_discovery_type.
1732     if (!envoy_config_cluster_v3_Cluster_has_type(cluster)) {
1733       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("DiscoveryType not found.");
1734     }
1735     if (envoy_config_cluster_v3_Cluster_type(cluster) !=
1736         envoy_config_cluster_v3_Cluster_EDS) {
1737       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("DiscoveryType is not EDS.");
1738     }
1739     // Check the EDS config source.
1740     const envoy_config_cluster_v3_Cluster_EdsClusterConfig* eds_cluster_config =
1741         envoy_config_cluster_v3_Cluster_eds_cluster_config(cluster);
1742     const envoy_config_core_v3_ConfigSource* eds_config =
1743         envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_config(
1744             eds_cluster_config);
1745     if (!envoy_config_core_v3_ConfigSource_has_ads(eds_config)) {
1746       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1747           "EDS ConfigSource is not ADS.");
1748     }
1749     // Record EDS service_name (if any).
1750     upb_strview service_name =
1751         envoy_config_cluster_v3_Cluster_EdsClusterConfig_service_name(
1752             eds_cluster_config);
1753     if (service_name.size != 0) {
1754       cds_update.eds_service_name = UpbStringToStdString(service_name);
1755     }
1756     // Check the LB policy.
1757     if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) !=
1758         envoy_config_cluster_v3_Cluster_ROUND_ROBIN) {
1759       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1760           "LB policy is not ROUND_ROBIN.");
1761     }
1762     if (XdsSecurityEnabled()) {
1763       // Record Upstream tls context
1764       auto* transport_socket =
1765           envoy_config_cluster_v3_Cluster_transport_socket(cluster);
1766       if (transport_socket != nullptr) {
1767         absl::string_view name = UpbStringToAbsl(
1768             envoy_config_core_v3_TransportSocket_name(transport_socket));
1769         if (name == "envoy.transport_sockets.tls") {
1770           auto* typed_config =
1771               envoy_config_core_v3_TransportSocket_typed_config(
1772                   transport_socket);
1773           if (typed_config != nullptr) {
1774             const upb_strview encoded_upstream_tls_context =
1775                 google_protobuf_Any_value(typed_config);
1776             auto* upstream_tls_context =
1777                 envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_parse(
1778                     encoded_upstream_tls_context.data,
1779                     encoded_upstream_tls_context.size, arena);
1780             if (upstream_tls_context == nullptr) {
1781               return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1782                   "Can't decode upstream tls context.");
1783             }
1784             auto* common_tls_context =
1785                 envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_common_tls_context(
1786                     upstream_tls_context);
1787             if (common_tls_context != nullptr) {
1788               grpc_error* error = CommonTlsContextParse(
1789                   common_tls_context, &cds_update.common_tls_context);
1790               if (error != GRPC_ERROR_NONE) return error;
1791             }
1792           }
1793           if (cds_update.common_tls_context.combined_validation_context
1794                   .validation_context_certificate_provider_instance
1795                   .instance_name.empty()) {
1796             return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1797                 "TLS configuration provided but no "
1798                 "validation_context_certificate_provider_instance found.");
1799           }
1800         }
1801       }
1802     }
1803     // Record LRS server name (if any).
1804     const envoy_config_core_v3_ConfigSource* lrs_server =
1805         envoy_config_cluster_v3_Cluster_lrs_server(cluster);
1806     if (lrs_server != nullptr) {
1807       if (!envoy_config_core_v3_ConfigSource_has_self(lrs_server)) {
1808         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1809             "LRS ConfigSource is not self.");
1810       }
1811       cds_update.lrs_load_reporting_server_name.emplace("");
1812     }
1813     // The Cluster resource encodes the circuit breaking parameters in a list of
1814     // Thresholds messages, where each message specifies the parameters for a
1815     // particular RoutingPriority. we will look only at the first entry in the
1816     // list for priority DEFAULT and default to 1024 if not found.
1817     if (envoy_config_cluster_v3_Cluster_has_circuit_breakers(cluster)) {
1818       const envoy_config_cluster_v3_CircuitBreakers* circuit_breakers =
1819           envoy_config_cluster_v3_Cluster_circuit_breakers(cluster);
1820       size_t num_thresholds;
1821       const envoy_config_cluster_v3_CircuitBreakers_Thresholds* const*
1822           thresholds = envoy_config_cluster_v3_CircuitBreakers_thresholds(
1823               circuit_breakers, &num_thresholds);
1824       for (size_t i = 0; i < num_thresholds; ++i) {
1825         const auto* threshold = thresholds[i];
1826         if (envoy_config_cluster_v3_CircuitBreakers_Thresholds_priority(
1827                 threshold) == envoy_config_core_v3_DEFAULT) {
1828           const google_protobuf_UInt32Value* max_requests =
1829               envoy_config_cluster_v3_CircuitBreakers_Thresholds_max_requests(
1830                   threshold);
1831           if (max_requests != nullptr) {
1832             cds_update.max_concurrent_requests =
1833                 google_protobuf_UInt32Value_value(max_requests);
1834           }
1835           break;
1836         }
1837       }
1838     }
1839   }
1840   return GRPC_ERROR_NONE;
1841 }
1842 
ServerAddressParseAndAppend(const envoy_config_endpoint_v3_LbEndpoint * lb_endpoint,ServerAddressList * list)1843 grpc_error* ServerAddressParseAndAppend(
1844     const envoy_config_endpoint_v3_LbEndpoint* lb_endpoint,
1845     ServerAddressList* list) {
1846   // If health_status is not HEALTHY or UNKNOWN, skip this endpoint.
1847   const int32_t health_status =
1848       envoy_config_endpoint_v3_LbEndpoint_health_status(lb_endpoint);
1849   if (health_status != envoy_config_core_v3_UNKNOWN &&
1850       health_status != envoy_config_core_v3_HEALTHY) {
1851     return GRPC_ERROR_NONE;
1852   }
1853   // Find the ip:port.
1854   const envoy_config_endpoint_v3_Endpoint* endpoint =
1855       envoy_config_endpoint_v3_LbEndpoint_endpoint(lb_endpoint);
1856   const envoy_config_core_v3_Address* address =
1857       envoy_config_endpoint_v3_Endpoint_address(endpoint);
1858   const envoy_config_core_v3_SocketAddress* socket_address =
1859       envoy_config_core_v3_Address_socket_address(address);
1860   std::string address_str = UpbStringToStdString(
1861       envoy_config_core_v3_SocketAddress_address(socket_address));
1862   uint32_t port = envoy_config_core_v3_SocketAddress_port_value(socket_address);
1863   if (GPR_UNLIKELY(port >> 16) != 0) {
1864     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid port.");
1865   }
1866   // Populate grpc_resolved_address.
1867   grpc_resolved_address addr;
1868   grpc_string_to_sockaddr(&addr, address_str.c_str(), port);
1869   // Append the address to the list.
1870   list->emplace_back(addr, nullptr);
1871   return GRPC_ERROR_NONE;
1872 }
1873 
LocalityParse(const envoy_config_endpoint_v3_LocalityLbEndpoints * locality_lb_endpoints,XdsApi::EdsUpdate::Priority::Locality * output_locality,size_t * priority)1874 grpc_error* LocalityParse(
1875     const envoy_config_endpoint_v3_LocalityLbEndpoints* locality_lb_endpoints,
1876     XdsApi::EdsUpdate::Priority::Locality* output_locality, size_t* priority) {
1877   // Parse LB weight.
1878   const google_protobuf_UInt32Value* lb_weight =
1879       envoy_config_endpoint_v3_LocalityLbEndpoints_load_balancing_weight(
1880           locality_lb_endpoints);
1881   // If LB weight is not specified, it means this locality is assigned no load.
1882   // TODO(juanlishen): When we support CDS to configure the inter-locality
1883   // policy, we should change the LB weight handling.
1884   output_locality->lb_weight =
1885       lb_weight != nullptr ? google_protobuf_UInt32Value_value(lb_weight) : 0;
1886   if (output_locality->lb_weight == 0) return GRPC_ERROR_NONE;
1887   // Parse locality name.
1888   const envoy_config_core_v3_Locality* locality =
1889       envoy_config_endpoint_v3_LocalityLbEndpoints_locality(
1890           locality_lb_endpoints);
1891   std::string region =
1892       UpbStringToStdString(envoy_config_core_v3_Locality_region(locality));
1893   std::string zone =
1894       UpbStringToStdString(envoy_config_core_v3_Locality_region(locality));
1895   std::string sub_zone =
1896       UpbStringToStdString(envoy_config_core_v3_Locality_sub_zone(locality));
1897   output_locality->name = MakeRefCounted<XdsLocalityName>(
1898       std::move(region), std::move(zone), std::move(sub_zone));
1899   // Parse the addresses.
1900   size_t size;
1901   const envoy_config_endpoint_v3_LbEndpoint* const* lb_endpoints =
1902       envoy_config_endpoint_v3_LocalityLbEndpoints_lb_endpoints(
1903           locality_lb_endpoints, &size);
1904   for (size_t i = 0; i < size; ++i) {
1905     grpc_error* error = ServerAddressParseAndAppend(
1906         lb_endpoints[i], &output_locality->endpoints);
1907     if (error != GRPC_ERROR_NONE) return error;
1908   }
1909   // Parse the priority.
1910   *priority = envoy_config_endpoint_v3_LocalityLbEndpoints_priority(
1911       locality_lb_endpoints);
1912   return GRPC_ERROR_NONE;
1913 }
1914 
DropParseAndAppend(const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload * drop_overload,XdsApi::EdsUpdate::DropConfig * drop_config)1915 grpc_error* DropParseAndAppend(
1916     const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload*
1917         drop_overload,
1918     XdsApi::EdsUpdate::DropConfig* drop_config) {
1919   // Get the category.
1920   std::string category = UpbStringToStdString(
1921       envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload_category(
1922           drop_overload));
1923   if (category.empty()) {
1924     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty drop category name");
1925   }
1926   // Get the drop rate (per million).
1927   const envoy_type_v3_FractionalPercent* drop_percentage =
1928       envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload_drop_percentage(
1929           drop_overload);
1930   uint32_t numerator =
1931       envoy_type_v3_FractionalPercent_numerator(drop_percentage);
1932   const auto denominator =
1933       static_cast<envoy_type_v3_FractionalPercent_DenominatorType>(
1934           envoy_type_v3_FractionalPercent_denominator(drop_percentage));
1935   // Normalize to million.
1936   switch (denominator) {
1937     case envoy_type_v3_FractionalPercent_HUNDRED:
1938       numerator *= 10000;
1939       break;
1940     case envoy_type_v3_FractionalPercent_TEN_THOUSAND:
1941       numerator *= 100;
1942       break;
1943     case envoy_type_v3_FractionalPercent_MILLION:
1944       break;
1945     default:
1946       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unknown denominator type");
1947   }
1948   // Cap numerator to 1000000.
1949   numerator = GPR_MIN(numerator, 1000000);
1950   drop_config->AddCategory(std::move(category), numerator);
1951   return GRPC_ERROR_NONE;
1952 }
1953 
EdsResponseParse(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_service_discovery_v3_DiscoveryResponse * response,const std::set<absl::string_view> & expected_eds_service_names,XdsApi::EdsUpdateMap * eds_update_map,upb_arena * arena)1954 grpc_error* EdsResponseParse(
1955     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
1956     const envoy_service_discovery_v3_DiscoveryResponse* response,
1957     const std::set<absl::string_view>& expected_eds_service_names,
1958     XdsApi::EdsUpdateMap* eds_update_map, upb_arena* arena) {
1959   // Get the resources from the response.
1960   size_t size;
1961   const google_protobuf_Any* const* resources =
1962       envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
1963   for (size_t i = 0; i < size; ++i) {
1964     // Check the type_url of the resource.
1965     absl::string_view type_url =
1966         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
1967     if (!IsEds(type_url)) {
1968       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not EDS.");
1969     }
1970     // Get the cluster_load_assignment.
1971     upb_strview encoded_cluster_load_assignment =
1972         google_protobuf_Any_value(resources[i]);
1973     envoy_config_endpoint_v3_ClusterLoadAssignment* cluster_load_assignment =
1974         envoy_config_endpoint_v3_ClusterLoadAssignment_parse(
1975             encoded_cluster_load_assignment.data,
1976             encoded_cluster_load_assignment.size, arena);
1977     if (cluster_load_assignment == nullptr) {
1978       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1979           "Can't parse cluster_load_assignment.");
1980     }
1981     MaybeLogClusterLoadAssignment(client, tracer, symtab,
1982                                   cluster_load_assignment);
1983     // Check the EDS service name.  Ignore unexpected names.
1984     std::string eds_service_name = UpbStringToStdString(
1985         envoy_config_endpoint_v3_ClusterLoadAssignment_cluster_name(
1986             cluster_load_assignment));
1987     if (expected_eds_service_names.find(eds_service_name) ==
1988         expected_eds_service_names.end()) {
1989       continue;
1990     }
1991     // Fail on duplicate resources.
1992     if (eds_update_map->find(eds_service_name) != eds_update_map->end()) {
1993       return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
1994           absl::StrCat("duplicate resource name \"", eds_service_name, "\"")
1995               .c_str());
1996     }
1997     XdsApi::EdsUpdate& eds_update =
1998         (*eds_update_map)[std::move(eds_service_name)];
1999     // Get the endpoints.
2000     size_t locality_size;
2001     const envoy_config_endpoint_v3_LocalityLbEndpoints* const* endpoints =
2002         envoy_config_endpoint_v3_ClusterLoadAssignment_endpoints(
2003             cluster_load_assignment, &locality_size);
2004     for (size_t j = 0; j < locality_size; ++j) {
2005       size_t priority;
2006       XdsApi::EdsUpdate::Priority::Locality locality;
2007       grpc_error* error = LocalityParse(endpoints[j], &locality, &priority);
2008       if (error != GRPC_ERROR_NONE) return error;
2009       // Filter out locality with weight 0.
2010       if (locality.lb_weight == 0) continue;
2011       // Make sure prorities is big enough. Note that they might not
2012       // arrive in priority order.
2013       while (eds_update.priorities.size() < priority + 1) {
2014         eds_update.priorities.emplace_back();
2015       }
2016       eds_update.priorities[priority].localities.emplace(locality.name.get(),
2017                                                          std::move(locality));
2018     }
2019     for (const auto& priority : eds_update.priorities) {
2020       if (priority.localities.empty()) {
2021         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
2022             "EDS update includes sparse priority list");
2023       }
2024     }
2025     // Get the drop config.
2026     eds_update.drop_config = MakeRefCounted<XdsApi::EdsUpdate::DropConfig>();
2027     const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy* policy =
2028         envoy_config_endpoint_v3_ClusterLoadAssignment_policy(
2029             cluster_load_assignment);
2030     if (policy != nullptr) {
2031       size_t drop_size;
2032       const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload* const*
2033           drop_overload =
2034               envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_drop_overloads(
2035                   policy, &drop_size);
2036       for (size_t j = 0; j < drop_size; ++j) {
2037         grpc_error* error =
2038             DropParseAndAppend(drop_overload[j], eds_update.drop_config.get());
2039         if (error != GRPC_ERROR_NONE) return error;
2040       }
2041     }
2042   }
2043   return GRPC_ERROR_NONE;
2044 }
2045 
TypeUrlInternalToExternal(absl::string_view type_url)2046 std::string TypeUrlInternalToExternal(absl::string_view type_url) {
2047   if (type_url == kLdsV2TypeUrl) {
2048     return XdsApi::kLdsTypeUrl;
2049   } else if (type_url == kRdsV2TypeUrl) {
2050     return XdsApi::kRdsTypeUrl;
2051   } else if (type_url == kCdsV2TypeUrl) {
2052     return XdsApi::kCdsTypeUrl;
2053   } else if (type_url == kEdsV2TypeUrl) {
2054     return XdsApi::kEdsTypeUrl;
2055   }
2056   return std::string(type_url);
2057 }
2058 
2059 }  // namespace
2060 
ParseAdsResponse(const grpc_slice & encoded_response,const std::set<absl::string_view> & expected_listener_names,const std::set<absl::string_view> & expected_route_configuration_names,const std::set<absl::string_view> & expected_cluster_names,const std::set<absl::string_view> & expected_eds_service_names)2061 XdsApi::AdsParseResult XdsApi::ParseAdsResponse(
2062     const grpc_slice& encoded_response,
2063     const std::set<absl::string_view>& expected_listener_names,
2064     const std::set<absl::string_view>& expected_route_configuration_names,
2065     const std::set<absl::string_view>& expected_cluster_names,
2066     const std::set<absl::string_view>& expected_eds_service_names) {
2067   AdsParseResult result;
2068   upb::Arena arena;
2069   // Decode the response.
2070   const envoy_service_discovery_v3_DiscoveryResponse* response =
2071       envoy_service_discovery_v3_DiscoveryResponse_parse(
2072           reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(encoded_response)),
2073           GRPC_SLICE_LENGTH(encoded_response), arena.ptr());
2074   // If decoding fails, output an empty type_url and return.
2075   if (response == nullptr) {
2076     result.parse_error =
2077         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode DiscoveryResponse.");
2078     return result;
2079   }
2080   MaybeLogDiscoveryResponse(client_, tracer_, symtab_.ptr(), response);
2081   // Record the type_url, the version_info, and the nonce of the response.
2082   result.type_url = TypeUrlInternalToExternal(UpbStringToAbsl(
2083       envoy_service_discovery_v3_DiscoveryResponse_type_url(response)));
2084   result.version = UpbStringToStdString(
2085       envoy_service_discovery_v3_DiscoveryResponse_version_info(response));
2086   result.nonce = UpbStringToStdString(
2087       envoy_service_discovery_v3_DiscoveryResponse_nonce(response));
2088   // Parse the response according to the resource type.
2089   if (IsLds(result.type_url)) {
2090     result.parse_error = LdsResponseParse(client_, tracer_, symtab_.ptr(),
2091                                           response, expected_listener_names,
2092                                           &result.lds_update_map, arena.ptr());
2093   } else if (IsRds(result.type_url)) {
2094     result.parse_error =
2095         RdsResponseParse(client_, tracer_, symtab_.ptr(), response,
2096                          expected_route_configuration_names,
2097                          &result.rds_update_map, arena.ptr());
2098   } else if (IsCds(result.type_url)) {
2099     result.parse_error = CdsResponseParse(client_, tracer_, symtab_.ptr(),
2100                                           response, expected_cluster_names,
2101                                           &result.cds_update_map, arena.ptr());
2102   } else if (IsEds(result.type_url)) {
2103     result.parse_error = EdsResponseParse(client_, tracer_, symtab_.ptr(),
2104                                           response, expected_eds_service_names,
2105                                           &result.eds_update_map, arena.ptr());
2106   }
2107   return result;
2108 }
2109 
2110 namespace {
2111 
MaybeLogLrsRequest(XdsClient * client,TraceFlag * tracer,upb_symtab * symtab,const envoy_service_load_stats_v3_LoadStatsRequest * request)2112 void MaybeLogLrsRequest(
2113     XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
2114     const envoy_service_load_stats_v3_LoadStatsRequest* request) {
2115   if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
2116       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
2117     const upb_msgdef* msg_type =
2118         envoy_service_load_stats_v3_LoadStatsRequest_getmsgdef(symtab);
2119     char buf[10240];
2120     upb_text_encode(request, msg_type, nullptr, 0, buf, sizeof(buf));
2121     gpr_log(GPR_DEBUG, "[xds_client %p] constructed LRS request: %s", client,
2122             buf);
2123   }
2124 }
2125 
SerializeLrsRequest(const envoy_service_load_stats_v3_LoadStatsRequest * request,upb_arena * arena)2126 grpc_slice SerializeLrsRequest(
2127     const envoy_service_load_stats_v3_LoadStatsRequest* request,
2128     upb_arena* arena) {
2129   size_t output_length;
2130   char* output = envoy_service_load_stats_v3_LoadStatsRequest_serialize(
2131       request, arena, &output_length);
2132   return grpc_slice_from_copied_buffer(output, output_length);
2133 }
2134 
2135 }  // namespace
2136 
CreateLrsInitialRequest(const XdsBootstrap::XdsServer & server)2137 grpc_slice XdsApi::CreateLrsInitialRequest(
2138     const XdsBootstrap::XdsServer& server) {
2139   upb::Arena arena;
2140   // Create a request.
2141   envoy_service_load_stats_v3_LoadStatsRequest* request =
2142       envoy_service_load_stats_v3_LoadStatsRequest_new(arena.ptr());
2143   // Populate node.
2144   envoy_config_core_v3_Node* node_msg =
2145       envoy_service_load_stats_v3_LoadStatsRequest_mutable_node(request,
2146                                                                 arena.ptr());
2147   PopulateNode(arena.ptr(), node_, server.ShouldUseV3(), build_version_,
2148                user_agent_name_, node_msg);
2149   envoy_config_core_v3_Node_add_client_features(
2150       node_msg, upb_strview_makez("envoy.lrs.supports_send_all_clusters"),
2151       arena.ptr());
2152   MaybeLogLrsRequest(client_, tracer_, symtab_.ptr(), request);
2153   return SerializeLrsRequest(request, arena.ptr());
2154 }
2155 
2156 namespace {
2157 
LocalityStatsPopulate(envoy_config_endpoint_v3_UpstreamLocalityStats * output,const XdsLocalityName & locality_name,const XdsClusterLocalityStats::Snapshot & snapshot,upb_arena * arena)2158 void LocalityStatsPopulate(
2159     envoy_config_endpoint_v3_UpstreamLocalityStats* output,
2160     const XdsLocalityName& locality_name,
2161     const XdsClusterLocalityStats::Snapshot& snapshot, upb_arena* arena) {
2162   // Set locality.
2163   envoy_config_core_v3_Locality* locality =
2164       envoy_config_endpoint_v3_UpstreamLocalityStats_mutable_locality(output,
2165                                                                       arena);
2166   if (!locality_name.region().empty()) {
2167     envoy_config_core_v3_Locality_set_region(
2168         locality, StdStringToUpbString(locality_name.region()));
2169   }
2170   if (!locality_name.zone().empty()) {
2171     envoy_config_core_v3_Locality_set_zone(
2172         locality, StdStringToUpbString(locality_name.zone()));
2173   }
2174   if (!locality_name.sub_zone().empty()) {
2175     envoy_config_core_v3_Locality_set_sub_zone(
2176         locality, StdStringToUpbString(locality_name.sub_zone()));
2177   }
2178   // Set total counts.
2179   envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_successful_requests(
2180       output, snapshot.total_successful_requests);
2181   envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_requests_in_progress(
2182       output, snapshot.total_requests_in_progress);
2183   envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_error_requests(
2184       output, snapshot.total_error_requests);
2185   envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_issued_requests(
2186       output, snapshot.total_issued_requests);
2187   // Add backend metrics.
2188   for (const auto& p : snapshot.backend_metrics) {
2189     const std::string& metric_name = p.first;
2190     const XdsClusterLocalityStats::BackendMetric& metric_value = p.second;
2191     envoy_config_endpoint_v3_EndpointLoadMetricStats* load_metric =
2192         envoy_config_endpoint_v3_UpstreamLocalityStats_add_load_metric_stats(
2193             output, arena);
2194     envoy_config_endpoint_v3_EndpointLoadMetricStats_set_metric_name(
2195         load_metric, StdStringToUpbString(metric_name));
2196     envoy_config_endpoint_v3_EndpointLoadMetricStats_set_num_requests_finished_with_metric(
2197         load_metric, metric_value.num_requests_finished_with_metric);
2198     envoy_config_endpoint_v3_EndpointLoadMetricStats_set_total_metric_value(
2199         load_metric, metric_value.total_metric_value);
2200   }
2201 }
2202 
2203 }  // namespace
2204 
CreateLrsRequest(ClusterLoadReportMap cluster_load_report_map)2205 grpc_slice XdsApi::CreateLrsRequest(
2206     ClusterLoadReportMap cluster_load_report_map) {
2207   upb::Arena arena;
2208   // Create a request.
2209   envoy_service_load_stats_v3_LoadStatsRequest* request =
2210       envoy_service_load_stats_v3_LoadStatsRequest_new(arena.ptr());
2211   for (auto& p : cluster_load_report_map) {
2212     const std::string& cluster_name = p.first.first;
2213     const std::string& eds_service_name = p.first.second;
2214     const ClusterLoadReport& load_report = p.second;
2215     // Add cluster stats.
2216     envoy_config_endpoint_v3_ClusterStats* cluster_stats =
2217         envoy_service_load_stats_v3_LoadStatsRequest_add_cluster_stats(
2218             request, arena.ptr());
2219     // Set the cluster name.
2220     envoy_config_endpoint_v3_ClusterStats_set_cluster_name(
2221         cluster_stats, StdStringToUpbString(cluster_name));
2222     // Set EDS service name, if non-empty.
2223     if (!eds_service_name.empty()) {
2224       envoy_config_endpoint_v3_ClusterStats_set_cluster_service_name(
2225           cluster_stats, StdStringToUpbString(eds_service_name));
2226     }
2227     // Add locality stats.
2228     for (const auto& p : load_report.locality_stats) {
2229       const XdsLocalityName& locality_name = *p.first;
2230       const auto& snapshot = p.second;
2231       envoy_config_endpoint_v3_UpstreamLocalityStats* locality_stats =
2232           envoy_config_endpoint_v3_ClusterStats_add_upstream_locality_stats(
2233               cluster_stats, arena.ptr());
2234       LocalityStatsPopulate(locality_stats, locality_name, snapshot,
2235                             arena.ptr());
2236     }
2237     // Add dropped requests.
2238     uint64_t total_dropped_requests = 0;
2239     for (const auto& p : load_report.dropped_requests.categorized_drops) {
2240       const std::string& category = p.first;
2241       const uint64_t count = p.second;
2242       envoy_config_endpoint_v3_ClusterStats_DroppedRequests* dropped_requests =
2243           envoy_config_endpoint_v3_ClusterStats_add_dropped_requests(
2244               cluster_stats, arena.ptr());
2245       envoy_config_endpoint_v3_ClusterStats_DroppedRequests_set_category(
2246           dropped_requests, StdStringToUpbString(category));
2247       envoy_config_endpoint_v3_ClusterStats_DroppedRequests_set_dropped_count(
2248           dropped_requests, count);
2249       total_dropped_requests += count;
2250     }
2251     total_dropped_requests += load_report.dropped_requests.uncategorized_drops;
2252     // Set total dropped requests.
2253     envoy_config_endpoint_v3_ClusterStats_set_total_dropped_requests(
2254         cluster_stats, total_dropped_requests);
2255     // Set real load report interval.
2256     gpr_timespec timespec =
2257         grpc_millis_to_timespec(load_report.load_report_interval, GPR_TIMESPAN);
2258     google_protobuf_Duration* load_report_interval =
2259         envoy_config_endpoint_v3_ClusterStats_mutable_load_report_interval(
2260             cluster_stats, arena.ptr());
2261     google_protobuf_Duration_set_seconds(load_report_interval, timespec.tv_sec);
2262     google_protobuf_Duration_set_nanos(load_report_interval, timespec.tv_nsec);
2263   }
2264   MaybeLogLrsRequest(client_, tracer_, symtab_.ptr(), request);
2265   return SerializeLrsRequest(request, arena.ptr());
2266 }
2267 
ParseLrsResponse(const grpc_slice & encoded_response,bool * send_all_clusters,std::set<std::string> * cluster_names,grpc_millis * load_reporting_interval)2268 grpc_error* XdsApi::ParseLrsResponse(const grpc_slice& encoded_response,
2269                                      bool* send_all_clusters,
2270                                      std::set<std::string>* cluster_names,
2271                                      grpc_millis* load_reporting_interval) {
2272   upb::Arena arena;
2273   // Decode the response.
2274   const envoy_service_load_stats_v3_LoadStatsResponse* decoded_response =
2275       envoy_service_load_stats_v3_LoadStatsResponse_parse(
2276           reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(encoded_response)),
2277           GRPC_SLICE_LENGTH(encoded_response), arena.ptr());
2278   // Parse the response.
2279   if (decoded_response == nullptr) {
2280     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode response.");
2281   }
2282   // Check send_all_clusters.
2283   if (envoy_service_load_stats_v3_LoadStatsResponse_send_all_clusters(
2284           decoded_response)) {
2285     *send_all_clusters = true;
2286   } else {
2287     // Store the cluster names.
2288     size_t size;
2289     const upb_strview* clusters =
2290         envoy_service_load_stats_v3_LoadStatsResponse_clusters(decoded_response,
2291                                                                &size);
2292     for (size_t i = 0; i < size; ++i) {
2293       cluster_names->emplace(UpbStringToStdString(clusters[i]));
2294     }
2295   }
2296   // Get the load report interval.
2297   const google_protobuf_Duration* load_reporting_interval_duration =
2298       envoy_service_load_stats_v3_LoadStatsResponse_load_reporting_interval(
2299           decoded_response);
2300   gpr_timespec timespec{
2301       google_protobuf_Duration_seconds(load_reporting_interval_duration),
2302       google_protobuf_Duration_nanos(load_reporting_interval_duration),
2303       GPR_TIMESPAN};
2304   *load_reporting_interval = gpr_time_to_millis(timespec);
2305   return GRPC_ERROR_NONE;
2306 }
2307 
2308 }  // namespace grpc_core
2309