1 //
2 // Copyright 2018 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #ifndef GRPC_SRC_CORE_EXT_XDS_XDS_ROUTE_CONFIG_H
18 #define GRPC_SRC_CORE_EXT_XDS_XDS_ROUTE_CONFIG_H
19 
20 #include <grpc/support/port_platform.h>
21 
22 #include <stdint.h>
23 
24 #include <algorithm>
25 #include <map>
26 #include <memory>
27 #include <string>
28 #include <vector>
29 
30 #include "absl/strings/string_view.h"
31 #include "absl/types/optional.h"
32 #include "absl/types/variant.h"
33 #include "envoy/config/route/v3/route.upb.h"
34 #include "envoy/config/route/v3/route.upbdefs.h"
35 #include "re2/re2.h"
36 #include "upb/reflection/def.h"
37 
38 #include "src/core/ext/xds/xds_bootstrap_grpc.h"
39 #include "src/core/ext/xds/xds_client.h"
40 #include "src/core/ext/xds/xds_cluster_specifier_plugin.h"
41 #include "src/core/ext/xds/xds_http_filters.h"
42 #include "src/core/ext/xds/xds_resource_type.h"
43 #include "src/core/ext/xds/xds_resource_type_impl.h"
44 #include "src/core/lib/channel/status_util.h"
45 #include "src/core/lib/gprpp/time.h"
46 #include "src/core/lib/gprpp/validation_errors.h"
47 #include "src/core/lib/matchers/matchers.h"
48 
49 namespace grpc_core {
50 
51 struct XdsRouteConfigResource : public XdsResourceType::ResourceData {
52   using TypedPerFilterConfig =
53       std::map<std::string, XdsHttpFilterImpl::FilterConfig>;
54 
55   using ClusterSpecifierPluginMap =
56       std::map<std::string /*cluster_specifier_plugin_name*/,
57                std::string /*LB policy config*/>;
58 
59   struct RetryPolicy {
60     internal::StatusCodeSet retry_on;
61     uint32_t num_retries;
62 
63     struct RetryBackOff {
64       Duration base_interval;
65       Duration max_interval;
66 
67       bool operator==(const RetryBackOff& other) const {
68         return base_interval == other.base_interval &&
69                max_interval == other.max_interval;
70       }
71       std::string ToString() const;
72     };
73     RetryBackOff retry_back_off;
74 
75     bool operator==(const RetryPolicy& other) const {
76       return (retry_on == other.retry_on && num_retries == other.num_retries &&
77               retry_back_off == other.retry_back_off);
78     }
79     std::string ToString() const;
80   };
81 
82   struct Route {
83     // Matchers for this route.
84     struct Matchers {
85       StringMatcher path_matcher;
86       std::vector<HeaderMatcher> header_matchers;
87       absl::optional<uint32_t> fraction_per_million;
88 
89       bool operator==(const Matchers& other) const {
90         return path_matcher == other.path_matcher &&
91                header_matchers == other.header_matchers &&
92                fraction_per_million == other.fraction_per_million;
93       }
94       std::string ToString() const;
95     };
96 
97     Matchers matchers;
98 
99     struct UnknownAction {
100       bool operator==(const UnknownAction& /* other */) const { return true; }
101     };
102 
103     struct RouteAction {
104       struct HashPolicy {
105         struct Header {
106           std::string header_name;
107           std::unique_ptr<RE2> regex;
108           std::string regex_substitution;
109 
110           Header() = default;
111 
112           // Copyable.
113           Header(const Header& other);
114           Header& operator=(const Header& other);
115 
116           // Movable.
117           Header(Header&& other) noexcept;
118           Header& operator=(Header&& other) noexcept;
119 
120           bool operator==(const Header& other) const;
121           std::string ToString() const;
122         };
123 
124         struct ChannelId {
125           bool operator==(const ChannelId&) const { return true; }
126         };
127 
128         absl::variant<Header, ChannelId> policy;
129         bool terminal = false;
130 
131         bool operator==(const HashPolicy& other) const {
132           return policy == other.policy && terminal == other.terminal;
133         }
134         std::string ToString() const;
135       };
136 
137       struct ClusterName {
138         std::string cluster_name;
139 
140         bool operator==(const ClusterName& other) const {
141           return cluster_name == other.cluster_name;
142         }
143       };
144 
145       struct ClusterWeight {
146         std::string name;
147         uint32_t weight;
148         TypedPerFilterConfig typed_per_filter_config;
149 
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;
153         }
154         std::string ToString() const;
155       };
156 
157       struct ClusterSpecifierPluginName {
158         std::string cluster_specifier_plugin_name;
159 
160         bool operator==(const ClusterSpecifierPluginName& other) const {
161           return cluster_specifier_plugin_name ==
162                  other.cluster_specifier_plugin_name;
163         }
164       };
165 
166       std::vector<HashPolicy> hash_policies;
167       absl::optional<RetryPolicy> retry_policy;
168 
169       // Action for this route.
170       absl::variant<ClusterName, std::vector<ClusterWeight>,
171                     ClusterSpecifierPluginName>
172           action;
173       // Storing the timeout duration from route action:
174       // RouteAction.max_stream_duration.grpc_timeout_header_max or
175       // RouteAction.max_stream_duration.max_stream_duration if the former is
176       // not set.
177       absl::optional<Duration> max_stream_duration;
178 
179       bool operator==(const RouteAction& other) const {
180         return hash_policies == other.hash_policies &&
181                retry_policy == other.retry_policy && action == other.action &&
182                max_stream_duration == other.max_stream_duration;
183       }
184       std::string ToString() const;
185     };
186 
187     struct NonForwardingAction {
188       bool operator==(const NonForwardingAction& /* other */) const {
189         return true;
190       }
191     };
192 
193     absl::variant<UnknownAction, RouteAction, NonForwardingAction> action;
194     TypedPerFilterConfig typed_per_filter_config;
195 
196     bool operator==(const Route& other) const {
197       return matchers == other.matchers && action == other.action &&
198              typed_per_filter_config == other.typed_per_filter_config;
199     }
200     std::string ToString() const;
201   };
202 
203   struct VirtualHost {
204     std::vector<std::string> domains;
205     std::vector<Route> routes;
206     TypedPerFilterConfig typed_per_filter_config;
207 
208     bool operator==(const VirtualHost& other) const {
209       return domains == other.domains && routes == other.routes &&
210              typed_per_filter_config == other.typed_per_filter_config;
211     }
212   };
213 
214   std::vector<VirtualHost> virtual_hosts;
215   ClusterSpecifierPluginMap cluster_specifier_plugin_map;
216 
217   bool operator==(const XdsRouteConfigResource& other) const {
218     return virtual_hosts == other.virtual_hosts &&
219            cluster_specifier_plugin_map == other.cluster_specifier_plugin_map;
220   }
221   std::string ToString() const;
222 
223   static XdsRouteConfigResource Parse(
224       const XdsResourceType::DecodeContext& context,
225       const envoy_config_route_v3_RouteConfiguration* route_config,
226       ValidationErrors* errors);
227 };
228 
229 class XdsRouteConfigResourceType
230     : public XdsResourceTypeImpl<XdsRouteConfigResourceType,
231                                  XdsRouteConfigResource> {
232  public:
type_url()233   absl::string_view type_url() const override {
234     return "envoy.config.route.v3.RouteConfiguration";
235   }
236 
237   DecodeResult Decode(const XdsResourceType::DecodeContext& context,
238                       absl::string_view serialized_resource) const override;
239 
InitUpbSymtab(XdsClient * xds_client,upb_DefPool * symtab)240   void InitUpbSymtab(XdsClient* xds_client,
241                      upb_DefPool* symtab) const override {
242     envoy_config_route_v3_RouteConfiguration_getmsgdef(symtab);
243     const auto& cluster_specifier_plugin_registry =
244         static_cast<const GrpcXdsBootstrap&>(xds_client->bootstrap())
245             .cluster_specifier_plugin_registry();
246     cluster_specifier_plugin_registry.PopulateSymtab(symtab);
247   }
248 };
249 
250 }  // namespace grpc_core
251 
252 #endif  // GRPC_SRC_CORE_EXT_XDS_XDS_ROUTE_CONFIG_H
253