Imported Upstream version 1.36.0
[platform/upstream/grpc.git] / src / core / ext / xds / xds_api.h
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     }
63     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
316       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
326       const DropCategoryList& drop_category_list() const {
327         return drop_category_list_;
328       }
329
330       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 */