3 * Copyright 2018 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #ifndef GRPC_CORE_EXT_XDS_XDS_API_H
20 #define GRPC_CORE_EXT_XDS_XDS_API_H
22 #include <grpc/support/port_platform.h>
28 #include "absl/container/inlined_vector.h"
29 #include "absl/types/optional.h"
32 #include "upb/def.hpp"
34 #include <grpc/slice_buffer.h>
36 #include "envoy/admin/v3/config_dump.upb.h"
37 #include "src/core/ext/filters/client_channel/server_address.h"
38 #include "src/core/ext/xds/xds_bootstrap.h"
39 #include "src/core/ext/xds/xds_client_stats.h"
40 #include "src/core/ext/xds/xds_http_filters.h"
41 #include "src/core/lib/channel/status_util.h"
42 #include "src/core/lib/matchers/matchers.h"
46 // TODO(yashykt): Check to see if xDS security is enabled. This will be
47 // removed once this feature is fully integration-tested and enabled by
49 bool XdsSecurityEnabled();
55 static const char* kLdsTypeUrl;
56 static const char* kRdsTypeUrl;
57 static const char* kCdsTypeUrl;
58 static const char* kEdsTypeUrl;
63 bool operator==(const Duration& other) const {
64 return seconds == other.seconds && nanos == other.nanos;
66 std::string ToString() const {
67 return absl::StrFormat("Duration seconds: %ld, nanos %d", seconds, nanos);
71 using TypedPerFilterConfig =
72 std::map<std::string, XdsHttpFilterImpl::FilterConfig>;
74 // TODO(donnadionne): When we can use absl::variant<>, consider using that
75 // for: PathMatcher, HeaderMatcher, cluster_name and weighted_clusters
77 // Matchers for this route.
79 StringMatcher path_matcher;
80 std::vector<HeaderMatcher> header_matchers;
81 absl::optional<uint32_t> fraction_per_million;
83 bool operator==(const Matchers& other) const {
84 return path_matcher == other.path_matcher &&
85 header_matchers == other.header_matchers &&
86 fraction_per_million == other.fraction_per_million;
88 std::string ToString() const;
92 enum Type { HEADER, CHANNEL_ID };
94 bool terminal = false;
95 // Fields used for type HEADER.
96 std::string header_name;
97 std::unique_ptr<RE2> regex = nullptr;
98 std::string regex_substitution;
103 HashPolicy(const HashPolicy& other);
104 HashPolicy& operator=(const HashPolicy& other);
107 HashPolicy(HashPolicy&& other) noexcept;
108 HashPolicy& operator=(HashPolicy&& other) noexcept;
110 bool operator==(const HashPolicy& other) const;
111 std::string ToString() const;
114 std::vector<HashPolicy> hash_policies;
117 internal::StatusCodeSet retry_on;
118 uint32_t num_retries;
120 struct RetryBackOff {
121 Duration base_interval;
122 Duration max_interval;
124 bool operator==(const RetryBackOff& other) const {
125 return base_interval == other.base_interval &&
126 max_interval == other.max_interval;
128 std::string ToString() const;
130 RetryBackOff retry_back_off;
132 bool operator==(const RetryPolicy& other) const {
133 return (retry_on == other.retry_on &&
134 num_retries == other.num_retries &&
135 retry_back_off == other.retry_back_off);
137 std::string ToString() const;
139 absl::optional<RetryPolicy> retry_policy;
141 // Action for this route.
142 // TODO(roth): When we can use absl::variant<>, consider using that
143 // here, to enforce the fact that only one of the two fields can be set.
144 std::string cluster_name;
145 struct ClusterWeight {
148 TypedPerFilterConfig typed_per_filter_config;
150 bool operator==(const ClusterWeight& other) const {
151 return name == other.name && weight == other.weight &&
152 typed_per_filter_config == other.typed_per_filter_config;
154 std::string ToString() const;
156 std::vector<ClusterWeight> weighted_clusters;
157 // Storing the timeout duration from route action:
158 // RouteAction.max_stream_duration.grpc_timeout_header_max or
159 // RouteAction.max_stream_duration.max_stream_duration if the former is
161 absl::optional<Duration> max_stream_duration;
163 TypedPerFilterConfig typed_per_filter_config;
165 bool operator==(const Route& other) const {
166 return matchers == other.matchers && cluster_name == other.cluster_name &&
167 retry_policy == other.retry_policy &&
168 weighted_clusters == other.weighted_clusters &&
169 max_stream_duration == other.max_stream_duration &&
170 typed_per_filter_config == other.typed_per_filter_config;
172 std::string ToString() const;
177 std::vector<std::string> domains;
178 std::vector<Route> routes;
179 TypedPerFilterConfig typed_per_filter_config;
181 bool operator==(const VirtualHost& other) const {
182 return domains == other.domains && routes == other.routes &&
183 typed_per_filter_config == other.typed_per_filter_config;
187 std::vector<VirtualHost> virtual_hosts;
189 bool operator==(const RdsUpdate& other) const {
190 return virtual_hosts == other.virtual_hosts;
192 std::string ToString() const;
193 VirtualHost* FindVirtualHostForDomain(const std::string& domain);
196 struct CommonTlsContext {
197 struct CertificateValidationContext {
198 std::vector<StringMatcher> match_subject_alt_names;
200 bool operator==(const CertificateValidationContext& other) const {
201 return match_subject_alt_names == other.match_subject_alt_names;
204 std::string ToString() const;
208 struct CertificateProviderInstance {
209 std::string instance_name;
210 std::string certificate_name;
212 bool operator==(const CertificateProviderInstance& other) const {
213 return instance_name == other.instance_name &&
214 certificate_name == other.certificate_name;
217 std::string ToString() const;
221 struct CombinedCertificateValidationContext {
222 CertificateValidationContext default_validation_context;
223 CertificateProviderInstance
224 validation_context_certificate_provider_instance;
226 bool operator==(const CombinedCertificateValidationContext& other) const {
227 return default_validation_context == other.default_validation_context &&
228 validation_context_certificate_provider_instance ==
229 other.validation_context_certificate_provider_instance;
232 std::string ToString() const;
236 CertificateProviderInstance tls_certificate_certificate_provider_instance;
237 CombinedCertificateValidationContext combined_validation_context;
239 bool operator==(const CommonTlsContext& other) const {
240 return tls_certificate_certificate_provider_instance ==
241 other.tls_certificate_certificate_provider_instance &&
242 combined_validation_context == other.combined_validation_context;
245 std::string ToString() const;
249 struct DownstreamTlsContext {
250 CommonTlsContext common_tls_context;
251 bool require_client_certificate = false;
253 bool operator==(const DownstreamTlsContext& other) const {
254 return common_tls_context == other.common_tls_context &&
255 require_client_certificate == other.require_client_certificate;
258 std::string ToString() const;
262 // TODO(roth): When we can use absl::variant<>, consider using that
263 // here, to enforce the fact that only one of the two fields can be set.
265 enum class ListenerType {
270 struct HttpConnectionManager {
271 // The name to use in the RDS request.
272 std::string route_config_name;
273 // Storing the Http Connection Manager Common Http Protocol Option
274 // max_stream_duration
275 Duration http_max_stream_duration;
276 // The RouteConfiguration to use for this listener.
277 // Present only if it is inlined in the LDS response.
278 absl::optional<RdsUpdate> rds_update;
282 XdsHttpFilterImpl::FilterConfig config;
284 bool operator==(const HttpFilter& other) const {
285 return name == other.name && config == other.config;
288 std::string ToString() const;
290 std::vector<HttpFilter> http_filters;
292 bool operator==(const HttpConnectionManager& other) const {
293 return route_config_name == other.route_config_name &&
294 http_max_stream_duration == other.http_max_stream_duration &&
295 rds_update == other.rds_update &&
296 http_filters == other.http_filters;
299 std::string ToString() const;
302 // Populated for type=kHttpApiListener.
303 HttpConnectionManager http_connection_manager;
305 // Populated for type=kTcpListener.
306 // host:port listening_address set when type is kTcpListener
309 struct FilterChainData {
310 DownstreamTlsContext downstream_tls_context;
311 // This is in principle the filter list.
312 // We currently require exactly one filter, which is the HCM.
313 HttpConnectionManager http_connection_manager;
315 bool operator==(const FilterChainData& other) const {
316 return downstream_tls_context == other.downstream_tls_context &&
317 http_connection_manager == other.http_connection_manager;
320 std::string ToString() const;
323 // A multi-level map used to determine which filter chain to use for a given
324 // incoming connection. Determining the right filter chain for a given
325 // connection checks the following properties, in order:
326 // - destination port (never matched, so not present in map)
327 // - destination IP address
328 // - server name (never matched, so not present in map)
329 // - transport protocol (allows only "raw_buffer" or unset, prefers the
330 // former, so only one of those two types is present in map)
331 // - application protocol (never matched, so not present in map)
332 // - connection source type (any, local or external)
333 // - source IP address
335 // https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/listener/v3/listener_components.proto#config-listener-v3-filterchainmatch
337 struct FilterChainMap {
338 struct FilterChainDataSharedPtr {
339 std::shared_ptr<FilterChainData> data;
340 bool operator==(const FilterChainDataSharedPtr& other) const {
341 return *data == *other.data;
345 grpc_resolved_address address;
348 bool operator==(const CidrRange& other) const {
349 return memcmp(&address, &other.address, sizeof(address)) == 0 &&
350 prefix_len == other.prefix_len;
353 std::string ToString() const;
355 using SourcePortsMap = std::map<uint16_t, FilterChainDataSharedPtr>;
357 absl::optional<CidrRange> prefix_range;
358 SourcePortsMap ports_map;
360 bool operator==(const SourceIp& other) const {
361 return prefix_range == other.prefix_range &&
362 ports_map == other.ports_map;
365 using SourceIpVector = std::vector<SourceIp>;
366 enum class ConnectionSourceType {
371 using ConnectionSourceTypesArray = std::array<SourceIpVector, 3>;
372 struct DestinationIp {
373 absl::optional<CidrRange> prefix_range;
374 // We always fail match on server name, so those filter chains are not
376 ConnectionSourceTypesArray source_types_array;
378 bool operator==(const DestinationIp& other) const {
379 return prefix_range == other.prefix_range &&
380 source_types_array == other.source_types_array;
383 // We always fail match on destination ports map
384 using DestinationIpVector = std::vector<DestinationIp>;
385 DestinationIpVector destination_ip_vector;
387 bool operator==(const FilterChainMap& other) const {
388 return destination_ip_vector == other.destination_ip_vector;
391 std::string ToString() const;
394 absl::optional<FilterChainData> default_filter_chain;
396 bool operator==(const LdsUpdate& other) const {
397 return http_connection_manager == other.http_connection_manager &&
398 address == other.address &&
399 filter_chain_map == other.filter_chain_map &&
400 default_filter_chain == other.default_filter_chain;
403 std::string ToString() const;
406 struct LdsResourceData {
408 std::string serialized_proto;
411 using LdsUpdateMap = std::map<std::string /*server_name*/, LdsResourceData>;
413 struct RdsResourceData {
415 std::string serialized_proto;
419 std::map<std::string /*route_config_name*/, RdsResourceData>;
422 enum ClusterType { EDS, LOGICAL_DNS, AGGREGATE };
423 ClusterType cluster_type;
424 // For cluster type EDS.
425 // The name to use in the EDS request.
426 // If empty, the cluster name will be used.
427 std::string eds_service_name;
428 // For cluster type LOGICAL_DNS.
429 // The hostname to lookup in DNS.
430 std::string dns_hostname;
431 // For cluster type AGGREGATE.
432 // The prioritized list of cluster names.
433 std::vector<std::string> prioritized_cluster_names;
435 // Tls Context used by clients
436 CommonTlsContext common_tls_context;
438 // The LRS server to use for load reporting.
439 // If not set, load reporting will be disabled.
440 // If set to the empty string, will use the same server we obtained the CDS
442 absl::optional<std::string> lrs_load_reporting_server_name;
444 // The LB policy to use (e.g., "ROUND_ROBIN" or "RING_HASH").
445 std::string lb_policy;
446 // Used for RING_HASH LB policy only.
447 uint64_t min_ring_size = 1024;
448 uint64_t max_ring_size = 8388608;
449 // Maximum number of outstanding requests can be made to the upstream
451 uint32_t max_concurrent_requests = 1024;
453 bool operator==(const CdsUpdate& other) const {
454 return cluster_type == other.cluster_type &&
455 eds_service_name == other.eds_service_name &&
456 dns_hostname == other.dns_hostname &&
457 prioritized_cluster_names == other.prioritized_cluster_names &&
458 common_tls_context == other.common_tls_context &&
459 lrs_load_reporting_server_name ==
460 other.lrs_load_reporting_server_name &&
461 lb_policy == other.lb_policy &&
462 min_ring_size == other.min_ring_size &&
463 max_ring_size == other.max_ring_size &&
464 max_concurrent_requests == other.max_concurrent_requests;
467 std::string ToString() const;
470 struct CdsResourceData {
472 std::string serialized_proto;
475 using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsResourceData>;
480 RefCountedPtr<XdsLocalityName> name;
482 ServerAddressList endpoints;
484 bool operator==(const Locality& other) const {
485 return *name == *other.name && lb_weight == other.lb_weight &&
486 endpoints == other.endpoints;
488 bool operator!=(const Locality& other) const {
489 return !(*this == other);
491 std::string ToString() const;
494 std::map<XdsLocalityName*, Locality, XdsLocalityName::Less> localities;
496 bool operator==(const Priority& other) const;
497 std::string ToString() const;
499 using PriorityList = absl::InlinedVector<Priority, 2>;
501 // There are two phases of accessing this class's content:
502 // 1. to initialize in the control plane combiner;
503 // 2. to use in the data plane combiner.
504 // So no additional synchronization is needed.
505 class DropConfig : public RefCounted<DropConfig> {
507 struct DropCategory {
508 bool operator==(const DropCategory& other) const {
509 return name == other.name &&
510 parts_per_million == other.parts_per_million;
514 const uint32_t parts_per_million;
517 using DropCategoryList = absl::InlinedVector<DropCategory, 2>;
519 void AddCategory(std::string name, uint32_t parts_per_million) {
520 drop_category_list_.emplace_back(
521 DropCategory{std::move(name), parts_per_million});
522 if (parts_per_million == 1000000) drop_all_ = true;
525 // The only method invoked from outside the WorkSerializer (used in
527 bool ShouldDrop(const std::string** category_name) const;
529 const DropCategoryList& drop_category_list() const {
530 return drop_category_list_;
533 bool drop_all() const { return drop_all_; }
535 bool operator==(const DropConfig& other) const {
536 return drop_category_list_ == other.drop_category_list_;
538 bool operator!=(const DropConfig& other) const {
539 return !(*this == other);
542 std::string ToString() const;
545 DropCategoryList drop_category_list_;
546 bool drop_all_ = false;
549 PriorityList priorities;
550 RefCountedPtr<DropConfig> drop_config;
552 bool operator==(const EdsUpdate& other) const {
553 return priorities == other.priorities &&
554 *drop_config == *other.drop_config;
556 std::string ToString() const;
559 struct EdsResourceData {
561 std::string serialized_proto;
565 std::map<std::string /*eds_service_name*/, EdsResourceData>;
567 struct ClusterLoadReport {
568 XdsClusterDropStats::Snapshot dropped_requests;
569 std::map<RefCountedPtr<XdsLocalityName>, XdsClusterLocalityStats::Snapshot,
570 XdsLocalityName::Less>
572 grpc_millis load_report_interval;
574 using ClusterLoadReportMap = std::map<
575 std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>,
578 // The metadata of the xDS resource; used by the xDS config dump.
579 struct ResourceMetadata {
580 // Resource status from the view of a xDS client, which tells the
581 // synchronization status between the xDS client and the xDS server.
582 enum ClientResourceStatus {
583 // Client requested this resource but hasn't received any update from
584 // management server. The client will not fail requests, but will queue
586 // until update arrives or the client times out waiting for the resource.
588 // This resource has been requested by the client but has either not been
589 // delivered by the server or was previously delivered by the server and
590 // then subsequently removed from resources provided by the server.
592 // Client received this resource and replied with ACK.
594 // Client received this resource and replied with NACK.
598 // The client status of this resource.
599 ClientResourceStatus client_status = REQUESTED;
600 // The serialized bytes of the last successfully updated raw xDS resource.
601 std::string serialized_proto;
602 // The timestamp when the resource was last successfully updated.
603 grpc_millis update_time = 0;
604 // The last successfully updated version of the resource.
606 // The rejected version string of the last failed update attempt.
607 std::string failed_version;
608 // Details about the last failed update attempt.
609 std::string failed_details;
610 // Timestamp of the last failed update attempt.
611 grpc_millis failed_update_time = 0;
613 using ResourceMetadataMap =
614 std::map<absl::string_view /*resource_name*/, const ResourceMetadata*>;
615 struct ResourceTypeMetadata {
616 absl::string_view version;
617 ResourceMetadataMap resource_metadata_map;
619 using ResourceTypeMetadataMap =
620 std::map<absl::string_view /*type_url*/, ResourceTypeMetadata>;
621 static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
622 envoy_admin_v3_REQUESTED) ==
623 ResourceMetadata::ClientResourceStatus::REQUESTED,
625 static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
626 envoy_admin_v3_DOES_NOT_EXIST) ==
627 ResourceMetadata::ClientResourceStatus::DOES_NOT_EXIST,
629 static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
630 envoy_admin_v3_ACKED) ==
631 ResourceMetadata::ClientResourceStatus::ACKED,
633 static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
634 envoy_admin_v3_NACKED) ==
635 ResourceMetadata::ClientResourceStatus::NACKED,
638 // If the response can't be parsed at the top level, the resulting
639 // type_url will be empty.
640 // If there is any other type of validation error, the parse_error
641 // field will be set to something other than GRPC_ERROR_NONE and the
642 // resource_names_failed field will be populated.
643 // Otherwise, one of the *_update_map fields will be populated, based
644 // on the type_url field.
645 struct AdsParseResult {
646 grpc_error_handle parse_error = GRPC_ERROR_NONE;
649 std::string type_url;
650 LdsUpdateMap lds_update_map;
651 RdsUpdateMap rds_update_map;
652 CdsUpdateMap cds_update_map;
653 EdsUpdateMap eds_update_map;
654 std::set<std::string> resource_names_failed;
657 XdsApi(XdsClient* client, TraceFlag* tracer, const XdsBootstrap::Node* node,
658 const CertificateProviderStore::PluginDefinitionMap* map);
660 // Creates an ADS request.
661 // Takes ownership of \a error.
662 grpc_slice CreateAdsRequest(const XdsBootstrap::XdsServer& server,
663 const std::string& type_url,
664 const std::set<absl::string_view>& resource_names,
665 const std::string& version,
666 const std::string& nonce, grpc_error_handle error,
669 // Parses an ADS response.
670 AdsParseResult ParseAdsResponse(
671 const XdsBootstrap::XdsServer& server, const grpc_slice& encoded_response,
672 const std::set<absl::string_view>& expected_listener_names,
673 const std::set<absl::string_view>& expected_route_configuration_names,
674 const std::set<absl::string_view>& expected_cluster_names,
675 const std::set<absl::string_view>& expected_eds_service_names);
677 // Creates an initial LRS request.
678 grpc_slice CreateLrsInitialRequest(const XdsBootstrap::XdsServer& server);
680 // Creates an LRS request sending a client-side load report.
681 grpc_slice CreateLrsRequest(ClusterLoadReportMap cluster_load_report_map);
683 // Parses the LRS response and returns \a
684 // load_reporting_interval for client-side load reporting. If there is any
685 // error, the output config is invalid.
686 grpc_error_handle ParseLrsResponse(const grpc_slice& encoded_response,
687 bool* send_all_clusters,
688 std::set<std::string>* cluster_names,
689 grpc_millis* load_reporting_interval);
691 // Assemble the client config proto message and return the serialized result.
692 std::string AssembleClientConfig(
693 const ResourceTypeMetadataMap& resource_type_metadata_map);
698 const XdsBootstrap::Node* node_; // Do not own.
699 const CertificateProviderStore::PluginDefinitionMap*
700 certificate_provider_definition_map_; // Do not own.
701 upb::SymbolTable symtab_;
702 const std::string build_version_;
703 const std::string user_agent_name_;
704 const std::string user_agent_version_;
707 } // namespace grpc_core
709 #endif /* GRPC_CORE_EXT_XDS_XDS_API_H */