Imported Upstream version 1.34.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
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     }
62     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   struct StringMatcher {
179     enum class StringMatcherType {
180       EXACT,       // value stored in string_matcher_field
181       PREFIX,      // value stored in string_matcher_field
182       SUFFIX,      // value stored in string_matcher_field
183       SAFE_REGEX,  // use regex_match field
184       CONTAINS,    // value stored in string_matcher_field
185     };
186     StringMatcherType type;
187     std::string string_matcher;
188     std::unique_ptr<RE2> regex_match;
189     bool ignore_case;
190
191     StringMatcher() = default;
192     StringMatcher(const StringMatcher& other);
193     StringMatcher& operator=(const StringMatcher& other);
194     bool operator==(const StringMatcher& other) const;
195   };
196
197   struct CommonTlsContext {
198     struct CertificateValidationContext {
199       std::vector<StringMatcher> match_subject_alt_names;
200
201       bool operator==(const CertificateValidationContext& other) const {
202         return match_subject_alt_names == other.match_subject_alt_names;
203       }
204     };
205
206     struct CertificateProviderInstance {
207       std::string instance_name;
208       std::string certificate_name;
209
210       bool operator==(const CertificateProviderInstance& other) const {
211         return instance_name == other.instance_name &&
212                certificate_name == other.certificate_name;
213       }
214     };
215
216     struct CombinedCertificateValidationContext {
217       CertificateValidationContext default_validation_context;
218       CertificateProviderInstance
219           validation_context_certificate_provider_instance;
220
221       bool operator==(const CombinedCertificateValidationContext& other) const {
222         return default_validation_context == other.default_validation_context &&
223                validation_context_certificate_provider_instance ==
224                    other.validation_context_certificate_provider_instance;
225       }
226     };
227
228     CertificateProviderInstance tls_certificate_certificate_provider_instance;
229     CombinedCertificateValidationContext combined_validation_context;
230
231     bool operator==(const CommonTlsContext& other) const {
232       return tls_certificate_certificate_provider_instance ==
233                  other.tls_certificate_certificate_provider_instance &&
234              combined_validation_context == other.combined_validation_context;
235     }
236   };
237
238   // TODO(roth): When we can use absl::variant<>, consider using that
239   // here, to enforce the fact that only one of the two fields can be set.
240   struct LdsUpdate {
241     // The name to use in the RDS request.
242     std::string route_config_name;
243     // Storing the Http Connection Manager Common Http Protocol Option
244     // max_stream_duration
245     Duration http_max_stream_duration;
246     // The RouteConfiguration to use for this listener.
247     // Present only if it is inlined in the LDS response.
248     absl::optional<RdsUpdate> rds_update;
249
250     bool operator==(const LdsUpdate& other) const {
251       return route_config_name == other.route_config_name &&
252              rds_update == other.rds_update &&
253              http_max_stream_duration == other.http_max_stream_duration;
254     }
255   };
256
257   using LdsUpdateMap = std::map<std::string /*server_name*/, LdsUpdate>;
258
259   using RdsUpdateMap = std::map<std::string /*route_config_name*/, RdsUpdate>;
260
261   struct CdsUpdate {
262     // The name to use in the EDS request.
263     // If empty, the cluster name will be used.
264     std::string eds_service_name;
265     // Tls Context used by clients
266     CommonTlsContext common_tls_context;
267     // The LRS server to use for load reporting.
268     // If not set, load reporting will be disabled.
269     // If set to the empty string, will use the same server we obtained the CDS
270     // data from.
271     absl::optional<std::string> lrs_load_reporting_server_name;
272     // Maximum number of outstanding requests can be made to the upstream
273     // cluster.
274     uint32_t max_concurrent_requests = 1024;
275
276     bool operator==(const CdsUpdate& other) const {
277       return eds_service_name == other.eds_service_name &&
278              common_tls_context == other.common_tls_context &&
279              lrs_load_reporting_server_name ==
280                  other.lrs_load_reporting_server_name &&
281              max_concurrent_requests == other.max_concurrent_requests;
282     }
283   };
284
285   using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsUpdate>;
286
287   struct EdsUpdate {
288     struct Priority {
289       struct Locality {
290         RefCountedPtr<XdsLocalityName> name;
291         uint32_t lb_weight;
292         ServerAddressList endpoints;
293
294         bool operator==(const Locality& other) const {
295           return *name == *other.name && lb_weight == other.lb_weight &&
296                  endpoints == other.endpoints;
297         }
298         bool operator!=(const Locality& other) const {
299           return !(*this == other);
300         }
301         std::string ToString() const;
302       };
303
304       std::map<XdsLocalityName*, Locality, XdsLocalityName::Less> localities;
305
306       bool operator==(const Priority& other) const;
307       std::string ToString() const;
308     };
309     using PriorityList = absl::InlinedVector<Priority, 2>;
310
311     // There are two phases of accessing this class's content:
312     // 1. to initialize in the control plane combiner;
313     // 2. to use in the data plane combiner.
314     // So no additional synchronization is needed.
315     class DropConfig : public RefCounted<DropConfig> {
316      public:
317       struct DropCategory {
318         bool operator==(const DropCategory& other) const {
319           return name == other.name &&
320                  parts_per_million == other.parts_per_million;
321         }
322
323         std::string name;
324         const uint32_t parts_per_million;
325       };
326
327       using DropCategoryList = absl::InlinedVector<DropCategory, 2>;
328
329       void AddCategory(std::string name, uint32_t parts_per_million) {
330         drop_category_list_.emplace_back(
331             DropCategory{std::move(name), parts_per_million});
332         if (parts_per_million == 1000000) drop_all_ = true;
333       }
334
335       // The only method invoked from outside the WorkSerializer (used in
336       // the data plane).
337       bool ShouldDrop(const std::string** category_name) const;
338
339       const DropCategoryList& drop_category_list() const {
340         return drop_category_list_;
341       }
342
343       bool drop_all() const { return drop_all_; }
344
345       bool operator==(const DropConfig& other) const {
346         return drop_category_list_ == other.drop_category_list_;
347       }
348       bool operator!=(const DropConfig& other) const {
349         return !(*this == other);
350       }
351
352       std::string ToString() const;
353
354      private:
355       DropCategoryList drop_category_list_;
356       bool drop_all_ = false;
357     };
358
359     PriorityList priorities;
360     RefCountedPtr<DropConfig> drop_config;
361
362     bool operator==(const EdsUpdate& other) const {
363       return priorities == other.priorities &&
364              *drop_config == *other.drop_config;
365     }
366     std::string ToString() const;
367   };
368
369   using EdsUpdateMap = std::map<std::string /*eds_service_name*/, EdsUpdate>;
370
371   struct ClusterLoadReport {
372     XdsClusterDropStats::Snapshot dropped_requests;
373     std::map<RefCountedPtr<XdsLocalityName>, XdsClusterLocalityStats::Snapshot,
374              XdsLocalityName::Less>
375         locality_stats;
376     grpc_millis load_report_interval;
377   };
378   using ClusterLoadReportMap = std::map<
379       std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>,
380       ClusterLoadReport>;
381
382   XdsApi(XdsClient* client, TraceFlag* tracer, const XdsBootstrap::Node* node);
383
384   // Creates an ADS request.
385   // Takes ownership of \a error.
386   grpc_slice CreateAdsRequest(const XdsBootstrap::XdsServer& server,
387                               const std::string& type_url,
388                               const std::set<absl::string_view>& resource_names,
389                               const std::string& version,
390                               const std::string& nonce, grpc_error* error,
391                               bool populate_node);
392
393   // Parses an ADS response.
394   // If the response can't be parsed at the top level, the resulting
395   // type_url will be empty.
396   struct AdsParseResult {
397     grpc_error* parse_error = GRPC_ERROR_NONE;
398     std::string version;
399     std::string nonce;
400     std::string type_url;
401     LdsUpdateMap lds_update_map;
402     RdsUpdateMap rds_update_map;
403     CdsUpdateMap cds_update_map;
404     EdsUpdateMap eds_update_map;
405   };
406   AdsParseResult ParseAdsResponse(
407       const grpc_slice& encoded_response,
408       const std::set<absl::string_view>& expected_listener_names,
409       const std::set<absl::string_view>& expected_route_configuration_names,
410       const std::set<absl::string_view>& expected_cluster_names,
411       const std::set<absl::string_view>& expected_eds_service_names);
412
413   // Creates an initial LRS request.
414   grpc_slice CreateLrsInitialRequest(const XdsBootstrap::XdsServer& server);
415
416   // Creates an LRS request sending a client-side load report.
417   grpc_slice CreateLrsRequest(ClusterLoadReportMap cluster_load_report_map);
418
419   // Parses the LRS response and returns \a
420   // load_reporting_interval for client-side load reporting. If there is any
421   // error, the output config is invalid.
422   grpc_error* ParseLrsResponse(const grpc_slice& encoded_response,
423                                bool* send_all_clusters,
424                                std::set<std::string>* cluster_names,
425                                grpc_millis* load_reporting_interval);
426
427  private:
428   XdsClient* client_;
429   TraceFlag* tracer_;
430   const XdsBootstrap::Node* node_;  // Do not own.
431   upb::SymbolTable symtab_;
432   const std::string build_version_;
433   const std::string user_agent_name_;
434 };
435
436 }  // namespace grpc_core
437
438 #endif /* GRPC_CORE_EXT_XDS_XDS_API_H */