• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2020 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 "absl/strings/str_replace.h"
22 
23 #include "src/core/ext/xds/xds_certificate_provider.h"
24 #include "src/core/ext/xds/xds_client.h"
25 #include "src/core/lib/address_utils/sockaddr_utils.h"
26 #include "src/core/lib/channel/channel_args.h"
27 #include "src/core/lib/gprpp/host_port.h"
28 #include "src/core/lib/iomgr/sockaddr.h"
29 #include "src/core/lib/iomgr/socket_utils.h"
30 #include "src/core/lib/security/credentials/xds/xds_credentials.h"
31 #include "src/core/lib/surface/api_trace.h"
32 #include "src/core/lib/surface/server.h"
33 #include "src/core/lib/uri/uri_parser.h"
34 
35 namespace grpc_core {
36 
37 TraceFlag grpc_xds_server_config_fetcher_trace(false,
38                                                "xds_server_config_fetcher");
39 
40 namespace {
41 
42 class FilterChainMatchManager
43     : public grpc_server_config_fetcher::ConnectionManager {
44  public:
FilterChainMatchManager(RefCountedPtr<XdsClient> xds_client,XdsApi::LdsUpdate::FilterChainMap filter_chain_map,absl::optional<XdsApi::LdsUpdate::FilterChainData> default_filter_chain)45   FilterChainMatchManager(
46       RefCountedPtr<XdsClient> xds_client,
47       XdsApi::LdsUpdate::FilterChainMap filter_chain_map,
48       absl::optional<XdsApi::LdsUpdate::FilterChainData> default_filter_chain)
49       : xds_client_(xds_client),
50         filter_chain_map_(std::move(filter_chain_map)),
51         default_filter_chain_(std::move(default_filter_chain)) {}
52 
53   absl::StatusOr<grpc_channel_args*> UpdateChannelArgsForConnection(
54       grpc_channel_args* args, grpc_endpoint* tcp) override;
55 
filter_chain_map() const56   const XdsApi::LdsUpdate::FilterChainMap& filter_chain_map() const {
57     return filter_chain_map_;
58   }
59 
60   const absl::optional<XdsApi::LdsUpdate::FilterChainData>&
default_filter_chain() const61   default_filter_chain() const {
62     return default_filter_chain_;
63   }
64 
65  private:
66   struct CertificateProviders {
67     // We need to save our own refs to the root and instance certificate
68     // providers since the xds certificate provider just stores a ref to their
69     // distributors.
70     RefCountedPtr<grpc_tls_certificate_provider> root;
71     RefCountedPtr<grpc_tls_certificate_provider> instance;
72     RefCountedPtr<XdsCertificateProvider> xds;
73   };
74 
75   absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
76   CreateOrGetXdsCertificateProviderFromFilterChainData(
77       const XdsApi::LdsUpdate::FilterChainData* filter_chain);
78 
79   const RefCountedPtr<XdsClient> xds_client_;
80   const XdsApi::LdsUpdate::FilterChainMap filter_chain_map_;
81   const absl::optional<XdsApi::LdsUpdate::FilterChainData>
82       default_filter_chain_;
83   Mutex mu_;
84   std::map<const XdsApi::LdsUpdate::FilterChainData*, CertificateProviders>
85       certificate_providers_map_ ABSL_GUARDED_BY(mu_);
86 };
87 
IsLoopbackIp(const grpc_resolved_address * address)88 bool IsLoopbackIp(const grpc_resolved_address* address) {
89   const grpc_sockaddr* sock_addr =
90       reinterpret_cast<const grpc_sockaddr*>(&address->addr);
91   if (sock_addr->sa_family == GRPC_AF_INET) {
92     const grpc_sockaddr_in* addr4 =
93         reinterpret_cast<const grpc_sockaddr_in*>(sock_addr);
94     if (addr4->sin_addr.s_addr == grpc_htonl(INADDR_LOOPBACK)) {
95       return true;
96     }
97   } else if (sock_addr->sa_family == GRPC_AF_INET6) {
98     const grpc_sockaddr_in6* addr6 =
99         reinterpret_cast<const grpc_sockaddr_in6*>(sock_addr);
100     if (memcmp(&addr6->sin6_addr, &in6addr_loopback,
101                sizeof(in6addr_loopback)) == 0) {
102       return true;
103     }
104   }
105   return false;
106 }
107 
FindFilterChainDataForSourcePort(const XdsApi::LdsUpdate::FilterChainMap::SourcePortsMap & source_ports_map,absl::string_view port_str)108 const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourcePort(
109     const XdsApi::LdsUpdate::FilterChainMap::SourcePortsMap& source_ports_map,
110     absl::string_view port_str) {
111   int port = 0;
112   if (!absl::SimpleAtoi(port_str, &port)) return nullptr;
113   auto it = source_ports_map.find(port);
114   if (it != source_ports_map.end()) {
115     return it->second.data.get();
116   }
117   // Search for the catch-all port 0 since we didn't get a direct match
118   it = source_ports_map.find(0);
119   if (it != source_ports_map.end()) {
120     return it->second.data.get();
121   }
122   return nullptr;
123 }
124 
FindFilterChainDataForSourceIp(const XdsApi::LdsUpdate::FilterChainMap::SourceIpVector & source_ip_vector,const grpc_resolved_address * source_ip,absl::string_view port)125 const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourceIp(
126     const XdsApi::LdsUpdate::FilterChainMap::SourceIpVector& source_ip_vector,
127     const grpc_resolved_address* source_ip, absl::string_view port) {
128   const XdsApi::LdsUpdate::FilterChainMap::SourceIp* best_match = nullptr;
129   for (const auto& entry : source_ip_vector) {
130     // Special case for catch-all
131     if (!entry.prefix_range.has_value()) {
132       if (best_match == nullptr) {
133         best_match = &entry;
134       }
135       continue;
136     }
137     if (best_match != nullptr && best_match->prefix_range.has_value() &&
138         best_match->prefix_range->prefix_len >=
139             entry.prefix_range->prefix_len) {
140       continue;
141     }
142     if (grpc_sockaddr_match_subnet(source_ip, &entry.prefix_range->address,
143                                    entry.prefix_range->prefix_len)) {
144       best_match = &entry;
145     }
146   }
147   if (best_match == nullptr) return nullptr;
148   return FindFilterChainDataForSourcePort(best_match->ports_map, port);
149 }
150 
FindFilterChainDataForSourceType(const XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceTypesArray & source_types_array,grpc_endpoint * tcp,absl::string_view destination_ip)151 const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourceType(
152     const XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceTypesArray&
153         source_types_array,
154     grpc_endpoint* tcp, absl::string_view destination_ip) {
155   auto source_uri = URI::Parse(grpc_endpoint_get_peer(tcp));
156   if (!source_uri.ok() ||
157       (source_uri->scheme() != "ipv4" && source_uri->scheme() != "ipv6")) {
158     return nullptr;
159   }
160   std::string host;
161   std::string port;
162   if (!SplitHostPort(source_uri->path(), &host, &port)) {
163     return nullptr;
164   }
165   grpc_resolved_address source_addr;
166   grpc_error_handle error = grpc_string_to_sockaddr(
167       &source_addr, host.c_str(), 0 /* port doesn't matter here */);
168   if (error != GRPC_ERROR_NONE) {
169     gpr_log(GPR_DEBUG, "Could not parse string to socket address: %s",
170             host.c_str());
171     GRPC_ERROR_UNREF(error);
172     return nullptr;
173   }
174   // Use kAny only if kSameIporLoopback and kExternal are empty
175   if (source_types_array[static_cast<int>(
176                              XdsApi::LdsUpdate::FilterChainMap::
177                                  ConnectionSourceType::kSameIpOrLoopback)]
178           .empty() &&
179       source_types_array[static_cast<int>(XdsApi::LdsUpdate::FilterChainMap::
180                                               ConnectionSourceType::kExternal)]
181           .empty()) {
182     return FindFilterChainDataForSourceIp(
183         source_types_array[static_cast<int>(
184             XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::kAny)],
185         &source_addr, port);
186   }
187   if (IsLoopbackIp(&source_addr) || host == destination_ip) {
188     return FindFilterChainDataForSourceIp(
189         source_types_array[static_cast<int>(
190             XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::
191                 kSameIpOrLoopback)],
192         &source_addr, port);
193   } else {
194     return FindFilterChainDataForSourceIp(
195         source_types_array[static_cast<int>(
196             XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::
197                 kExternal)],
198         &source_addr, port);
199   }
200 }
201 
FindFilterChainDataForDestinationIp(const XdsApi::LdsUpdate::FilterChainMap::DestinationIpVector destination_ip_vector,grpc_endpoint * tcp)202 const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForDestinationIp(
203     const XdsApi::LdsUpdate::FilterChainMap::DestinationIpVector
204         destination_ip_vector,
205     grpc_endpoint* tcp) {
206   auto destination_uri = URI::Parse(grpc_endpoint_get_local_address(tcp));
207   if (!destination_uri.ok() || (destination_uri->scheme() != "ipv4" &&
208                                 destination_uri->scheme() != "ipv6")) {
209     return nullptr;
210   }
211   std::string host;
212   std::string port;
213   if (!SplitHostPort(destination_uri->path(), &host, &port)) {
214     return nullptr;
215   }
216   grpc_resolved_address destination_addr;
217   grpc_error_handle error = grpc_string_to_sockaddr(
218       &destination_addr, host.c_str(), 0 /* port doesn't matter here */);
219   if (error != GRPC_ERROR_NONE) {
220     gpr_log(GPR_DEBUG, "Could not parse string to socket address: %s",
221             host.c_str());
222     GRPC_ERROR_UNREF(error);
223     return nullptr;
224   }
225   const XdsApi::LdsUpdate::FilterChainMap::DestinationIp* best_match = nullptr;
226   for (const auto& entry : destination_ip_vector) {
227     // Special case for catch-all
228     if (!entry.prefix_range.has_value()) {
229       if (best_match == nullptr) {
230         best_match = &entry;
231       }
232       continue;
233     }
234     if (best_match != nullptr && best_match->prefix_range.has_value() &&
235         best_match->prefix_range->prefix_len >=
236             entry.prefix_range->prefix_len) {
237       continue;
238     }
239     if (grpc_sockaddr_match_subnet(&destination_addr,
240                                    &entry.prefix_range->address,
241                                    entry.prefix_range->prefix_len)) {
242       best_match = &entry;
243     }
244   }
245   if (best_match == nullptr) return nullptr;
246   return FindFilterChainDataForSourceType(best_match->source_types_array, tcp,
247                                           host);
248 }
249 
250 absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
CreateOrGetXdsCertificateProviderFromFilterChainData(const XdsApi::LdsUpdate::FilterChainData * filter_chain)251 FilterChainMatchManager::CreateOrGetXdsCertificateProviderFromFilterChainData(
252     const XdsApi::LdsUpdate::FilterChainData* filter_chain) {
253   MutexLock lock(&mu_);
254   auto it = certificate_providers_map_.find(filter_chain);
255   if (it != certificate_providers_map_.end()) {
256     return it->second.xds;
257   }
258   CertificateProviders certificate_providers;
259   // Configure root cert.
260   absl::string_view root_provider_instance_name =
261       filter_chain->downstream_tls_context.common_tls_context
262           .combined_validation_context
263           .validation_context_certificate_provider_instance.instance_name;
264   absl::string_view root_provider_cert_name =
265       filter_chain->downstream_tls_context.common_tls_context
266           .combined_validation_context
267           .validation_context_certificate_provider_instance.certificate_name;
268   if (!root_provider_instance_name.empty()) {
269     certificate_providers.root =
270         xds_client_->certificate_provider_store()
271             .CreateOrGetCertificateProvider(root_provider_instance_name);
272     if (certificate_providers.root == nullptr) {
273       return absl::NotFoundError(
274           absl::StrCat("Certificate provider instance name: \"",
275                        root_provider_instance_name, "\" not recognized."));
276     }
277   }
278   // Configure identity cert.
279   absl::string_view identity_provider_instance_name =
280       filter_chain->downstream_tls_context.common_tls_context
281           .tls_certificate_certificate_provider_instance.instance_name;
282   absl::string_view identity_provider_cert_name =
283       filter_chain->downstream_tls_context.common_tls_context
284           .tls_certificate_certificate_provider_instance.certificate_name;
285   if (!identity_provider_instance_name.empty()) {
286     certificate_providers.instance =
287         xds_client_->certificate_provider_store()
288             .CreateOrGetCertificateProvider(identity_provider_instance_name);
289     if (certificate_providers.instance == nullptr) {
290       return absl::NotFoundError(
291           absl::StrCat("Certificate provider instance name: \"",
292                        identity_provider_instance_name, "\" not recognized."));
293     }
294   }
295   certificate_providers.xds = MakeRefCounted<XdsCertificateProvider>();
296   certificate_providers.xds->UpdateRootCertNameAndDistributor(
297       "", root_provider_cert_name,
298       certificate_providers.root == nullptr
299           ? nullptr
300           : certificate_providers.root->distributor());
301   certificate_providers.xds->UpdateIdentityCertNameAndDistributor(
302       "", identity_provider_cert_name,
303       certificate_providers.instance == nullptr
304           ? nullptr
305           : certificate_providers.instance->distributor());
306   certificate_providers.xds->UpdateRequireClientCertificate(
307       "", filter_chain->downstream_tls_context.require_client_certificate);
308   auto xds_certificate_provider = certificate_providers.xds;
309   certificate_providers_map_.emplace(filter_chain,
310                                      std::move(certificate_providers));
311   return xds_certificate_provider;
312 }
313 
314 absl::StatusOr<grpc_channel_args*>
UpdateChannelArgsForConnection(grpc_channel_args * args,grpc_endpoint * tcp)315 FilterChainMatchManager::UpdateChannelArgsForConnection(grpc_channel_args* args,
316                                                         grpc_endpoint* tcp) {
317   const auto* filter_chain = FindFilterChainDataForDestinationIp(
318       filter_chain_map_.destination_ip_vector, tcp);
319   if (filter_chain == nullptr && default_filter_chain_.has_value()) {
320     filter_chain = &default_filter_chain_.value();
321   }
322   if (filter_chain == nullptr) {
323     grpc_channel_args_destroy(args);
324     return absl::UnavailableError("No matching filter chain found");
325   }
326   // Nothing to update if credentials are not xDS.
327   grpc_server_credentials* server_creds =
328       grpc_find_server_credentials_in_args(args);
329   if (server_creds == nullptr || server_creds->type() != kCredentialsTypeXds) {
330     return args;
331   }
332   absl::StatusOr<RefCountedPtr<XdsCertificateProvider>> result =
333       CreateOrGetXdsCertificateProviderFromFilterChainData(filter_chain);
334   if (!result.ok()) {
335     grpc_channel_args_destroy(args);
336     return result.status();
337   }
338   RefCountedPtr<XdsCertificateProvider> xds_certificate_provider =
339       std::move(*result);
340   GPR_ASSERT(xds_certificate_provider != nullptr);
341   grpc_arg arg_to_add = xds_certificate_provider->MakeChannelArg();
342   grpc_channel_args* updated_args =
343       grpc_channel_args_copy_and_add(args, &arg_to_add, 1);
344   grpc_channel_args_destroy(args);
345   return updated_args;
346 }
347 
348 class XdsServerConfigFetcher : public grpc_server_config_fetcher {
349  public:
XdsServerConfigFetcher(RefCountedPtr<XdsClient> xds_client,grpc_server_xds_status_notifier notifier)350   explicit XdsServerConfigFetcher(RefCountedPtr<XdsClient> xds_client,
351                                   grpc_server_xds_status_notifier notifier)
352       : xds_client_(std::move(xds_client)), serving_status_notifier_(notifier) {
353     GPR_ASSERT(xds_client_ != nullptr);
354   }
355 
StartWatch(std::string listening_address,grpc_channel_args * args,std::unique_ptr<grpc_server_config_fetcher::WatcherInterface> watcher)356   void StartWatch(std::string listening_address, grpc_channel_args* args,
357                   std::unique_ptr<grpc_server_config_fetcher::WatcherInterface>
358                       watcher) override {
359     grpc_server_config_fetcher::WatcherInterface* watcher_ptr = watcher.get();
360     auto listener_watcher = absl::make_unique<ListenerWatcher>(
361         std::move(watcher), args, xds_client_, serving_status_notifier_,
362         listening_address);
363     auto* listener_watcher_ptr = listener_watcher.get();
364     listening_address = absl::StrReplaceAll(
365         xds_client_->bootstrap().server_listener_resource_name_template(),
366         {{"%s", listening_address}});
367     xds_client_->WatchListenerData(listening_address,
368                                    std::move(listener_watcher));
369     MutexLock lock(&mu_);
370     auto& watcher_state = watchers_[watcher_ptr];
371     watcher_state.listening_address = listening_address;
372     watcher_state.listener_watcher = listener_watcher_ptr;
373   }
374 
CancelWatch(grpc_server_config_fetcher::WatcherInterface * watcher)375   void CancelWatch(
376       grpc_server_config_fetcher::WatcherInterface* watcher) override {
377     MutexLock lock(&mu_);
378     auto it = watchers_.find(watcher);
379     if (it != watchers_.end()) {
380       // Cancel the watch on the listener before erasing
381       xds_client_->CancelListenerDataWatch(it->second.listening_address,
382                                            it->second.listener_watcher,
383                                            false /* delay_unsubscription */);
384       watchers_.erase(it);
385     }
386   }
387 
388   // Return the interested parties from the xds client so that it can be polled.
interested_parties()389   grpc_pollset_set* interested_parties() override {
390     return xds_client_->interested_parties();
391   }
392 
393  private:
394   class ListenerWatcher : public XdsClient::ListenerWatcherInterface {
395    public:
ListenerWatcher(std::unique_ptr<grpc_server_config_fetcher::WatcherInterface> server_config_watcher,grpc_channel_args * args,RefCountedPtr<XdsClient> xds_client,grpc_server_xds_status_notifier serving_status_notifier,std::string listening_address)396     explicit ListenerWatcher(
397         std::unique_ptr<grpc_server_config_fetcher::WatcherInterface>
398             server_config_watcher,
399         grpc_channel_args* args, RefCountedPtr<XdsClient> xds_client,
400         grpc_server_xds_status_notifier serving_status_notifier,
401         std::string listening_address)
402         : server_config_watcher_(std::move(server_config_watcher)),
403           args_(args),
404           xds_client_(std::move(xds_client)),
405           serving_status_notifier_(serving_status_notifier),
406           listening_address_(std::move(listening_address)) {}
407 
~ListenerWatcher()408     ~ListenerWatcher() override { grpc_channel_args_destroy(args_); }
409 
410     // Deleted due to special handling required for args_. Copy the channel args
411     // if we ever need these.
412     ListenerWatcher(const ListenerWatcher&) = delete;
413     ListenerWatcher& operator=(const ListenerWatcher&) = delete;
414 
OnListenerChanged(XdsApi::LdsUpdate listener)415     void OnListenerChanged(XdsApi::LdsUpdate listener) override {
416       if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_server_config_fetcher_trace)) {
417         gpr_log(
418             GPR_INFO,
419             "[ListenerWatcher %p] Received LDS update from xds client %p: %s",
420             this, xds_client_.get(), listener.ToString().c_str());
421       }
422       if (listener.address != listening_address_) {
423         OnFatalError(absl::FailedPreconditionError(
424             "Address in LDS update does not match listening address"));
425         return;
426       }
427       if (filter_chain_match_manager_ == nullptr) {
428         if (serving_status_notifier_.on_serving_status_update != nullptr) {
429           serving_status_notifier_.on_serving_status_update(
430               serving_status_notifier_.user_data, listening_address_.c_str(),
431               GRPC_STATUS_OK, "");
432         } else {
433           gpr_log(GPR_INFO,
434                   "xDS Listener resource obtained; will start serving on %s",
435                   listening_address_.c_str());
436         }
437       }
438       if (filter_chain_match_manager_ == nullptr ||
439           !(listener.filter_chain_map ==
440                 filter_chain_match_manager_->filter_chain_map() &&
441             listener.default_filter_chain ==
442                 filter_chain_match_manager_->default_filter_chain())) {
443         filter_chain_match_manager_ = MakeRefCounted<FilterChainMatchManager>(
444             xds_client_, std::move(listener.filter_chain_map),
445             std::move(listener.default_filter_chain));
446         server_config_watcher_->UpdateConnectionManager(
447             filter_chain_match_manager_);
448       }
449     }
450 
OnError(grpc_error_handle error)451     void OnError(grpc_error_handle error) override {
452       if (filter_chain_match_manager_ != nullptr) {
453         gpr_log(GPR_ERROR,
454                 "ListenerWatcher:%p XdsClient reports error: %s for %s; "
455                 "ignoring in favor of existing resource",
456                 this, grpc_error_std_string(error).c_str(),
457                 listening_address_.c_str());
458       } else {
459         if (serving_status_notifier_.on_serving_status_update != nullptr) {
460           serving_status_notifier_.on_serving_status_update(
461               serving_status_notifier_.user_data, listening_address_.c_str(),
462               GRPC_STATUS_UNAVAILABLE, grpc_error_std_string(error).c_str());
463         } else {
464           gpr_log(
465               GPR_ERROR,
466               "ListenerWatcher:%p error obtaining xDS Listener resource: %s; "
467               "not serving on %s",
468               this, grpc_error_std_string(error).c_str(),
469               listening_address_.c_str());
470         }
471       }
472       GRPC_ERROR_UNREF(error);
473     }
474 
OnFatalError(absl::Status status)475     void OnFatalError(absl::Status status) {
476       gpr_log(
477           GPR_ERROR,
478           "ListenerWatcher:%p Encountered fatal error %s; not serving on %s",
479           this, status.ToString().c_str(), listening_address_.c_str());
480       if (filter_chain_match_manager_ != nullptr) {
481         // The server has started listening already, so we need to gracefully
482         // stop serving.
483         server_config_watcher_->StopServing();
484         filter_chain_match_manager_.reset();
485       }
486       if (serving_status_notifier_.on_serving_status_update != nullptr) {
487         serving_status_notifier_.on_serving_status_update(
488             serving_status_notifier_.user_data, listening_address_.c_str(),
489             static_cast<grpc_status_code>(status.raw_code()),
490             std::string(status.message()).c_str());
491       }
492     }
493 
OnResourceDoesNotExist()494     void OnResourceDoesNotExist() override {
495       OnFatalError(absl::NotFoundError("Requested listener does not exist"));
496     }
497 
498    private:
499     std::unique_ptr<grpc_server_config_fetcher::WatcherInterface>
500         server_config_watcher_;
501     grpc_channel_args* args_;
502     RefCountedPtr<XdsClient> xds_client_;
503     grpc_server_xds_status_notifier serving_status_notifier_;
504     std::string listening_address_;
505     RefCountedPtr<FilterChainMatchManager> filter_chain_match_manager_;
506   };
507 
508   struct WatcherState {
509     std::string listening_address;
510     ListenerWatcher* listener_watcher = nullptr;
511   };
512 
513   RefCountedPtr<XdsClient> xds_client_;
514   grpc_server_xds_status_notifier serving_status_notifier_;
515   Mutex mu_;
516   std::map<grpc_server_config_fetcher::WatcherInterface*, WatcherState>
517       watchers_ ABSL_GUARDED_BY(mu_);
518 };
519 
520 }  // namespace
521 }  // namespace grpc_core
522 
grpc_server_config_fetcher_xds_create(grpc_server_xds_status_notifier notifier,const grpc_channel_args * args)523 grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create(
524     grpc_server_xds_status_notifier notifier, const grpc_channel_args* args) {
525   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
526   grpc_core::ExecCtx exec_ctx;
527   GRPC_API_TRACE("grpc_server_config_fetcher_xds_create()", 0, ());
528   grpc_error_handle error = GRPC_ERROR_NONE;
529   grpc_core::RefCountedPtr<grpc_core::XdsClient> xds_client =
530       grpc_core::XdsClient::GetOrCreate(args, &error);
531   if (error != GRPC_ERROR_NONE) {
532     gpr_log(GPR_ERROR, "Failed to create xds client: %s",
533             grpc_error_std_string(error).c_str());
534     GRPC_ERROR_UNREF(error);
535     return nullptr;
536   }
537   if (xds_client->bootstrap()
538           .server_listener_resource_name_template()
539           .empty()) {
540     gpr_log(GPR_ERROR,
541             "server_listener_resource_name_template not provided in bootstrap "
542             "file.");
543     return nullptr;
544   }
545   return new grpc_core::XdsServerConfigFetcher(std::move(xds_client), notifier);
546 }
547