xref: /aosp_15_r20/external/grpc-grpc/src/core/resolver/xds/xds_dependency_manager.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 #ifndef GRPC_SRC_CORE_RESOLVER_XDS_XDS_DEPENDENCY_MANAGER_H
18 #define GRPC_SRC_CORE_RESOLVER_XDS_XDS_DEPENDENCY_MANAGER_H
19 
20 #include <grpc/support/port_platform.h>
21 
22 #include "absl/container/flat_hash_map.h"
23 #include "absl/container/flat_hash_set.h"
24 #include "absl/strings/string_view.h"
25 
26 #include "src/core/ext/xds/xds_client_grpc.h"
27 #include "src/core/ext/xds/xds_cluster.h"
28 #include "src/core/ext/xds/xds_endpoint.h"
29 #include "src/core/ext/xds/xds_listener.h"
30 #include "src/core/ext/xds/xds_route_config.h"
31 #include "src/core/lib/gprpp/ref_counted.h"
32 #include "src/core/resolver/resolver.h"
33 
34 namespace grpc_core {
35 
36 // Watches all xDS resources and handles dependencies between them.
37 // Reports updates only when all necessary resources have been obtained.
38 class XdsDependencyManager final : public RefCounted<XdsDependencyManager>,
39                                    public Orphanable {
40  public:
41   struct XdsConfig : public RefCounted<XdsConfig> {
42     // Listener resource.  Always non-null.
43     std::shared_ptr<const XdsListenerResource> listener;
44     // RouteConfig resource.  Will be populated even if RouteConfig is
45     // inlined into the Listener resource.
46     std::shared_ptr<const XdsRouteConfigResource> route_config;
47     // Virtual host.  Points into route_config.  Will always be non-null.
48     const XdsRouteConfigResource::VirtualHost* virtual_host;
49 
50     struct ClusterConfig {
51       // Cluster resource.  Always non-null.
52       std::shared_ptr<const XdsClusterResource> cluster;
53       // Endpoint info for EDS and LOGICAL_DNS clusters.  If there was an
54       // error, endpoints will be null and resolution_note will be set.
55       struct EndpointConfig {
56         std::shared_ptr<const XdsEndpointResource> endpoints;
57         std::string resolution_note;
58 
EndpointConfigXdsConfig::ClusterConfig::EndpointConfig59         EndpointConfig(std::shared_ptr<const XdsEndpointResource> endpoints,
60                        std::string resolution_note)
61             : endpoints(std::move(endpoints)),
62               resolution_note(std::move(resolution_note)) {}
63         bool operator==(const EndpointConfig& other) const {
64           return endpoints == other.endpoints &&
65                  resolution_note == other.resolution_note;
66         }
67       };
68       // The list of leaf clusters for an aggregate cluster.
69       struct AggregateConfig {
70         std::vector<absl::string_view> leaf_clusters;
71 
AggregateConfigXdsConfig::ClusterConfig::AggregateConfig72         explicit AggregateConfig(std::vector<absl::string_view> leaf_clusters)
73             : leaf_clusters(std::move(leaf_clusters)) {}
74         bool operator==(const AggregateConfig& other) const {
75           return leaf_clusters == other.leaf_clusters;
76         }
77       };
78       absl::variant<EndpointConfig, AggregateConfig> children;
79 
80       // Ctor for leaf clusters.
81       ClusterConfig(std::shared_ptr<const XdsClusterResource> cluster,
82                     std::shared_ptr<const XdsEndpointResource> endpoints,
83                     std::string resolution_note);
84       // Ctor for aggregate clusters.
85       ClusterConfig(std::shared_ptr<const XdsClusterResource> cluster,
86                     std::vector<absl::string_view> leaf_clusters);
87 
88       bool operator==(const ClusterConfig& other) const {
89         return cluster == other.cluster && children == other.children;
90       }
91     };
92     // Cluster map.  A cluster will have a non-OK status if either
93     // (a) there was an error and we did not already have a valid
94     // resource or (b) the resource does not exist.
95     absl::flat_hash_map<std::string, absl::StatusOr<ClusterConfig>> clusters;
96 
97     std::string ToString() const;
98 
ChannelArgNameXdsConfig99     static absl::string_view ChannelArgName() {
100       return GRPC_ARG_NO_SUBCHANNEL_PREFIX "xds_config";
101     }
ChannelArgsCompareXdsConfig102     static int ChannelArgsCompare(const XdsConfig* a, const XdsConfig* b) {
103       return QsortCompare(a, b);
104     }
ChannelArgUseConstPtrXdsConfig105     static constexpr bool ChannelArgUseConstPtr() { return true; }
106   };
107 
108   class Watcher {
109    public:
110     virtual ~Watcher() = default;
111 
112     virtual void OnUpdate(RefCountedPtr<const XdsConfig> config) = 0;
113 
114     // These methods are invoked when there is an error or
115     // does-not-exist on LDS or RDS only.
116     virtual void OnError(absl::string_view context, absl::Status status) = 0;
117     virtual void OnResourceDoesNotExist(std::string context) = 0;
118   };
119 
120   class ClusterSubscription final : public DualRefCounted<ClusterSubscription> {
121    public:
ClusterSubscription(absl::string_view cluster_name,RefCountedPtr<XdsDependencyManager> dependency_mgr)122     ClusterSubscription(absl::string_view cluster_name,
123                         RefCountedPtr<XdsDependencyManager> dependency_mgr)
124         : cluster_name_(cluster_name),
125           dependency_mgr_(std::move(dependency_mgr)) {}
126 
cluster_name()127     absl::string_view cluster_name() const { return cluster_name_; }
128 
129    private:
130     void Orphaned() override;
131 
132     std::string cluster_name_;
133     RefCountedPtr<XdsDependencyManager> dependency_mgr_;
134   };
135 
136   XdsDependencyManager(RefCountedPtr<GrpcXdsClient> xds_client,
137                        std::shared_ptr<WorkSerializer> work_serializer,
138                        std::unique_ptr<Watcher> watcher,
139                        std::string data_plane_authority,
140                        std::string listener_resource_name, ChannelArgs args,
141                        grpc_pollset_set* interested_parties);
142 
143   void Orphan() override;
144 
145   // Gets an external cluster subscription.  This allows us to include
146   // clusters in the config that are referenced by something other than
147   // the route config (e.g., RLS).  The cluster will be included in the
148   // config as long as the returned object is still referenced.
149   RefCountedPtr<ClusterSubscription> GetClusterSubscription(
150       absl::string_view cluster_name);
151 
ChannelArgName()152   static absl::string_view ChannelArgName() {
153     return GRPC_ARG_NO_SUBCHANNEL_PREFIX "xds_dependency_manager";
154   }
ChannelArgsCompare(const XdsDependencyManager * a,const XdsDependencyManager * b)155   static int ChannelArgsCompare(const XdsDependencyManager* a,
156                                 const XdsDependencyManager* b) {
157     return QsortCompare(a, b);
158   }
159 
160  private:
161   class ListenerWatcher;
162   class RouteConfigWatcher;
163   class ClusterWatcher;
164   class EndpointWatcher;
165 
166   class DnsResultHandler;
167 
168   struct ClusterWatcherState {
169     // Pointer to watcher, to be used when cancelling.
170     // Not owned, so do not dereference.
171     ClusterWatcher* watcher = nullptr;
172     // Most recent update obtained from this watcher.
173     absl::StatusOr<std::shared_ptr<const XdsClusterResource>> update = nullptr;
174   };
175 
176   struct EndpointConfig {
177     // If there was an error, update will be null and resolution_note
178     // will be non-empty.
179     std::shared_ptr<const XdsEndpointResource> endpoints;
180     std::string resolution_note;
181   };
182 
183   struct EndpointWatcherState {
184     // Pointer to watcher, to be used when cancelling.
185     // Not owned, so do not dereference.
186     EndpointWatcher* watcher = nullptr;
187     // Most recent update obtained from this watcher.
188     EndpointConfig update;
189   };
190 
191   struct DnsState {
192     OrphanablePtr<Resolver> resolver;
193     // Most recent result from the resolver.
194     EndpointConfig update;
195   };
196 
197   // Event handlers.
198   void OnListenerUpdate(std::shared_ptr<const XdsListenerResource> listener);
199   void OnRouteConfigUpdate(
200       const std::string& name,
201       std::shared_ptr<const XdsRouteConfigResource> route_config);
202   void OnError(std::string context, absl::Status status);
203   void OnResourceDoesNotExist(std::string context);
204 
205   void OnClusterUpdate(const std::string& name,
206                        std::shared_ptr<const XdsClusterResource> cluster);
207   void OnClusterError(const std::string& name, absl::Status status);
208   void OnClusterDoesNotExist(const std::string& name);
209 
210   void OnEndpointUpdate(const std::string& name,
211                         std::shared_ptr<const XdsEndpointResource> endpoint);
212   void OnEndpointError(const std::string& name, absl::Status status);
213   void OnEndpointDoesNotExist(const std::string& name);
214 
215   void OnDnsResult(const std::string& dns_name, Resolver::Result result);
216   void PopulateDnsUpdate(const std::string& dns_name, Resolver::Result result,
217                          DnsState* dns_state);
218 
219   // Starts CDS and EDS/DNS watches for the specified cluster if needed.
220   // Adds an entry to cluster_config_map, which will contain the cluster
221   // data if the data is available.
222   // For each EDS cluster, adds the EDS resource to eds_resources_seen.
223   // For each Logical DNS cluster, adds the DNS hostname to dns_names_seen.
224   // For aggregate clusters, calls itself recursively.  If leaf_clusters is
225   // non-null, populates it with a list of leaf clusters, or an error if
226   // max depth is exceeded.
227   // Returns true if all resources have been obtained.
228   bool PopulateClusterConfigMap(
229       absl::string_view name, int depth,
230       absl::flat_hash_map<std::string,
231                           absl::StatusOr<XdsConfig::ClusterConfig>>*
232           cluster_config_map,
233       std::set<absl::string_view>* eds_resources_seen,
234       std::set<absl::string_view>* dns_names_seen,
235       absl::StatusOr<std::vector<absl::string_view>>* leaf_clusters = nullptr);
236 
237   // Called when an external cluster subscription is unreffed.
238   void OnClusterSubscriptionUnref(absl::string_view cluster_name,
239                                   ClusterSubscription* subscription);
240 
241   // Checks whether all necessary resources have been obtained, and if
242   // so reports an update to the watcher.
243   void MaybeReportUpdate();
244 
245   // Parameters passed into ctor.
246   RefCountedPtr<GrpcXdsClient> xds_client_;
247   std::shared_ptr<WorkSerializer> work_serializer_;
248   std::unique_ptr<Watcher> watcher_;
249   const std::string data_plane_authority_;
250   const std::string listener_resource_name_;
251   ChannelArgs args_;
252   grpc_pollset_set* interested_parties_;
253 
254   // Listener state.
255   ListenerWatcher* listener_watcher_ = nullptr;
256   std::shared_ptr<const XdsListenerResource> current_listener_;
257   std::string route_config_name_;
258 
259   // RouteConfig state.
260   RouteConfigWatcher* route_config_watcher_ = nullptr;
261   std::shared_ptr<const XdsRouteConfigResource> current_route_config_;
262   const XdsRouteConfigResource::VirtualHost* current_virtual_host_ = nullptr;
263   absl::flat_hash_set<absl::string_view> clusters_from_route_config_;
264 
265   // Cluster state.
266   absl::flat_hash_map<std::string, ClusterWatcherState> cluster_watchers_;
267   absl::flat_hash_map<absl::string_view, WeakRefCountedPtr<ClusterSubscription>>
268       cluster_subscriptions_;
269 
270   // Endpoint state.
271   absl::flat_hash_map<std::string, EndpointWatcherState> endpoint_watchers_;
272   absl::flat_hash_map<std::string, DnsState> dns_resolvers_;
273 };
274 
275 }  // namespace grpc_core
276 
277 #endif  // GRPC_SRC_CORE_RESOLVER_XDS_XDS_DEPENDENCY_MANAGER_H
278