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