• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include <grpc/impl/channel_arg_names.h>
18 #include <grpc/slice.h>
19 #include <grpc/status.h>
20 #include <grpc/support/port_platform.h>
21 #include <stdint.h>
22 #include <string.h>
23 
24 #include <algorithm>
25 #include <functional>
26 #include <map>
27 #include <memory>
28 #include <string>
29 #include <type_traits>
30 #include <utility>
31 #include <vector>
32 
33 #include "absl/log/check.h"
34 #include "absl/log/log.h"
35 #include "absl/meta/type_traits.h"
36 #include "absl/random/random.h"
37 #include "absl/status/status.h"
38 #include "absl/status/statusor.h"
39 #include "absl/strings/match.h"
40 #include "absl/strings/str_cat.h"
41 #include "absl/strings/str_format.h"
42 #include "absl/strings/str_join.h"
43 #include "absl/strings/str_replace.h"
44 #include "absl/strings/string_view.h"
45 #include "absl/strings/strip.h"
46 #include "absl/types/optional.h"
47 #include "absl/types/variant.h"
48 #include "re2/re2.h"
49 #include "src/core/client_channel/client_channel_internal.h"
50 #include "src/core/client_channel/config_selector.h"
51 #include "src/core/config/core_configuration.h"
52 #include "src/core/lib/channel/channel_args.h"
53 #include "src/core/lib/channel/channel_fwd.h"
54 #include "src/core/lib/channel/channel_stack.h"
55 #include "src/core/lib/channel/promise_based_filter.h"
56 #include "src/core/lib/channel/status_util.h"
57 #include "src/core/lib/debug/trace.h"
58 #include "src/core/lib/experiments/experiments.h"
59 #include "src/core/lib/iomgr/iomgr_fwd.h"
60 #include "src/core/lib/iomgr/pollset_set.h"
61 #include "src/core/lib/promise/arena_promise.h"
62 #include "src/core/lib/promise/context.h"
63 #include "src/core/lib/resource_quota/arena.h"
64 #include "src/core/lib/slice/slice.h"
65 #include "src/core/lib/transport/metadata_batch.h"
66 #include "src/core/lib/transport/transport.h"
67 #include "src/core/load_balancing/ring_hash/ring_hash.h"
68 #include "src/core/resolver/endpoint_addresses.h"
69 #include "src/core/resolver/resolver.h"
70 #include "src/core/resolver/resolver_factory.h"
71 #include "src/core/resolver/xds/xds_dependency_manager.h"
72 #include "src/core/resolver/xds/xds_resolver_attributes.h"
73 #include "src/core/service_config/service_config.h"
74 #include "src/core/service_config/service_config_impl.h"
75 #include "src/core/util/debug_location.h"
76 #include "src/core/util/dual_ref_counted.h"
77 #include "src/core/util/match.h"
78 #include "src/core/util/orphanable.h"
79 #include "src/core/util/ref_counted.h"
80 #include "src/core/util/ref_counted_ptr.h"
81 #include "src/core/util/time.h"
82 #include "src/core/util/uri.h"
83 #include "src/core/util/work_serializer.h"
84 #include "src/core/util/xxhash_inline.h"
85 #include "src/core/xds/grpc/xds_bootstrap_grpc.h"
86 #include "src/core/xds/grpc/xds_client_grpc.h"
87 #include "src/core/xds/grpc/xds_http_filter.h"
88 #include "src/core/xds/grpc/xds_listener.h"
89 #include "src/core/xds/grpc/xds_route_config.h"
90 #include "src/core/xds/grpc/xds_routing.h"
91 #include "src/core/xds/xds_client/xds_bootstrap.h"
92 
93 namespace grpc_core {
94 
95 namespace {
96 
97 //
98 // XdsResolver
99 //
100 
101 class XdsResolver final : public Resolver {
102  public:
XdsResolver(ResolverArgs args,std::string data_plane_authority)103   XdsResolver(ResolverArgs args, std::string data_plane_authority)
104       : work_serializer_(std::move(args.work_serializer)),
105         result_handler_(std::move(args.result_handler)),
106         args_(std::move(args.args)),
107         interested_parties_(args.pollset_set),
108         uri_(std::move(args.uri)),
109         data_plane_authority_(std::move(data_plane_authority)),
110         channel_id_(absl::Uniform<uint64_t>(absl::BitGen())) {
111     GRPC_TRACE_LOG(xds_resolver, INFO)
112         << "[xds_resolver " << this << "] created for URI " << uri_.ToString()
113         << "; data plane authority is " << data_plane_authority_;
114   }
115 
~XdsResolver()116   ~XdsResolver() override {
117     GRPC_TRACE_LOG(xds_resolver, INFO)
118         << "[xds_resolver " << this << "] destroyed";
119   }
120 
121   void StartLocked() override;
122 
123   void ShutdownLocked() override;
124 
RequestReresolutionLocked()125   void RequestReresolutionLocked() override {
126     if (dependency_mgr_ != nullptr) dependency_mgr_->RequestReresolution();
127   }
128 
ResetBackoffLocked()129   void ResetBackoffLocked() override {
130     if (xds_client_ != nullptr) xds_client_->ResetBackoff();
131     if (dependency_mgr_ != nullptr) dependency_mgr_->ResetBackoff();
132   }
133 
134  private:
135   class XdsWatcher final : public XdsDependencyManager::Watcher {
136    public:
XdsWatcher(RefCountedPtr<XdsResolver> resolver)137     explicit XdsWatcher(RefCountedPtr<XdsResolver> resolver)
138         : resolver_(std::move(resolver)) {}
139 
OnUpdate(absl::StatusOr<RefCountedPtr<const XdsConfig>> config)140     void OnUpdate(
141         absl::StatusOr<RefCountedPtr<const XdsConfig>> config) override {
142       resolver_->OnUpdate(std::move(config));
143     }
144 
145    private:
146     RefCountedPtr<XdsResolver> resolver_;
147   };
148 
149   // An entry in the map of clusters that need to be present in the LB
150   // policy config.  The map holds a weak ref.  One strong ref is held by
151   // the ConfigSelector, and another is held by each call assigned to
152   // the cluster by the ConfigSelector.  The ref for each call is held
153   // until the call is committed.  When the strong refs go away, we hop
154   // back into the WorkSerializer to remove the entry from the map.
155   class ClusterRef final : public DualRefCounted<ClusterRef> {
156    public:
ClusterRef(RefCountedPtr<XdsResolver> resolver,RefCountedPtr<XdsDependencyManager::ClusterSubscription> cluster_subscription,absl::string_view cluster_key)157     ClusterRef(RefCountedPtr<XdsResolver> resolver,
158                RefCountedPtr<XdsDependencyManager::ClusterSubscription>
159                    cluster_subscription,
160                absl::string_view cluster_key)
161         : resolver_(std::move(resolver)),
162           cluster_subscription_(std::move(cluster_subscription)),
163           cluster_key_(cluster_key) {}
164 
Orphaned()165     void Orphaned() override {
166       XdsResolver* resolver_ptr = resolver_.get();
167       resolver_ptr->work_serializer_->Run(
168           [resolver = std::move(resolver_)]() {
169             resolver->MaybeRemoveUnusedClusters();
170           },
171           DEBUG_LOCATION);
172       cluster_subscription_.reset();
173     }
174 
cluster_key() const175     const std::string& cluster_key() const { return cluster_key_; }
176 
177    private:
178     RefCountedPtr<XdsResolver> resolver_;
179     RefCountedPtr<XdsDependencyManager::ClusterSubscription>
180         cluster_subscription_;
181     std::string cluster_key_;
182   };
183 
184   // A routing data including cluster refs and routes table held by the
185   // XdsConfigSelector. A ref to this map will be taken by each call processed
186   // by the XdsConfigSelector, stored in a the call's call attributes, and later
187   // unreffed by the ClusterSelection filter.
188   class RouteConfigData final : public RefCounted<RouteConfigData> {
189    public:
190     struct RouteEntry {
191       struct ClusterWeightState {
192         uint32_t range_end;
193         absl::string_view cluster;
194         RefCountedPtr<ServiceConfig> method_config;
195 
operator ==grpc_core::__anon1bdda2e10111::XdsResolver::RouteConfigData::RouteEntry::ClusterWeightState196         bool operator==(const ClusterWeightState& other) const {
197           return range_end == other.range_end && cluster == other.cluster &&
198                  MethodConfigsEqual(method_config.get(),
199                                     other.method_config.get());
200         }
201       };
202 
203       XdsRouteConfigResource::Route route;
204       RefCountedPtr<ServiceConfig> method_config;
205       std::vector<ClusterWeightState> weighted_cluster_state;
206 
RouteEntrygrpc_core::__anon1bdda2e10111::XdsResolver::RouteConfigData::RouteEntry207       explicit RouteEntry(const XdsRouteConfigResource::Route& r) : route(r) {}
208 
operator ==grpc_core::__anon1bdda2e10111::XdsResolver::RouteConfigData::RouteEntry209       bool operator==(const RouteEntry& other) const {
210         return route == other.route &&
211                weighted_cluster_state == other.weighted_cluster_state &&
212                MethodConfigsEqual(method_config.get(),
213                                   other.method_config.get());
214       }
215     };
216 
217     static absl::StatusOr<RefCountedPtr<RouteConfigData>> Create(
218         XdsResolver* resolver, const Duration& default_max_stream_duration);
219 
operator ==(const RouteConfigData & other) const220     bool operator==(const RouteConfigData& other) const {
221       return clusters_ == other.clusters_ && routes_ == other.routes_;
222     }
223 
FindClusterRef(absl::string_view name) const224     RefCountedPtr<ClusterRef> FindClusterRef(absl::string_view name) const {
225       auto it = clusters_.find(name);
226       if (it == clusters_.end()) {
227         return nullptr;
228       }
229       return it->second;
230     }
231 
232     RouteEntry* GetRouteForRequest(absl::string_view path,
233                                    grpc_metadata_batch* initial_metadata);
234 
235    private:
236     class RouteListIterator;
237 
238     static absl::StatusOr<RefCountedPtr<ServiceConfig>> CreateMethodConfig(
239         XdsResolver* resolver, const XdsRouteConfigResource::Route& route,
240         const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
241             cluster_weight);
242 
MethodConfigsEqual(const ServiceConfig * sc1,const ServiceConfig * sc2)243     static bool MethodConfigsEqual(const ServiceConfig* sc1,
244                                    const ServiceConfig* sc2) {
245       if (sc1 == nullptr) return sc2 == nullptr;
246       if (sc2 == nullptr) return false;
247       return sc1->json_string() == sc2->json_string();
248     }
249 
250     absl::Status AddRouteEntry(XdsResolver* resolver,
251                                const XdsRouteConfigResource::Route& route,
252                                const Duration& default_max_stream_duration);
253 
254     std::map<absl::string_view, RefCountedPtr<ClusterRef>> clusters_;
255     std::vector<RouteEntry> routes_;
256   };
257 
258   class XdsConfigSelector final : public ConfigSelector {
259    public:
260     XdsConfigSelector(RefCountedPtr<XdsResolver> resolver,
261                       RefCountedPtr<RouteConfigData> route_config_data);
262     ~XdsConfigSelector() override;
263 
name() const264     UniqueTypeName name() const override {
265       static UniqueTypeName::Factory kFactory("XdsConfigSelector");
266       return kFactory.Create();
267     }
268 
Equals(const ConfigSelector * other) const269     bool Equals(const ConfigSelector* other) const override {
270       const auto* other_xds = static_cast<const XdsConfigSelector*>(other);
271       // Don't need to compare resolver_, since that will always be the same.
272       return *route_config_data_ == *other_xds->route_config_data_ &&
273              filters_ == other_xds->filters_;
274     }
275 
276     absl::Status GetCallConfig(GetCallConfigArgs args) override;
277 
278     void AddFilters(InterceptionChainBuilder& builder) override;
279 
280     std::vector<const grpc_channel_filter*> GetFilters() override;
281 
282    private:
283     RefCountedPtr<XdsResolver> resolver_;
284     RefCountedPtr<RouteConfigData> route_config_data_;
285     std::vector<const XdsHttpFilterImpl*> filters_;
286   };
287 
288   class XdsRouteStateAttributeImpl final : public XdsRouteStateAttribute {
289    public:
XdsRouteStateAttributeImpl(RefCountedPtr<RouteConfigData> route_config_data,RouteConfigData::RouteEntry * route)290     explicit XdsRouteStateAttributeImpl(
291         RefCountedPtr<RouteConfigData> route_config_data,
292         RouteConfigData::RouteEntry* route)
293         : route_config_data_(std::move(route_config_data)), route_(route) {}
294 
295     // This method can be called only once. The first call will release
296     // the reference to the cluster map, and subsequent calls will return
297     // nullptr.
298     RefCountedPtr<ClusterRef> LockAndGetCluster(absl::string_view cluster_name);
299 
300     bool HasClusterForRoute(absl::string_view cluster_name) const override;
301 
route() const302     const XdsRouteConfigResource::Route& route() const override {
303       return route_->route;
304     }
305 
306    private:
307     RefCountedPtr<RouteConfigData> route_config_data_;
308     RouteConfigData::RouteEntry* route_;
309   };
310 
311   class ClusterSelectionFilter final
312       : public ImplementChannelFilter<ClusterSelectionFilter> {
313    public:
314     const static grpc_channel_filter kFilter;
315 
TypeName()316     static absl::string_view TypeName() { return "cluster_selection_filter"; }
317 
Create(const ChannelArgs &,ChannelFilter::Args)318     static absl::StatusOr<std::unique_ptr<ClusterSelectionFilter>> Create(
319         const ChannelArgs& /* unused */,
320         ChannelFilter::Args /* filter_args */) {
321       return std::make_unique<ClusterSelectionFilter>();
322     }
323 
324     // Construct a promise for one call.
325     class Call {
326      public:
327       void OnClientInitialMetadata(ClientMetadata& md);
328       static const NoInterceptor OnServerInitialMetadata;
329       static const NoInterceptor OnServerTrailingMetadata;
330       static const NoInterceptor OnClientToServerMessage;
331       static const NoInterceptor OnClientToServerHalfClose;
332       static const NoInterceptor OnServerToClientMessage;
333       static const NoInterceptor OnFinalize;
334     };
335   };
336 
GetOrCreateClusterRef(absl::string_view cluster_key,absl::string_view cluster_name)337   RefCountedPtr<ClusterRef> GetOrCreateClusterRef(
338       absl::string_view cluster_key, absl::string_view cluster_name) {
339     auto it = cluster_ref_map_.find(cluster_key);
340     if (it == cluster_ref_map_.end()) {
341       RefCountedPtr<XdsDependencyManager::ClusterSubscription> subscription;
342       if (!cluster_name.empty()) {
343         // The cluster ref will hold a subscription to ensure that the
344         // XdsDependencyManager stays subscribed to the CDS resource as
345         // long as the cluster ref exists.
346         subscription = dependency_mgr_->GetClusterSubscription(cluster_name);
347       }
348       auto cluster = MakeRefCounted<ClusterRef>(
349           RefAsSubclass<XdsResolver>(), std::move(subscription), cluster_key);
350       cluster_ref_map_.emplace(cluster->cluster_key(), cluster->WeakRef());
351       return cluster;
352     }
353     return it->second->Ref();
354   }
355 
356   void OnUpdate(absl::StatusOr<RefCountedPtr<const XdsConfig>> config);
357 
358   absl::StatusOr<RefCountedPtr<ServiceConfig>> CreateServiceConfig();
359   void GenerateResult();
360   void GenerateErrorResult(std::string error);
361   void MaybeRemoveUnusedClusters();
362 
363   std::shared_ptr<WorkSerializer> work_serializer_;
364   std::unique_ptr<ResultHandler> result_handler_;
365   ChannelArgs args_;
366   grpc_pollset_set* interested_parties_;
367   URI uri_;
368   RefCountedPtr<GrpcXdsClient> xds_client_;
369   std::string lds_resource_name_;
370   std::string data_plane_authority_;
371   const uint64_t channel_id_;
372 
373   OrphanablePtr<XdsDependencyManager> dependency_mgr_;
374   RefCountedPtr<const XdsConfig> current_config_;
375   std::map<absl::string_view, WeakRefCountedPtr<ClusterRef>> cluster_ref_map_;
376 };
377 
378 const NoInterceptor
379     XdsResolver::ClusterSelectionFilter::Call::OnServerInitialMetadata;
380 const NoInterceptor
381     XdsResolver::ClusterSelectionFilter::Call::OnServerTrailingMetadata;
382 const NoInterceptor
383     XdsResolver::ClusterSelectionFilter::Call::OnClientToServerMessage;
384 const NoInterceptor
385     XdsResolver::ClusterSelectionFilter::Call::OnClientToServerHalfClose;
386 const NoInterceptor
387     XdsResolver::ClusterSelectionFilter::Call::OnServerToClientMessage;
388 const NoInterceptor XdsResolver::ClusterSelectionFilter::Call::OnFinalize;
389 
390 //
391 // XdsResolver::RouteConfigData::RouteListIterator
392 //
393 
394 // Implementation of XdsRouting::RouteListIterator for getting the matching
395 // route for a request.
396 class XdsResolver::RouteConfigData::RouteListIterator final
397     : public XdsRouting::RouteListIterator {
398  public:
RouteListIterator(const RouteConfigData * route_table)399   explicit RouteListIterator(const RouteConfigData* route_table)
400       : route_table_(route_table) {}
401 
Size() const402   size_t Size() const override { return route_table_->routes_.size(); }
403 
GetMatchersForRoute(size_t index) const404   const XdsRouteConfigResource::Route::Matchers& GetMatchersForRoute(
405       size_t index) const override {
406     return route_table_->routes_[index].route.matchers;
407   }
408 
409  private:
410   const RouteConfigData* route_table_;
411 };
412 
413 //
414 // XdsResolver::RouteConfigData
415 //
416 
417 absl::StatusOr<RefCountedPtr<XdsResolver::RouteConfigData>>
Create(XdsResolver * resolver,const Duration & default_max_stream_duration)418 XdsResolver::RouteConfigData::Create(
419     XdsResolver* resolver, const Duration& default_max_stream_duration) {
420   auto data = MakeRefCounted<RouteConfigData>();
421   // Reserve the necessary entries up-front to avoid reallocation as we add
422   // elements. This is necessary because the string_view in the entry's
423   // weighted_cluster_state field points to the memory in the route field, so
424   // moving the entry in a reallocation will cause the string_view to point to
425   // invalid data.
426   data->routes_.reserve(resolver->current_config_->virtual_host->routes.size());
427   for (auto& route : resolver->current_config_->virtual_host->routes) {
428     absl::Status status =
429         data->AddRouteEntry(resolver, route, default_max_stream_duration);
430     if (!status.ok()) {
431       return status;
432     }
433   }
434   return data;
435 }
436 
437 XdsResolver::RouteConfigData::RouteEntry*
GetRouteForRequest(absl::string_view path,grpc_metadata_batch * initial_metadata)438 XdsResolver::RouteConfigData::GetRouteForRequest(
439     absl::string_view path, grpc_metadata_batch* initial_metadata) {
440   auto route_index = XdsRouting::GetRouteForRequest(RouteListIterator(this),
441                                                     path, initial_metadata);
442   if (!route_index.has_value()) {
443     return nullptr;
444   }
445   return &routes_[*route_index];
446 }
447 
448 absl::StatusOr<RefCountedPtr<ServiceConfig>>
CreateMethodConfig(XdsResolver * resolver,const XdsRouteConfigResource::Route & route,const XdsRouteConfigResource::Route::RouteAction::ClusterWeight * cluster_weight)449 XdsResolver::RouteConfigData::CreateMethodConfig(
450     XdsResolver* resolver, const XdsRouteConfigResource::Route& route,
451     const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
452         cluster_weight) {
453   std::vector<std::string> fields;
454   const auto& route_action =
455       absl::get<XdsRouteConfigResource::Route::RouteAction>(route.action);
456   // Set retry policy if any.
457   if (route_action.retry_policy.has_value() &&
458       !route_action.retry_policy->retry_on.Empty()) {
459     std::vector<std::string> retry_parts;
460     retry_parts.push_back(absl::StrFormat(
461         "\"retryPolicy\": {\n"
462         "      \"maxAttempts\": %d,\n"
463         "      \"initialBackoff\": \"%s\",\n"
464         "      \"maxBackoff\": \"%s\",\n"
465         "      \"backoffMultiplier\": 2,\n",
466         route_action.retry_policy->num_retries + 1,
467         route_action.retry_policy->retry_back_off.base_interval.ToJsonString(),
468         route_action.retry_policy->retry_back_off.max_interval.ToJsonString()));
469     std::vector<std::string> code_parts;
470     if (route_action.retry_policy->retry_on.Contains(GRPC_STATUS_CANCELLED)) {
471       code_parts.push_back("        \"CANCELLED\"");
472     }
473     if (route_action.retry_policy->retry_on.Contains(
474             GRPC_STATUS_DEADLINE_EXCEEDED)) {
475       code_parts.push_back("        \"DEADLINE_EXCEEDED\"");
476     }
477     if (route_action.retry_policy->retry_on.Contains(GRPC_STATUS_INTERNAL)) {
478       code_parts.push_back("        \"INTERNAL\"");
479     }
480     if (route_action.retry_policy->retry_on.Contains(
481             GRPC_STATUS_RESOURCE_EXHAUSTED)) {
482       code_parts.push_back("        \"RESOURCE_EXHAUSTED\"");
483     }
484     if (route_action.retry_policy->retry_on.Contains(GRPC_STATUS_UNAVAILABLE)) {
485       code_parts.push_back("        \"UNAVAILABLE\"");
486     }
487     retry_parts.push_back(
488         absl::StrFormat("      \"retryableStatusCodes\": [\n %s ]\n",
489                         absl::StrJoin(code_parts, ",\n")));
490     retry_parts.push_back("    }");
491     fields.emplace_back(absl::StrJoin(retry_parts, ""));
492   }
493   // Set timeout.
494   if (route_action.max_stream_duration.has_value() &&
495       (route_action.max_stream_duration != Duration::Zero())) {
496     fields.emplace_back(
497         absl::StrFormat("    \"timeout\": \"%s\"",
498                         route_action.max_stream_duration->ToJsonString()));
499   }
500   // Handle xDS HTTP filters.
501   const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
502       resolver->current_config_->listener->listener);
503   auto result = XdsRouting::GeneratePerHTTPFilterConfigsForMethodConfig(
504       DownCast<const GrpcXdsBootstrap&>(resolver->xds_client_->bootstrap())
505           .http_filter_registry(),
506       hcm.http_filters, *resolver->current_config_->virtual_host, route,
507       cluster_weight, resolver->args_);
508   if (!result.ok()) return result.status();
509   for (const auto& p : result->per_filter_configs) {
510     fields.emplace_back(absl::StrCat("    \"", p.first, "\": [\n",
511                                      absl::StrJoin(p.second, ",\n"),
512                                      "\n    ]"));
513   }
514   // Construct service config.
515   if (!fields.empty()) {
516     std::string json = absl::StrCat(
517         "{\n"
518         "  \"methodConfig\": [ {\n"
519         "    \"name\": [\n"
520         "      {}\n"
521         "    ],\n"
522         "    ",
523         absl::StrJoin(fields, ",\n"),
524         "\n  } ]\n"
525         "}");
526     return ServiceConfigImpl::Create(result->args, json.c_str());
527   }
528   return nullptr;
529 }
530 
AddRouteEntry(XdsResolver * resolver,const XdsRouteConfigResource::Route & route,const Duration & default_max_stream_duration)531 absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
532     XdsResolver* resolver, const XdsRouteConfigResource::Route& route,
533     const Duration& default_max_stream_duration) {
534   GRPC_TRACE_LOG(xds_resolver, INFO)
535       << "[xds_resolver " << resolver << "] XdsConfigSelector " << this
536       << ": route: " << route.ToString();
537   routes_.emplace_back(route);
538   auto* route_entry = &routes_.back();
539   auto maybe_add_cluster = [&](absl::string_view cluster_key,
540                                absl::string_view cluster_name) {
541     if (clusters_.find(cluster_key) != clusters_.end()) return;
542     auto cluster_state =
543         resolver->GetOrCreateClusterRef(cluster_key, cluster_name);
544     absl::string_view key = cluster_state->cluster_key();
545     clusters_.emplace(key, std::move(cluster_state));
546   };
547   auto* route_action = absl::get_if<XdsRouteConfigResource::Route::RouteAction>(
548       &route_entry->route.action);
549   if (route_action != nullptr) {
550     // If the route doesn't specify a timeout, set its timeout to the global
551     // one.
552     if (!route_action->max_stream_duration.has_value()) {
553       route_action->max_stream_duration = default_max_stream_duration;
554     }
555     absl::Status status = Match(
556         route_action->action,
557         // cluster name
558         [&](const XdsRouteConfigResource::Route::RouteAction::ClusterName&
559                 cluster_name) {
560           auto result =
561               CreateMethodConfig(resolver, route_entry->route, nullptr);
562           if (!result.ok()) {
563             return result.status();
564           }
565           route_entry->method_config = std::move(*result);
566           maybe_add_cluster(absl::StrCat("cluster:", cluster_name.cluster_name),
567                             cluster_name.cluster_name);
568           return absl::OkStatus();
569         },
570         // WeightedClusters
571         [&](const std::vector<
572             XdsRouteConfigResource::Route::RouteAction::ClusterWeight>&
573                 weighted_clusters) {
574           uint32_t end = 0;
575           for (const auto& weighted_cluster : weighted_clusters) {
576             auto result = CreateMethodConfig(resolver, route_entry->route,
577                                              &weighted_cluster);
578             if (!result.ok()) {
579               return result.status();
580             }
581             RouteEntry::ClusterWeightState cluster_weight_state;
582             cluster_weight_state.method_config = std::move(*result);
583             end += weighted_cluster.weight;
584             cluster_weight_state.range_end = end;
585             cluster_weight_state.cluster = weighted_cluster.name;
586             route_entry->weighted_cluster_state.push_back(
587                 std::move(cluster_weight_state));
588             maybe_add_cluster(absl::StrCat("cluster:", weighted_cluster.name),
589                               weighted_cluster.name);
590           }
591           return absl::OkStatus();
592         },
593         // ClusterSpecifierPlugin
594         [&](const XdsRouteConfigResource::Route::RouteAction::
595                 ClusterSpecifierPluginName& cluster_specifier_plugin_name) {
596           auto result =
597               CreateMethodConfig(resolver, route_entry->route, nullptr);
598           if (!result.ok()) {
599             return result.status();
600           }
601           route_entry->method_config = std::move(*result);
602           maybe_add_cluster(
603               absl::StrCat(
604                   "cluster_specifier_plugin:",
605                   cluster_specifier_plugin_name.cluster_specifier_plugin_name),
606               /*subscription_name=*/"");
607           return absl::OkStatus();
608         });
609     if (!status.ok()) {
610       return status;
611     }
612   }
613   return absl::OkStatus();
614 }
615 
616 //
617 // XdsResolver::XdsConfigSelector
618 //
619 
XdsConfigSelector(RefCountedPtr<XdsResolver> resolver,RefCountedPtr<RouteConfigData> route_config_data)620 XdsResolver::XdsConfigSelector::XdsConfigSelector(
621     RefCountedPtr<XdsResolver> resolver,
622     RefCountedPtr<RouteConfigData> route_config_data)
623     : resolver_(std::move(resolver)),
624       route_config_data_(std::move(route_config_data)) {
625   GRPC_TRACE_LOG(xds_resolver, INFO) << "[xds_resolver " << resolver_.get()
626                                      << "] creating XdsConfigSelector " << this;
627   // Populate filter list.
628   const auto& http_filter_registry =
629       static_cast<const GrpcXdsBootstrap&>(resolver_->xds_client_->bootstrap())
630           .http_filter_registry();
631   const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
632       resolver_->current_config_->listener->listener);
633   for (const auto& http_filter : hcm.http_filters) {
634     // Find filter.  This is guaranteed to succeed, because it's checked
635     // at config validation time in the XdsApi code.
636     const XdsHttpFilterImpl* filter_impl =
637         http_filter_registry.GetFilterForType(
638             http_filter.config.config_proto_type_name);
639     CHECK_NE(filter_impl, nullptr);
640     // Add filter to list.
641     filters_.push_back(filter_impl);
642   }
643 }
644 
~XdsConfigSelector()645 XdsResolver::XdsConfigSelector::~XdsConfigSelector() {
646   GRPC_TRACE_LOG(xds_resolver, INFO)
647       << "[xds_resolver " << resolver_.get()
648       << "] destroying XdsConfigSelector " << this;
649   route_config_data_.reset();
650   if (!IsWorkSerializerDispatchEnabled()) {
651     resolver_->MaybeRemoveUnusedClusters();
652     return;
653   }
654   resolver_->work_serializer_->Run(
655       [resolver = std::move(resolver_)]() {
656         resolver->MaybeRemoveUnusedClusters();
657       },
658       DEBUG_LOCATION);
659 }
660 
HeaderHashHelper(const XdsRouteConfigResource::Route::RouteAction::HashPolicy::Header & header_policy,grpc_metadata_batch * initial_metadata)661 absl::optional<uint64_t> HeaderHashHelper(
662     const XdsRouteConfigResource::Route::RouteAction::HashPolicy::Header&
663         header_policy,
664     grpc_metadata_batch* initial_metadata) {
665   std::string value_buffer;
666   absl::optional<absl::string_view> header_value = XdsRouting::GetHeaderValue(
667       initial_metadata, header_policy.header_name, &value_buffer);
668   if (!header_value.has_value()) return absl::nullopt;
669   if (header_policy.regex != nullptr) {
670     // If GetHeaderValue() did not already store the value in
671     // value_buffer, copy it there now, so we can modify it.
672     if (header_value->data() != value_buffer.data()) {
673       value_buffer = std::string(*header_value);
674     }
675     RE2::GlobalReplace(&value_buffer, *header_policy.regex,
676                        header_policy.regex_substitution);
677     header_value = value_buffer;
678   }
679   return XXH64(header_value->data(), header_value->size(), 0);
680 }
681 
GetCallConfig(GetCallConfigArgs args)682 absl::Status XdsResolver::XdsConfigSelector::GetCallConfig(
683     GetCallConfigArgs args) {
684   Slice* path = args.initial_metadata->get_pointer(HttpPathMetadata());
685   CHECK_NE(path, nullptr);
686   auto* entry = route_config_data_->GetRouteForRequest(path->as_string_view(),
687                                                        args.initial_metadata);
688   if (entry == nullptr) {
689     return absl::UnavailableError(
690         "No matching route found in xDS route config");
691   }
692   // Found a route match
693   const auto* route_action =
694       absl::get_if<XdsRouteConfigResource::Route::RouteAction>(
695           &entry->route.action);
696   if (route_action == nullptr) {
697     return absl::UnavailableError("Matching route has inappropriate action");
698   }
699   std::string cluster_name;
700   RefCountedPtr<ServiceConfig> method_config;
701   Match(
702       route_action->action,
703       // cluster name
704       [&](const XdsRouteConfigResource::Route::RouteAction::ClusterName&
705               action_cluster_name) {
706         cluster_name =
707             absl::StrCat("cluster:", action_cluster_name.cluster_name);
708         method_config = entry->method_config;
709       },
710       // WeightedClusters
711       [&](const std::vector<
712           XdsRouteConfigResource::Route::RouteAction::ClusterWeight>&
713           /*weighted_clusters*/) {
714         const uint32_t key = absl::Uniform<uint32_t>(
715             absl::BitGen(), 0, entry->weighted_cluster_state.back().range_end);
716         // Find the index in weighted clusters corresponding to key.
717         size_t mid = 0;
718         size_t start_index = 0;
719         size_t end_index = entry->weighted_cluster_state.size() - 1;
720         size_t index = 0;
721         while (end_index > start_index) {
722           mid = (start_index + end_index) / 2;
723           if (entry->weighted_cluster_state[mid].range_end > key) {
724             end_index = mid;
725           } else if (entry->weighted_cluster_state[mid].range_end < key) {
726             start_index = mid + 1;
727           } else {
728             index = mid + 1;
729             break;
730           }
731         }
732         if (index == 0) index = start_index;
733         CHECK(entry->weighted_cluster_state[index].range_end > key);
734         cluster_name = absl::StrCat(
735             "cluster:", entry->weighted_cluster_state[index].cluster);
736         method_config = entry->weighted_cluster_state[index].method_config;
737       },
738       // ClusterSpecifierPlugin
739       [&](const XdsRouteConfigResource::Route::RouteAction::
740               ClusterSpecifierPluginName& cluster_specifier_plugin_name) {
741         cluster_name = absl::StrCat(
742             "cluster_specifier_plugin:",
743             cluster_specifier_plugin_name.cluster_specifier_plugin_name);
744         method_config = entry->method_config;
745       });
746   auto cluster = route_config_data_->FindClusterRef(cluster_name);
747   CHECK(cluster != nullptr);
748   // Generate a hash.
749   absl::optional<uint64_t> hash;
750   for (const auto& hash_policy : route_action->hash_policies) {
751     absl::optional<uint64_t> new_hash = Match(
752         hash_policy.policy,
753         [&](const XdsRouteConfigResource::Route::RouteAction::HashPolicy::
754                 Header& header) {
755           return HeaderHashHelper(header, args.initial_metadata);
756         },
757         [&](const XdsRouteConfigResource::Route::RouteAction::HashPolicy::
758                 ChannelId&) -> absl::optional<uint64_t> {
759           return resolver_->channel_id_;
760         });
761     if (new_hash.has_value()) {
762       // Rotating the old value prevents duplicate hash rules from cancelling
763       // each other out and preserves all of the entropy
764       const uint64_t old_value =
765           hash.has_value() ? ((*hash << 1) | (*hash >> 63)) : 0;
766       hash = old_value ^ *new_hash;
767     }
768     // If the policy is a terminal policy and a hash has been generated,
769     // ignore the rest of the hash policies.
770     if (hash_policy.terminal && hash.has_value()) {
771       break;
772     }
773   }
774   if (!hash.has_value()) {
775     hash = absl::Uniform<uint64_t>(absl::BitGen());
776   }
777   // Populate service config call data.
778   if (method_config != nullptr) {
779     auto* parsed_method_configs =
780         method_config->GetMethodParsedConfigVector(grpc_empty_slice());
781     args.service_config_call_data->SetServiceConfig(std::move(method_config),
782                                                     parsed_method_configs);
783   }
784   args.service_config_call_data->SetCallAttribute(
785       args.arena->New<XdsClusterAttribute>(cluster->cluster_key()));
786   args.service_config_call_data->SetCallAttribute(
787       args.arena->New<RequestHashAttribute>(*hash));
788   args.service_config_call_data->SetCallAttribute(
789       args.arena->ManagedNew<XdsRouteStateAttributeImpl>(route_config_data_,
790                                                          entry));
791   return absl::OkStatus();
792 }
793 
AddFilters(InterceptionChainBuilder & builder)794 void XdsResolver::XdsConfigSelector::AddFilters(
795     InterceptionChainBuilder& builder) {
796   for (const XdsHttpFilterImpl* filter : filters_) {
797     filter->AddFilter(builder);
798   }
799   builder.Add<ClusterSelectionFilter>();
800 }
801 
802 std::vector<const grpc_channel_filter*>
GetFilters()803 XdsResolver::XdsConfigSelector::GetFilters() {
804   std::vector<const grpc_channel_filter*> filters;
805   for (const XdsHttpFilterImpl* filter : filters_) {
806     if (filter->channel_filter() != nullptr) {
807       filters.push_back(filter->channel_filter());
808     }
809   }
810   filters.push_back(&ClusterSelectionFilter::kFilter);
811   return filters;
812 }
813 
814 //
815 // XdsResolver::XdsRouteStateAttributeImpl
816 //
817 
HasClusterForRoute(absl::string_view cluster_name) const818 bool XdsResolver::XdsRouteStateAttributeImpl::HasClusterForRoute(
819     absl::string_view cluster_name) const {
820   // Found a route match
821   const auto* route_action =
822       absl::get_if<XdsRouteConfigResource::Route::RouteAction>(
823           &static_cast<RouteConfigData::RouteEntry*>(route_)->route.action);
824   if (route_action == nullptr) return false;
825   return Match(
826       route_action->action,
827       [&](const XdsRouteConfigResource::Route::RouteAction::ClusterName& name) {
828         return name.cluster_name == cluster_name;
829       },
830       [&](const std::vector<
831           XdsRouteConfigResource::Route::RouteAction::ClusterWeight>&
832               clusters) {
833         for (const auto& cluster : clusters) {
834           if (cluster.name == cluster_name) {
835             return true;
836           }
837         }
838         return false;
839       },
840       [&](const XdsRouteConfigResource::Route::RouteAction::
841               ClusterSpecifierPluginName& /* name */) { return false; });
842 }
843 
844 RefCountedPtr<XdsResolver::ClusterRef>
LockAndGetCluster(absl::string_view cluster_name)845 XdsResolver::XdsRouteStateAttributeImpl::LockAndGetCluster(
846     absl::string_view cluster_name) {
847   if (route_config_data_ == nullptr) {
848     return nullptr;
849   }
850   auto cluster = route_config_data_->FindClusterRef(cluster_name);
851   route_config_data_.reset();
852   return cluster;
853 }
854 
855 //
856 // XdsResolver::ClusterSelectionFilter
857 //
858 
859 const grpc_channel_filter XdsResolver::ClusterSelectionFilter::kFilter =
860     MakePromiseBasedFilter<ClusterSelectionFilter, FilterEndpoint::kClient,
861                            kFilterExaminesServerInitialMetadata>();
862 
OnClientInitialMetadata(ClientMetadata &)863 void XdsResolver::ClusterSelectionFilter::Call::OnClientInitialMetadata(
864     ClientMetadata&) {
865   auto* service_config_call_data =
866       GetContext<ClientChannelServiceConfigCallData>();
867   CHECK_NE(service_config_call_data, nullptr);
868   auto* route_state_attribute = static_cast<XdsRouteStateAttributeImpl*>(
869       service_config_call_data->GetCallAttribute<XdsRouteStateAttribute>());
870   auto* cluster_name_attribute =
871       service_config_call_data->GetCallAttribute<XdsClusterAttribute>();
872   if (route_state_attribute != nullptr && cluster_name_attribute != nullptr) {
873     auto cluster = route_state_attribute->LockAndGetCluster(
874         cluster_name_attribute->cluster());
875     if (cluster != nullptr) {
876       service_config_call_data->SetOnCommit(
877           [cluster = std::move(cluster)]() mutable { cluster.reset(); });
878     }
879   }
880 }
881 
882 //
883 // XdsResolver
884 //
885 
StartLocked()886 void XdsResolver::StartLocked() {
887   auto xds_client =
888       GrpcXdsClient::GetOrCreate(uri_.ToString(), args_, "xds resolver");
889   if (!xds_client.ok()) {
890     LOG(ERROR) << "Failed to create xds client -- channel will remain in "
891                   "TRANSIENT_FAILURE: "
892                << xds_client.status();
893     absl::Status status = absl::UnavailableError(absl::StrCat(
894         "Failed to create XdsClient: ", xds_client.status().message()));
895     Result result;
896     result.addresses = status;
897     result.service_config = std::move(status);
898     result.args = args_;
899     result_handler_->ReportResult(std::move(result));
900     return;
901   }
902   xds_client_ = std::move(*xds_client);
903   grpc_pollset_set_add_pollset_set(xds_client_->interested_parties(),
904                                    interested_parties_);
905   // Determine LDS resource name.
906   std::string resource_name_fragment(absl::StripPrefix(uri_.path(), "/"));
907   if (!uri_.authority().empty()) {
908     // target_uri.authority is set case
909     const auto* authority_config =
910         static_cast<const GrpcXdsBootstrap::GrpcAuthority*>(
911             xds_client_->bootstrap().LookupAuthority(uri_.authority()));
912     if (authority_config == nullptr) {
913       absl::Status status = absl::UnavailableError(
914           absl::StrCat("Invalid target URI -- authority not found for ",
915                        uri_.authority().c_str()));
916       Result result;
917       result.addresses = status;
918       result.service_config = std::move(status);
919       result.args = args_;
920       result_handler_->ReportResult(std::move(result));
921       return;
922     }
923     std::string name_template =
924         authority_config->client_listener_resource_name_template();
925     if (name_template.empty()) {
926       name_template = absl::StrCat(
927           "xdstp://", URI::PercentEncodeAuthority(uri_.authority()),
928           "/envoy.config.listener.v3.Listener/%s");
929     }
930     lds_resource_name_ = absl::StrReplaceAll(
931         name_template,
932         {{"%s", URI::PercentEncodePath(resource_name_fragment)}});
933   } else {
934     // target_uri.authority not set
935     absl::string_view name_template =
936         static_cast<const GrpcXdsBootstrap&>(xds_client_->bootstrap())
937             .client_default_listener_resource_name_template();
938     if (name_template.empty()) {
939       name_template = "%s";
940     }
941     if (absl::StartsWith(name_template, "xdstp:")) {
942       resource_name_fragment = URI::PercentEncodePath(resource_name_fragment);
943     }
944     lds_resource_name_ =
945         absl::StrReplaceAll(name_template, {{"%s", resource_name_fragment}});
946   }
947   GRPC_TRACE_LOG(xds_resolver, INFO)
948       << "[xds_resolver " << this << "] Started with lds_resource_name "
949       << lds_resource_name_;
950   // Start watch for xDS config.
951   dependency_mgr_ = MakeOrphanable<XdsDependencyManager>(
952       xds_client_, work_serializer_,
953       std::make_unique<XdsWatcher>(RefAsSubclass<XdsResolver>()),
954       data_plane_authority_, lds_resource_name_, args_, interested_parties_);
955 }
956 
ShutdownLocked()957 void XdsResolver::ShutdownLocked() {
958   GRPC_TRACE_LOG(xds_resolver, INFO)
959       << "[xds_resolver " << this << "] shutting down";
960   if (xds_client_ != nullptr) {
961     dependency_mgr_.reset();
962     grpc_pollset_set_del_pollset_set(xds_client_->interested_parties(),
963                                      interested_parties_);
964     xds_client_.reset(DEBUG_LOCATION, "xds resolver");
965   }
966 }
967 
OnUpdate(absl::StatusOr<RefCountedPtr<const XdsConfig>> config)968 void XdsResolver::OnUpdate(
969     absl::StatusOr<RefCountedPtr<const XdsConfig>> config) {
970   GRPC_TRACE_LOG(xds_resolver, INFO)
971       << "[xds_resolver " << this << "] received updated xDS config";
972   if (xds_client_ == nullptr) return;
973   if (!config.ok()) {
974     LOG(ERROR) << "[xds_resolver " << this << "] config error ("
975                << config.status()
976                << ") -- clearing update and returning empty service config";
977     current_config_.reset();
978     GenerateErrorResult(std::string(config.status().message()));
979     return;
980   }
981   current_config_ = std::move(*config);
982   GenerateResult();
983 }
984 
985 absl::StatusOr<RefCountedPtr<ServiceConfig>>
CreateServiceConfig()986 XdsResolver::CreateServiceConfig() {
987   std::vector<std::string> clusters;
988   for (const auto& cluster : cluster_ref_map_) {
989     absl::string_view child_name = cluster.first;
990     if (absl::ConsumePrefix(&child_name, "cluster_specifier_plugin:")) {
991       clusters.push_back(absl::StrFormat(
992           "      \"%s\":{\n"
993           "        \"childPolicy\": %s\n"
994           "       }",
995           cluster.first,
996           current_config_->route_config->cluster_specifier_plugin_map.at(
997               std::string(child_name))));
998     } else {
999       absl::ConsumePrefix(&child_name, "cluster:");
1000       clusters.push_back(
1001           absl::StrFormat("      \"%s\":{\n"
1002                           "        \"childPolicy\":[ {\n"
1003                           "          \"cds_experimental\":{\n"
1004                           "            \"cluster\": \"%s\"\n"
1005                           "          }\n"
1006                           "        } ]\n"
1007                           "       }",
1008                           cluster.first, child_name));
1009     }
1010   }
1011   std::vector<std::string> config_parts;
1012   config_parts.push_back(
1013       absl::StrCat("  \"loadBalancingConfig\":[\n"
1014                    "    { \"xds_cluster_manager_experimental\":{\n"
1015                    "      \"children\":{\n",
1016                    absl::StrJoin(clusters, ",\n"),
1017                    "    }\n"
1018                    "    } }\n"
1019                    "  ]"));
1020   auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
1021       current_config_->listener->listener);
1022   auto filter_configs =
1023       XdsRouting::GeneratePerHTTPFilterConfigsForServiceConfig(
1024           static_cast<const GrpcXdsBootstrap&>(xds_client_->bootstrap())
1025               .http_filter_registry(),
1026           hcm.http_filters, args_);
1027   if (!filter_configs.ok()) return filter_configs.status();
1028   for (const auto& p : filter_configs->per_filter_configs) {
1029     config_parts.emplace_back(absl::StrCat(
1030         "  \"", p.first, "\": [\n", absl::StrJoin(p.second, ",\n"), "\n  ]"));
1031   }
1032   std::string json = absl::StrCat("{", absl::StrJoin(config_parts, ",\n"), "}");
1033   return ServiceConfigImpl::Create(filter_configs->args, json.c_str());
1034 }
1035 
GenerateResult()1036 void XdsResolver::GenerateResult() {
1037   if (xds_client_ == nullptr || current_config_ == nullptr) return;
1038   // First create XdsConfigSelector, which may add new entries to the cluster
1039   // state map.
1040   const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
1041       current_config_->listener->listener);
1042   auto route_config_data =
1043       RouteConfigData::Create(this, hcm.http_max_stream_duration);
1044   if (!route_config_data.ok()) {
1045     GenerateErrorResult(absl::StrCat("could not create ConfigSelector: ",
1046                                      route_config_data.status().message()));
1047     return;
1048   }
1049   auto config_selector = MakeRefCounted<XdsConfigSelector>(
1050       RefAsSubclass<XdsResolver>(), std::move(*route_config_data));
1051   // Now create the service config.
1052   Result result;
1053   result.addresses.emplace();
1054   result.service_config = CreateServiceConfig();
1055   GRPC_TRACE_LOG(xds_resolver, INFO)
1056       << "[xds_resolver " << this << "] generated service config: "
1057       << (result.service_config.ok()
1058               ? ((*result.service_config)->json_string())
1059               : result.service_config.status().ToString());
1060   result.args =
1061       args_.SetObject(xds_client_.Ref(DEBUG_LOCATION, "xds resolver result"))
1062           .SetObject(config_selector)
1063           .SetObject(current_config_)
1064           .SetObject(dependency_mgr_->Ref());
1065   result_handler_->ReportResult(std::move(result));
1066 }
1067 
GenerateErrorResult(std::string error)1068 void XdsResolver::GenerateErrorResult(std::string error) {
1069   Result result;
1070   result.addresses.emplace();
1071   result.service_config = ServiceConfigImpl::Create(args_, "{}");
1072   CHECK(result.service_config.ok());
1073   result.resolution_note = std::move(error);
1074   result.args = args_;
1075   result_handler_->ReportResult(std::move(result));
1076 }
1077 
MaybeRemoveUnusedClusters()1078 void XdsResolver::MaybeRemoveUnusedClusters() {
1079   bool update_needed = false;
1080   for (auto it = cluster_ref_map_.begin(); it != cluster_ref_map_.end();) {
1081     RefCountedPtr<ClusterRef> cluster_state = it->second->RefIfNonZero();
1082     if (cluster_state != nullptr) {
1083       ++it;
1084     } else {
1085       update_needed = true;
1086       it = cluster_ref_map_.erase(it);
1087     }
1088   }
1089   if (update_needed) GenerateResult();
1090 }
1091 
1092 //
1093 // XdsResolverFactory
1094 //
1095 
1096 class XdsResolverFactory final : public ResolverFactory {
1097  public:
scheme() const1098   absl::string_view scheme() const override { return "xds"; }
1099 
IsValidUri(const URI & uri) const1100   bool IsValidUri(const URI& uri) const override {
1101     if (uri.path().empty() || uri.path().back() == '/') {
1102       LOG(ERROR) << "URI path does not contain valid data plane authority";
1103       return false;
1104     }
1105     return true;
1106   }
1107 
CreateResolver(ResolverArgs args) const1108   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
1109     if (!IsValidUri(args.uri)) return nullptr;
1110     std::string authority = GetDataPlaneAuthority(args.args, args.uri);
1111     return MakeOrphanable<XdsResolver>(std::move(args), std::move(authority));
1112   }
1113 
1114  private:
GetDataPlaneAuthority(const ChannelArgs & args,const URI & uri) const1115   std::string GetDataPlaneAuthority(const ChannelArgs& args,
1116                                     const URI& uri) const {
1117     absl::optional<absl::string_view> authority =
1118         args.GetString(GRPC_ARG_DEFAULT_AUTHORITY);
1119     if (authority.has_value()) return URI::PercentEncodeAuthority(*authority);
1120     return GetDefaultAuthority(uri);
1121   }
1122 };
1123 
1124 }  // namespace
1125 
RegisterXdsResolver(CoreConfiguration::Builder * builder)1126 void RegisterXdsResolver(CoreConfiguration::Builder* builder) {
1127   builder->resolver_registry()->RegisterResolverFactory(
1128       std::make_unique<XdsResolverFactory>());
1129 }
1130 
1131 }  // namespace grpc_core
1132