1 /* 2 * 3 * Copyright 2018 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #ifndef GRPC_CORE_EXT_XDS_XDS_API_H 20 #define GRPC_CORE_EXT_XDS_XDS_API_H 21 22 #include <grpc/support/port_platform.h> 23 24 #include <stdint.h> 25 26 #include <set> 27 28 #include "absl/container/inlined_vector.h" 29 #include "absl/types/optional.h" 30 #include "re2/re2.h" 31 32 #include "upb/def.hpp" 33 34 #include <grpc/slice_buffer.h> 35 36 #include "src/core/ext/filters/client_channel/server_address.h" 37 #include "src/core/ext/xds/xds_bootstrap.h" 38 #include "src/core/ext/xds/xds_client_stats.h" 39 #include "src/core/lib/security/authorization/matchers.h" 40 41 namespace grpc_core { 42 43 // TODO(yashykt): Check to see if xDS security is enabled. This will be 44 // removed once this feature is fully integration-tested and enabled by 45 // default. 46 bool XdsSecurityEnabled(); 47 48 class XdsClient; 49 50 class XdsApi { 51 public: 52 static const char* kLdsTypeUrl; 53 static const char* kRdsTypeUrl; 54 static const char* kCdsTypeUrl; 55 static const char* kEdsTypeUrl; 56 57 struct Duration { 58 int64_t seconds = 0; 59 int32_t nanos = 0; 60 bool operator==(const Duration& other) const { 61 return (seconds == other.seconds && nanos == other.nanos); 62 } ToStringDuration63 std::string ToString() const { 64 return absl::StrFormat("Duration seconds: %ld, nanos %d", seconds, nanos); 65 } 66 }; 67 68 // TODO(donnadionne): When we can use absl::variant<>, consider using that 69 // for: PathMatcher, HeaderMatcher, cluster_name and weighted_clusters 70 struct Route { 71 // Matchers for this route. 72 struct Matchers { 73 StringMatcher path_matcher; 74 std::vector<HeaderMatcher> header_matchers; 75 absl::optional<uint32_t> fraction_per_million; 76 77 bool operator==(const Matchers& other) const { 78 return (path_matcher == other.path_matcher && 79 header_matchers == other.header_matchers && 80 fraction_per_million == other.fraction_per_million); 81 } 82 std::string ToString() const; 83 }; 84 85 Matchers matchers; 86 87 // Action for this route. 88 // TODO(roth): When we can use absl::variant<>, consider using that 89 // here, to enforce the fact that only one of the two fields can be set. 90 std::string cluster_name; 91 struct ClusterWeight { 92 std::string name; 93 uint32_t weight; 94 bool operator==(const ClusterWeight& other) const { 95 return (name == other.name && weight == other.weight); 96 } 97 std::string ToString() const; 98 }; 99 std::vector<ClusterWeight> weighted_clusters; 100 // Storing the timeout duration from route action: 101 // RouteAction.max_stream_duration.grpc_timeout_header_max or 102 // RouteAction.max_stream_duration.max_stream_duration if the former is 103 // not set. 104 absl::optional<Duration> max_stream_duration; 105 106 bool operator==(const Route& other) const { 107 return (matchers == other.matchers && 108 cluster_name == other.cluster_name && 109 weighted_clusters == other.weighted_clusters && 110 max_stream_duration == other.max_stream_duration); 111 } 112 std::string ToString() const; 113 }; 114 115 struct RdsUpdate { 116 struct VirtualHost { 117 std::vector<std::string> domains; 118 std::vector<Route> routes; 119 120 bool operator==(const VirtualHost& other) const { 121 return domains == other.domains && routes == other.routes; 122 } 123 }; 124 125 std::vector<VirtualHost> virtual_hosts; 126 127 bool operator==(const RdsUpdate& other) const { 128 return virtual_hosts == other.virtual_hosts; 129 } 130 std::string ToString() const; 131 VirtualHost* FindVirtualHostForDomain(const std::string& domain); 132 }; 133 134 struct CommonTlsContext { 135 struct CertificateValidationContext { 136 std::vector<StringMatcher> match_subject_alt_names; 137 138 bool operator==(const CertificateValidationContext& other) const { 139 return match_subject_alt_names == other.match_subject_alt_names; 140 } 141 142 std::string ToString() const; 143 bool Empty() const; 144 }; 145 146 struct CertificateProviderInstance { 147 std::string instance_name; 148 std::string certificate_name; 149 150 bool operator==(const CertificateProviderInstance& other) const { 151 return instance_name == other.instance_name && 152 certificate_name == other.certificate_name; 153 } 154 155 std::string ToString() const; 156 bool Empty() const; 157 }; 158 159 struct CombinedCertificateValidationContext { 160 CertificateValidationContext default_validation_context; 161 CertificateProviderInstance 162 validation_context_certificate_provider_instance; 163 164 bool operator==(const CombinedCertificateValidationContext& other) const { 165 return default_validation_context == other.default_validation_context && 166 validation_context_certificate_provider_instance == 167 other.validation_context_certificate_provider_instance; 168 } 169 170 std::string ToString() const; 171 bool Empty() const; 172 }; 173 174 CertificateProviderInstance tls_certificate_certificate_provider_instance; 175 CombinedCertificateValidationContext combined_validation_context; 176 177 bool operator==(const CommonTlsContext& other) const { 178 return tls_certificate_certificate_provider_instance == 179 other.tls_certificate_certificate_provider_instance && 180 combined_validation_context == other.combined_validation_context; 181 } 182 183 std::string ToString() const; 184 bool Empty() const; 185 }; 186 187 struct DownstreamTlsContext { 188 CommonTlsContext common_tls_context; 189 bool require_client_certificate = false; 190 191 bool operator==(const DownstreamTlsContext& other) const { 192 return common_tls_context == other.common_tls_context && 193 require_client_certificate == other.require_client_certificate; 194 } 195 196 std::string ToString() const; 197 bool Empty() const; 198 }; 199 200 // TODO(roth): When we can use absl::variant<>, consider using that 201 // here, to enforce the fact that only one of the two fields can be set. 202 struct LdsUpdate { 203 enum class ListenerType { 204 kTcpListener = 0, 205 kHttpApiListener, 206 } type; 207 DownstreamTlsContext downstream_tls_context; 208 // The name to use in the RDS request. 209 std::string route_config_name; 210 // Storing the Http Connection Manager Common Http Protocol Option 211 // max_stream_duration 212 Duration http_max_stream_duration; 213 // The RouteConfiguration to use for this listener. 214 // Present only if it is inlined in the LDS response. 215 absl::optional<RdsUpdate> rds_update; 216 217 bool operator==(const LdsUpdate& other) const { 218 return downstream_tls_context == other.downstream_tls_context && 219 route_config_name == other.route_config_name && 220 rds_update == other.rds_update && 221 http_max_stream_duration == other.http_max_stream_duration; 222 } 223 224 std::string ToString() const; 225 }; 226 227 using LdsUpdateMap = std::map<std::string /*server_name*/, LdsUpdate>; 228 229 using RdsUpdateMap = std::map<std::string /*route_config_name*/, RdsUpdate>; 230 231 struct CdsUpdate { 232 enum ClusterType { EDS, LOGICAL_DNS, AGGREGATE }; 233 ClusterType cluster_type; 234 // For cluster type EDS. 235 // The name to use in the EDS request. 236 // If empty, the cluster name will be used. 237 std::string eds_service_name; 238 // Tls Context used by clients 239 CommonTlsContext common_tls_context; 240 // The LRS server to use for load reporting. 241 // If not set, load reporting will be disabled. 242 // If set to the empty string, will use the same server we obtained the CDS 243 // data from. 244 absl::optional<std::string> lrs_load_reporting_server_name; 245 // The LB policy to use (e.g., "ROUND_ROBIN" or "RING_HASH"). 246 std::string lb_policy; 247 // Used for RING_HASH LB policy only. 248 uint64_t min_ring_size = 1024; 249 uint64_t max_ring_size = 8388608; 250 enum HashFunction { XX_HASH, MURMUR_HASH_2 }; 251 HashFunction hash_function; 252 // Maximum number of outstanding requests can be made to the upstream 253 // cluster. 254 uint32_t max_concurrent_requests = 1024; 255 // For cluster type AGGREGATE. 256 // The prioritized list of cluster names. 257 std::vector<std::string> prioritized_cluster_names; 258 259 bool operator==(const CdsUpdate& other) const { 260 return cluster_type == other.cluster_type && 261 eds_service_name == other.eds_service_name && 262 common_tls_context == other.common_tls_context && 263 lrs_load_reporting_server_name == 264 other.lrs_load_reporting_server_name && 265 prioritized_cluster_names == other.prioritized_cluster_names && 266 max_concurrent_requests == other.max_concurrent_requests; 267 } 268 269 std::string ToString() const; 270 }; 271 272 using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsUpdate>; 273 274 struct EdsUpdate { 275 struct Priority { 276 struct Locality { 277 RefCountedPtr<XdsLocalityName> name; 278 uint32_t lb_weight; 279 ServerAddressList endpoints; 280 281 bool operator==(const Locality& other) const { 282 return *name == *other.name && lb_weight == other.lb_weight && 283 endpoints == other.endpoints; 284 } 285 bool operator!=(const Locality& other) const { 286 return !(*this == other); 287 } 288 std::string ToString() const; 289 }; 290 291 std::map<XdsLocalityName*, Locality, XdsLocalityName::Less> localities; 292 293 bool operator==(const Priority& other) const; 294 std::string ToString() const; 295 }; 296 using PriorityList = absl::InlinedVector<Priority, 2>; 297 298 // There are two phases of accessing this class's content: 299 // 1. to initialize in the control plane combiner; 300 // 2. to use in the data plane combiner. 301 // So no additional synchronization is needed. 302 class DropConfig : public RefCounted<DropConfig> { 303 public: 304 struct DropCategory { 305 bool operator==(const DropCategory& other) const { 306 return name == other.name && 307 parts_per_million == other.parts_per_million; 308 } 309 310 std::string name; 311 const uint32_t parts_per_million; 312 }; 313 314 using DropCategoryList = absl::InlinedVector<DropCategory, 2>; 315 AddCategoryEdsUpdate316 void AddCategory(std::string name, uint32_t parts_per_million) { 317 drop_category_list_.emplace_back( 318 DropCategory{std::move(name), parts_per_million}); 319 if (parts_per_million == 1000000) drop_all_ = true; 320 } 321 322 // The only method invoked from outside the WorkSerializer (used in 323 // the data plane). 324 bool ShouldDrop(const std::string** category_name) const; 325 drop_category_listEdsUpdate326 const DropCategoryList& drop_category_list() const { 327 return drop_category_list_; 328 } 329 drop_allEdsUpdate330 bool drop_all() const { return drop_all_; } 331 332 bool operator==(const DropConfig& other) const { 333 return drop_category_list_ == other.drop_category_list_; 334 } 335 bool operator!=(const DropConfig& other) const { 336 return !(*this == other); 337 } 338 339 std::string ToString() const; 340 341 private: 342 DropCategoryList drop_category_list_; 343 bool drop_all_ = false; 344 }; 345 346 PriorityList priorities; 347 RefCountedPtr<DropConfig> drop_config; 348 349 bool operator==(const EdsUpdate& other) const { 350 return priorities == other.priorities && 351 *drop_config == *other.drop_config; 352 } 353 std::string ToString() const; 354 }; 355 356 using EdsUpdateMap = std::map<std::string /*eds_service_name*/, EdsUpdate>; 357 358 struct ClusterLoadReport { 359 XdsClusterDropStats::Snapshot dropped_requests; 360 std::map<RefCountedPtr<XdsLocalityName>, XdsClusterLocalityStats::Snapshot, 361 XdsLocalityName::Less> 362 locality_stats; 363 grpc_millis load_report_interval; 364 }; 365 using ClusterLoadReportMap = std::map< 366 std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>, 367 ClusterLoadReport>; 368 369 XdsApi(XdsClient* client, TraceFlag* tracer, const XdsBootstrap::Node* node); 370 371 // Creates an ADS request. 372 // Takes ownership of \a error. 373 grpc_slice CreateAdsRequest(const XdsBootstrap::XdsServer& server, 374 const std::string& type_url, 375 const std::set<absl::string_view>& resource_names, 376 const std::string& version, 377 const std::string& nonce, grpc_error* error, 378 bool populate_node); 379 380 // Parses an ADS response. 381 // If the response can't be parsed at the top level, the resulting 382 // type_url will be empty. 383 // If there is any other type of validation error, the parse_error 384 // field will be set to something other than GRPC_ERROR_NONE and the 385 // resource_names_failed field will be populated. 386 // Otherwise, one of the *_update_map fields will be populated, based 387 // on the type_url field. 388 struct AdsParseResult { 389 grpc_error* parse_error = GRPC_ERROR_NONE; 390 std::string version; 391 std::string nonce; 392 std::string type_url; 393 LdsUpdateMap lds_update_map; 394 RdsUpdateMap rds_update_map; 395 CdsUpdateMap cds_update_map; 396 EdsUpdateMap eds_update_map; 397 std::set<std::string> resource_names_failed; 398 }; 399 AdsParseResult ParseAdsResponse( 400 const grpc_slice& encoded_response, 401 const std::set<absl::string_view>& expected_listener_names, 402 const std::set<absl::string_view>& expected_route_configuration_names, 403 const std::set<absl::string_view>& expected_cluster_names, 404 const std::set<absl::string_view>& expected_eds_service_names); 405 406 // Creates an initial LRS request. 407 grpc_slice CreateLrsInitialRequest(const XdsBootstrap::XdsServer& server); 408 409 // Creates an LRS request sending a client-side load report. 410 grpc_slice CreateLrsRequest(ClusterLoadReportMap cluster_load_report_map); 411 412 // Parses the LRS response and returns \a 413 // load_reporting_interval for client-side load reporting. If there is any 414 // error, the output config is invalid. 415 grpc_error* ParseLrsResponse(const grpc_slice& encoded_response, 416 bool* send_all_clusters, 417 std::set<std::string>* cluster_names, 418 grpc_millis* load_reporting_interval); 419 420 private: 421 XdsClient* client_; 422 TraceFlag* tracer_; 423 const XdsBootstrap::Node* node_; // Do not own. 424 upb::SymbolTable symtab_; 425 const std::string build_version_; 426 const std::string user_agent_name_; 427 }; 428 429 } // namespace grpc_core 430 431 #endif /* GRPC_CORE_EXT_XDS_XDS_API_H */ 432