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 40 namespace grpc_core { 41 42 // TODO(yashykt): Check to see if xDS security is enabled. This will be 43 // removed once this feature is fully integration-tested and enabled by 44 // default. 45 bool XdsSecurityEnabled(); 46 47 class XdsClient; 48 49 class XdsApi { 50 public: 51 static const char* kLdsTypeUrl; 52 static const char* kRdsTypeUrl; 53 static const char* kCdsTypeUrl; 54 static const char* kEdsTypeUrl; 55 56 struct Duration { 57 int64_t seconds = 0; 58 int32_t nanos = 0; 59 bool operator==(const Duration& other) const { 60 return (seconds == other.seconds && nanos == other.nanos); 61 } ToStringDuration62 std::string ToString() const { 63 return absl::StrFormat("Duration seconds: %ld, nanos %d", seconds, nanos); 64 } 65 }; 66 67 // TODO(donnadionne): When we can use absl::variant<>, consider using that 68 // for: PathMatcher, HeaderMatcher, cluster_name and weighted_clusters 69 struct Route { 70 // Matchers for this route. 71 struct Matchers { 72 struct PathMatcher { 73 enum class PathMatcherType { 74 PATH, // path stored in string_matcher field 75 PREFIX, // prefix stored in string_matcher field 76 REGEX, // regex stored in regex_matcher field 77 }; 78 PathMatcherType type; 79 std::string string_matcher; 80 std::unique_ptr<RE2> regex_matcher; 81 bool case_sensitive = true; 82 83 PathMatcher() = default; 84 PathMatcher(const PathMatcher& other); 85 PathMatcher& operator=(const PathMatcher& other); 86 bool operator==(const PathMatcher& other) const; 87 std::string ToString() const; 88 }; 89 90 struct HeaderMatcher { 91 enum class HeaderMatcherType { 92 EXACT, // value stored in string_matcher field 93 REGEX, // uses regex_match field 94 RANGE, // uses range_start and range_end fields 95 PRESENT, // uses present_match field 96 PREFIX, // prefix stored in string_matcher field 97 SUFFIX, // suffix stored in string_matcher field 98 }; 99 std::string name; 100 HeaderMatcherType type; 101 int64_t range_start; 102 int64_t range_end; 103 std::string string_matcher; 104 std::unique_ptr<RE2> regex_match; 105 bool present_match; 106 // invert_match field may or may not exisit, so initialize it to 107 // false. 108 bool invert_match = false; 109 110 HeaderMatcher() = default; 111 HeaderMatcher(const HeaderMatcher& other); 112 HeaderMatcher& operator=(const HeaderMatcher& other); 113 bool operator==(const HeaderMatcher& other) const; 114 std::string ToString() const; 115 }; 116 117 PathMatcher path_matcher; 118 std::vector<HeaderMatcher> header_matchers; 119 absl::optional<uint32_t> fraction_per_million; 120 121 bool operator==(const Matchers& other) const { 122 return (path_matcher == other.path_matcher && 123 header_matchers == other.header_matchers && 124 fraction_per_million == other.fraction_per_million); 125 } 126 std::string ToString() const; 127 }; 128 129 Matchers matchers; 130 131 // Action for this route. 132 // TODO(roth): When we can use absl::variant<>, consider using that 133 // here, to enforce the fact that only one of the two fields can be set. 134 std::string cluster_name; 135 struct ClusterWeight { 136 std::string name; 137 uint32_t weight; 138 bool operator==(const ClusterWeight& other) const { 139 return (name == other.name && weight == other.weight); 140 } 141 std::string ToString() const; 142 }; 143 std::vector<ClusterWeight> weighted_clusters; 144 // Storing the timeout duration from route action: 145 // RouteAction.max_stream_duration.grpc_timeout_header_max or 146 // RouteAction.max_stream_duration.max_stream_duration if the former is 147 // not set. 148 absl::optional<Duration> max_stream_duration; 149 150 bool operator==(const Route& other) const { 151 return (matchers == other.matchers && 152 cluster_name == other.cluster_name && 153 weighted_clusters == other.weighted_clusters && 154 max_stream_duration == other.max_stream_duration); 155 } 156 std::string ToString() const; 157 }; 158 159 struct RdsUpdate { 160 struct VirtualHost { 161 std::vector<std::string> domains; 162 std::vector<Route> routes; 163 164 bool operator==(const VirtualHost& other) const { 165 return domains == other.domains && routes == other.routes; 166 } 167 }; 168 169 std::vector<VirtualHost> virtual_hosts; 170 171 bool operator==(const RdsUpdate& other) const { 172 return virtual_hosts == other.virtual_hosts; 173 } 174 std::string ToString() const; 175 VirtualHost* FindVirtualHostForDomain(const std::string& domain); 176 }; 177 178 class StringMatcher { 179 public: 180 enum class StringMatcherType { 181 EXACT, // value stored in string_matcher_ field 182 PREFIX, // value stored in string_matcher_ field 183 SUFFIX, // value stored in string_matcher_ field 184 SAFE_REGEX, // pattern stored in regex_matcher_ field 185 CONTAINS, // value stored in string_matcher_ field 186 }; 187 188 StringMatcher() = default; 189 StringMatcher(const StringMatcher& other); 190 StringMatcher(StringMatcherType type, const std::string& matcher, 191 bool ignore_case = false); 192 StringMatcher& operator=(const StringMatcher& other); 193 bool operator==(const StringMatcher& other) const; 194 195 bool Match(absl::string_view value) const; 196 197 std::string ToString() const; 198 type()199 StringMatcherType type() const { return type_; } 200 201 // Valid for EXACT, PREFIX, SUFFIX and CONTAINS string_matcher()202 const std::string& string_matcher() const { return string_matcher_; } 203 204 // Valid for SAFE_REGEX regex_matcher()205 RE2* regex_matcher() const { return regex_matcher_.get(); } 206 207 private: 208 StringMatcherType type_ = StringMatcherType::EXACT; 209 std::string string_matcher_; 210 std::unique_ptr<RE2> regex_matcher_; 211 bool ignore_case_ = false; 212 }; 213 214 struct CommonTlsContext { 215 struct CertificateValidationContext { 216 std::vector<StringMatcher> match_subject_alt_names; 217 218 bool operator==(const CertificateValidationContext& other) const { 219 return match_subject_alt_names == other.match_subject_alt_names; 220 } 221 222 std::string ToString() const; 223 bool Empty() const; 224 }; 225 226 struct CertificateProviderInstance { 227 std::string instance_name; 228 std::string certificate_name; 229 230 bool operator==(const CertificateProviderInstance& other) const { 231 return instance_name == other.instance_name && 232 certificate_name == other.certificate_name; 233 } 234 235 std::string ToString() const; 236 bool Empty() const; 237 }; 238 239 struct CombinedCertificateValidationContext { 240 CertificateValidationContext default_validation_context; 241 CertificateProviderInstance 242 validation_context_certificate_provider_instance; 243 244 bool operator==(const CombinedCertificateValidationContext& other) const { 245 return default_validation_context == other.default_validation_context && 246 validation_context_certificate_provider_instance == 247 other.validation_context_certificate_provider_instance; 248 } 249 250 std::string ToString() const; 251 bool Empty() const; 252 }; 253 254 CertificateProviderInstance tls_certificate_certificate_provider_instance; 255 CombinedCertificateValidationContext combined_validation_context; 256 257 bool operator==(const CommonTlsContext& other) const { 258 return tls_certificate_certificate_provider_instance == 259 other.tls_certificate_certificate_provider_instance && 260 combined_validation_context == other.combined_validation_context; 261 } 262 263 std::string ToString() const; 264 bool Empty() const; 265 }; 266 267 // TODO(roth): When we can use absl::variant<>, consider using that 268 // here, to enforce the fact that only one of the two fields can be set. 269 struct LdsUpdate { 270 // The name to use in the RDS request. 271 std::string route_config_name; 272 // Storing the Http Connection Manager Common Http Protocol Option 273 // max_stream_duration 274 Duration http_max_stream_duration; 275 // The RouteConfiguration to use for this listener. 276 // Present only if it is inlined in the LDS response. 277 absl::optional<RdsUpdate> rds_update; 278 279 bool operator==(const LdsUpdate& other) const { 280 return route_config_name == other.route_config_name && 281 rds_update == other.rds_update && 282 http_max_stream_duration == other.http_max_stream_duration; 283 } 284 }; 285 286 using LdsUpdateMap = std::map<std::string /*server_name*/, LdsUpdate>; 287 288 using RdsUpdateMap = std::map<std::string /*route_config_name*/, RdsUpdate>; 289 290 struct CdsUpdate { 291 // The name to use in the EDS request. 292 // If empty, the cluster name will be used. 293 std::string eds_service_name; 294 // Tls Context used by clients 295 CommonTlsContext common_tls_context; 296 // The LRS server to use for load reporting. 297 // If not set, load reporting will be disabled. 298 // If set to the empty string, will use the same server we obtained the CDS 299 // data from. 300 absl::optional<std::string> lrs_load_reporting_server_name; 301 // Maximum number of outstanding requests can be made to the upstream 302 // cluster. 303 uint32_t max_concurrent_requests = 1024; 304 305 bool operator==(const CdsUpdate& other) const { 306 return eds_service_name == other.eds_service_name && 307 common_tls_context == other.common_tls_context && 308 lrs_load_reporting_server_name == 309 other.lrs_load_reporting_server_name && 310 max_concurrent_requests == other.max_concurrent_requests; 311 } 312 313 std::string ToString() const; 314 }; 315 316 using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsUpdate>; 317 318 struct EdsUpdate { 319 struct Priority { 320 struct Locality { 321 RefCountedPtr<XdsLocalityName> name; 322 uint32_t lb_weight; 323 ServerAddressList endpoints; 324 325 bool operator==(const Locality& other) const { 326 return *name == *other.name && lb_weight == other.lb_weight && 327 endpoints == other.endpoints; 328 } 329 bool operator!=(const Locality& other) const { 330 return !(*this == other); 331 } 332 std::string ToString() const; 333 }; 334 335 std::map<XdsLocalityName*, Locality, XdsLocalityName::Less> localities; 336 337 bool operator==(const Priority& other) const; 338 std::string ToString() const; 339 }; 340 using PriorityList = absl::InlinedVector<Priority, 2>; 341 342 // There are two phases of accessing this class's content: 343 // 1. to initialize in the control plane combiner; 344 // 2. to use in the data plane combiner. 345 // So no additional synchronization is needed. 346 class DropConfig : public RefCounted<DropConfig> { 347 public: 348 struct DropCategory { 349 bool operator==(const DropCategory& other) const { 350 return name == other.name && 351 parts_per_million == other.parts_per_million; 352 } 353 354 std::string name; 355 const uint32_t parts_per_million; 356 }; 357 358 using DropCategoryList = absl::InlinedVector<DropCategory, 2>; 359 AddCategoryEdsUpdate360 void AddCategory(std::string name, uint32_t parts_per_million) { 361 drop_category_list_.emplace_back( 362 DropCategory{std::move(name), parts_per_million}); 363 if (parts_per_million == 1000000) drop_all_ = true; 364 } 365 366 // The only method invoked from outside the WorkSerializer (used in 367 // the data plane). 368 bool ShouldDrop(const std::string** category_name) const; 369 drop_category_listEdsUpdate370 const DropCategoryList& drop_category_list() const { 371 return drop_category_list_; 372 } 373 drop_allEdsUpdate374 bool drop_all() const { return drop_all_; } 375 376 bool operator==(const DropConfig& other) const { 377 return drop_category_list_ == other.drop_category_list_; 378 } 379 bool operator!=(const DropConfig& other) const { 380 return !(*this == other); 381 } 382 383 std::string ToString() const; 384 385 private: 386 DropCategoryList drop_category_list_; 387 bool drop_all_ = false; 388 }; 389 390 PriorityList priorities; 391 RefCountedPtr<DropConfig> drop_config; 392 393 bool operator==(const EdsUpdate& other) const { 394 return priorities == other.priorities && 395 *drop_config == *other.drop_config; 396 } 397 std::string ToString() const; 398 }; 399 400 using EdsUpdateMap = std::map<std::string /*eds_service_name*/, EdsUpdate>; 401 402 struct ClusterLoadReport { 403 XdsClusterDropStats::Snapshot dropped_requests; 404 std::map<RefCountedPtr<XdsLocalityName>, XdsClusterLocalityStats::Snapshot, 405 XdsLocalityName::Less> 406 locality_stats; 407 grpc_millis load_report_interval; 408 }; 409 using ClusterLoadReportMap = std::map< 410 std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>, 411 ClusterLoadReport>; 412 413 XdsApi(XdsClient* client, TraceFlag* tracer, const XdsBootstrap::Node* node); 414 415 // Creates an ADS request. 416 // Takes ownership of \a error. 417 grpc_slice CreateAdsRequest(const XdsBootstrap::XdsServer& server, 418 const std::string& type_url, 419 const std::set<absl::string_view>& resource_names, 420 const std::string& version, 421 const std::string& nonce, grpc_error* error, 422 bool populate_node); 423 424 // Parses an ADS response. 425 // If the response can't be parsed at the top level, the resulting 426 // type_url will be empty. 427 struct AdsParseResult { 428 grpc_error* parse_error = GRPC_ERROR_NONE; 429 std::string version; 430 std::string nonce; 431 std::string type_url; 432 LdsUpdateMap lds_update_map; 433 RdsUpdateMap rds_update_map; 434 CdsUpdateMap cds_update_map; 435 EdsUpdateMap eds_update_map; 436 }; 437 AdsParseResult ParseAdsResponse( 438 const grpc_slice& encoded_response, 439 const std::set<absl::string_view>& expected_listener_names, 440 const std::set<absl::string_view>& expected_route_configuration_names, 441 const std::set<absl::string_view>& expected_cluster_names, 442 const std::set<absl::string_view>& expected_eds_service_names); 443 444 // Creates an initial LRS request. 445 grpc_slice CreateLrsInitialRequest(const XdsBootstrap::XdsServer& server); 446 447 // Creates an LRS request sending a client-side load report. 448 grpc_slice CreateLrsRequest(ClusterLoadReportMap cluster_load_report_map); 449 450 // Parses the LRS response and returns \a 451 // load_reporting_interval for client-side load reporting. If there is any 452 // error, the output config is invalid. 453 grpc_error* ParseLrsResponse(const grpc_slice& encoded_response, 454 bool* send_all_clusters, 455 std::set<std::string>* cluster_names, 456 grpc_millis* load_reporting_interval); 457 458 private: 459 XdsClient* client_; 460 TraceFlag* tracer_; 461 const XdsBootstrap::Node* node_; // Do not own. 462 upb::SymbolTable symtab_; 463 const std::string build_version_; 464 const std::string user_agent_name_; 465 }; 466 467 } // namespace grpc_core 468 469 #endif /* GRPC_CORE_EXT_XDS_XDS_API_H */ 470