• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2016 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_SRC_CORE_LIB_SURFACE_CHANNEL_INIT_H
20 #define GRPC_SRC_CORE_LIB_SURFACE_CHANNEL_INIT_H
21 
22 #include <grpc/support/port_platform.h>
23 #include <stdint.h>
24 
25 #include <initializer_list>
26 #include <memory>
27 #include <ostream>
28 #include <utility>
29 #include <vector>
30 
31 #include "absl/functional/any_invocable.h"
32 #include "absl/log/check.h"
33 #include "src/core/lib/channel/channel_args.h"
34 #include "src/core/lib/channel/channel_fwd.h"
35 #include "src/core/lib/channel/channel_stack_builder.h"
36 #include "src/core/lib/surface/channel_stack_type.h"
37 #include "src/core/lib/transport/call_filters.h"
38 #include "src/core/lib/transport/interception_chain.h"
39 #include "src/core/util/debug_location.h"
40 #include "src/core/util/unique_type_name.h"
41 
42 /// This module provides a way for plugins (and the grpc core library itself)
43 /// to register mutators for channel stacks.
44 /// It also provides a universal entry path to run those mutators to build
45 /// a channel stack for various subsystems.
46 
47 namespace grpc_core {
48 
49 // HACK HACK HACK
50 // Right now grpc_channel_filter has a bunch of dependencies high in the stack,
51 // but this code needs to live as a dependency of CoreConfiguration so we need
52 // to be careful to ensure no dependency loops.
53 //
54 // We absolutely must be able to get the name from a filter - for stability and
55 // for debuggability.
56 //
57 // So we export this function, and have it filled in by the higher level code at
58 // static initialization time.
59 //
60 // TODO(ctiller): remove this. When we define a FilterFactory type, that type
61 // can be specified with the right constraints to be depended upon by this code,
62 // and that type can export a `string_view Name()` method.
63 extern UniqueTypeName (*NameFromChannelFilter)(const grpc_channel_filter*);
64 
65 class ChannelInit {
66  private:
67   // Version constraints: filters can be registered against a specific version
68   // of the stack (V2 || V3), or registered for any stack.
69   enum class Version : uint8_t {
70     kAny,
71     kV2,
72     kV3,
73   };
VersionToString(Version version)74   static const char* VersionToString(Version version) {
75     switch (version) {
76       case Version::kAny:
77         return "Any";
78       case Version::kV2:
79         return "V2";
80       case Version::kV3:
81         return "V3";
82     }
83     return "Unknown";
84   }
85   template <typename Sink>
AbslStringify(Sink & sink,Version version)86   friend void AbslStringify(Sink& sink, Version version) {
87     sink.Append(VersionToString(version));
88   }
89   friend std::ostream& operator<<(std::ostream& out, Version version) {
90     return out << VersionToString(version);
91   }
SkipV3(Version version)92   static bool SkipV3(Version version) {
93     switch (version) {
94       case Version::kAny:
95       case Version::kV3:
96         return false;
97       case Version::kV2:
98         return true;
99     }
100     GPR_UNREACHABLE_CODE(return false);
101   }
SkipV2(Version version)102   static bool SkipV2(Version version) {
103     switch (version) {
104       case Version::kAny:
105       case Version::kV2:
106         return false;
107       case Version::kV3:
108         return true;
109     }
110     GPR_UNREACHABLE_CODE(return false);
111   }
112 
113  public:
114   // Predicate for if a filter registration applies
115   using InclusionPredicate = absl::AnyInvocable<bool(const ChannelArgs&) const>;
116   // Post processor for the channel stack - applied in PostProcessorSlot order
117   using PostProcessor = absl::AnyInvocable<void(ChannelStackBuilder&) const>;
118   // Function that can be called to add a filter to a stack builder
119   using FilterAdder = void (*)(InterceptionChainBuilder&);
120   // Post processing slots - up to one PostProcessor per slot can be registered
121   // They run after filters registered are added to the channel stack builder,
122   // but before Build is called - allowing ad-hoc mutation to the channel stack.
123   enum class PostProcessorSlot : uint8_t {
124     kAuthSubstitution,
125     kXdsChannelStackModifier,
126     kCount
127   };
PostProcessorSlotName(PostProcessorSlot slot)128   static const char* PostProcessorSlotName(PostProcessorSlot slot) {
129     switch (slot) {
130       case PostProcessorSlot::kAuthSubstitution:
131         return "AuthSubstitution";
132       case PostProcessorSlot::kXdsChannelStackModifier:
133         return "XdsChannelStackModifier";
134       case PostProcessorSlot::kCount:
135         return "---count---";
136     }
137     return "Unknown";
138   }
139   template <typename Sink>
AbslStringify(Sink & sink,PostProcessorSlot slot)140   friend void AbslStringify(Sink& sink, PostProcessorSlot slot) {
141     sink.Append(PostProcessorSlotName(slot));
142   }
143   // Ordering priorities.
144   // Most filters should use the kDefault priority.
145   // Filters that need to appear before the default priority should use kTop,
146   // filters that need to appear later should use the kBottom priority.
147   // Explicit before/after ordering between filters dominates: eg, if a filter
148   // with kBottom priority is marked as *BEFORE* a kTop filter, then the first
149   // filter will appear before the second.
150   // It is an error to have two filters with kTop (or two with kBottom)
151   // available at the same time. If this occurs, the filters should be
152   // explicitly marked with a before/after relationship.
153   enum class Ordering : uint8_t { kTop, kDefault, kBottom };
OrderingToString(Ordering ordering)154   static const char* OrderingToString(Ordering ordering) {
155     switch (ordering) {
156       case Ordering::kTop:
157         return "Top";
158       case Ordering::kDefault:
159         return "Default";
160       case Ordering::kBottom:
161         return "Bottom";
162     }
163     return "Unknown";
164   }
165   template <typename Sink>
AbslStringify(Sink & sink,Ordering ordering)166   friend void AbslStringify(Sink& sink, Ordering ordering) {
167     sink.Append(OrderingToString(ordering));
168   };
169   friend std::ostream& operator<<(std::ostream& out, Ordering ordering) {
170     return out << OrderingToString(ordering);
171   }
172 
173   class FilterRegistration {
174    public:
175     // TODO(ctiller): Remove grpc_channel_filter* arg when that can be
176     // deprecated (once filter stack is removed).
FilterRegistration(UniqueTypeName name,const grpc_channel_filter * filter,FilterAdder filter_adder,SourceLocation registration_source)177     explicit FilterRegistration(UniqueTypeName name,
178                                 const grpc_channel_filter* filter,
179                                 FilterAdder filter_adder,
180                                 SourceLocation registration_source)
181         : name_(name),
182           filter_(filter),
183           filter_adder_(filter_adder),
184           registration_source_(registration_source) {}
185     FilterRegistration(const FilterRegistration&) = delete;
186     FilterRegistration& operator=(const FilterRegistration&) = delete;
187 
188     // Ensure that this filter is placed *after* the filters listed here.
189     // By Build() time all filters listed here must also be registered against
190     // the same channel stack type as this registration.
191     template <typename Filter>
After()192     FilterRegistration& After() {
193       return After({UniqueTypeNameFor<Filter>()});
194     }
195     // Ensure that this filter is placed *before* the filters listed here.
196     // By Build() time all filters listed here must also be registered against
197     // the same channel stack type as this registration.
198     template <typename Filter>
Before()199     FilterRegistration& Before() {
200       return Before({UniqueTypeNameFor<Filter>()});
201     }
202 
203     // Ensure that this filter is placed *after* the filters listed here.
204     // By Build() time all filters listed here must also be registered against
205     // the same channel stack type as this registration.
206     // TODO(ctiller): remove in favor of the version that does not mention
207     // grpc_channel_filter
208     FilterRegistration& After(std::initializer_list<UniqueTypeName> filters);
209     // Ensure that this filter is placed *before* the filters listed here.
210     // By Build() time all filters listed here must also be registered against
211     // the same channel stack type as this registration.
212     // TODO(ctiller): remove in favor of the version that does not mention
213     // grpc_channel_filter
214     FilterRegistration& Before(std::initializer_list<UniqueTypeName> filters);
215     // Add a predicate for this filters inclusion.
216     // If the predicate returns true the filter will be included in the stack.
217     // Predicates do not affect the ordering of the filter stack: we first
218     // topologically sort (once, globally) and only later apply predicates
219     // per-channel creation.
220     // Multiple predicates can be added to each registration.
221     FilterRegistration& If(InclusionPredicate predicate);
222     FilterRegistration& IfNot(InclusionPredicate predicate);
223     // Add a predicate that only includes this filter if a channel arg is
224     // present.
225     FilterRegistration& IfHasChannelArg(const char* arg);
226     // Add a predicate that only includes this filter if a boolean channel arg
227     // is true (with default_value being used if the argument is not present).
228     FilterRegistration& IfChannelArg(const char* arg, bool default_value);
229     // Mark this filter as being terminal.
230     // Exactly one terminal filter will be added at the end of each filter
231     // stack.
232     // If multiple are defined they are tried in registration order, and the
233     // first terminal filter whose predicates succeed is selected.
Terminal()234     FilterRegistration& Terminal() {
235       terminal_ = true;
236       return *this;
237     }
238     // Ensure this filter appears at the top of the stack.
239     // Effectively adds a 'Before' constraint on every other filter.
240     // Adding this to more than one filter will cause a loop.
BeforeAll()241     FilterRegistration& BeforeAll() {
242       before_all_ = true;
243       return *this;
244     }
245     // Add a predicate that ensures this filter does not appear in the minimal
246     // stack.
247     FilterRegistration& ExcludeFromMinimalStack();
SkipV3()248     FilterRegistration& SkipV3() {
249       CHECK_EQ(version_, Version::kAny);
250       version_ = Version::kV2;
251       return *this;
252     }
SkipV2()253     FilterRegistration& SkipV2() {
254       CHECK_EQ(version_, Version::kAny);
255       version_ = Version::kV3;
256       return *this;
257     }
258     // Request this filter be placed as high as possible in the stack (given
259     // before/after constraints).
FloatToTop()260     FilterRegistration& FloatToTop() {
261       CHECK_EQ(ordering_, Ordering::kDefault);
262       ordering_ = Ordering::kTop;
263       return *this;
264     }
265     // Request this filter be placed as low as possible in the stack (given
266     // before/after constraints).
SinkToBottom()267     FilterRegistration& SinkToBottom() {
268       CHECK_EQ(ordering_, Ordering::kDefault);
269       ordering_ = Ordering::kBottom;
270       return *this;
271     }
272 
273    private:
274     friend class ChannelInit;
275     const UniqueTypeName name_;
276     const grpc_channel_filter* const filter_;
277     const FilterAdder filter_adder_;
278     std::vector<UniqueTypeName> after_;
279     std::vector<UniqueTypeName> before_;
280     std::vector<InclusionPredicate> predicates_;
281     bool terminal_ = false;
282     bool before_all_ = false;
283     Version version_ = Version::kAny;
284     Ordering ordering_ = Ordering::kDefault;
285     SourceLocation registration_source_;
286   };
287 
288   class Builder {
289    public:
290     // Register a builder in the normal filter registration pass.
291     // This occurs first during channel build time.
292     // The FilterRegistration methods can be called to declaratively define
293     // properties of the filter being registered.
294     // TODO(ctiller): remove in favor of the version that does not mention
295     // grpc_channel_filter
296     FilterRegistration& RegisterFilter(grpc_channel_stack_type type,
297                                        UniqueTypeName name,
298                                        const grpc_channel_filter* filter,
299                                        FilterAdder filter_adder = nullptr,
300                                        SourceLocation registration_source = {});
301     FilterRegistration& RegisterFilter(
302         grpc_channel_stack_type type, const grpc_channel_filter* filter,
303         SourceLocation registration_source = {}) {
304       CHECK(filter != nullptr);
305       return RegisterFilter(type, NameFromChannelFilter(filter), filter,
306                             nullptr, registration_source);
307     }
308     template <typename Filter>
309     FilterRegistration& RegisterFilter(
310         grpc_channel_stack_type type, SourceLocation registration_source = {}) {
311       return RegisterFilter(
312           type, UniqueTypeNameFor<Filter>(), &Filter::kFilter,
313           [](InterceptionChainBuilder& builder) { builder.Add<Filter>(); },
314           registration_source);
315     }
316 
317     // Filter does not participate in v3
318     template <typename Filter>
319     FilterRegistration& RegisterV2Filter(
320         grpc_channel_stack_type type, SourceLocation registration_source = {}) {
321       return RegisterFilter(type, &Filter::kFilter, registration_source)
322           .SkipV3();
323     }
324 
325     // Register a post processor for the builder.
326     // These run after the main graph has been placed into the builder.
327     // At most one filter per slot per channel stack type can be added.
328     // If at all possible, prefer to use the RegisterFilter() mechanism to add
329     // filters to the system - this should be a last resort escape hatch.
RegisterPostProcessor(grpc_channel_stack_type type,PostProcessorSlot slot,PostProcessor post_processor)330     void RegisterPostProcessor(grpc_channel_stack_type type,
331                                PostProcessorSlot slot,
332                                PostProcessor post_processor) {
333       auto& slot_value = post_processors_[type][static_cast<int>(slot)];
334       CHECK(slot_value == nullptr);
335       slot_value = std::move(post_processor);
336     }
337 
338     /// Finalize registration.
339     ChannelInit Build();
340 
341    private:
342     std::vector<std::unique_ptr<FilterRegistration>>
343         filters_[GRPC_NUM_CHANNEL_STACK_TYPES];
344     PostProcessor post_processors_[GRPC_NUM_CHANNEL_STACK_TYPES]
345                                   [static_cast<int>(PostProcessorSlot::kCount)];
346   };
347 
348   /// Construct a channel stack of some sort: see channel_stack.h for details
349   /// \a builder is the channel stack builder to build into.
350   GRPC_MUST_USE_RESULT
351   bool CreateStack(ChannelStackBuilder* builder) const;
352 
353   void AddToInterceptionChainBuilder(grpc_channel_stack_type type,
354                                      InterceptionChainBuilder& builder) const;
355 
356  private:
357   // The type of object returned by a filter's Create method.
358   template <typename T>
359   using CreatedType =
360       typename decltype(T::Create(ChannelArgs(), {}))::value_type;
361 
362   class DependencyTracker;
363 
364   struct Filter {
FilterFilter365     Filter(UniqueTypeName name, const grpc_channel_filter* filter,
366            FilterAdder filter_adder, std::vector<InclusionPredicate> predicates,
367            Version version, Ordering ordering,
368            SourceLocation registration_source)
369         : name(name),
370           filter(filter),
371           filter_adder(filter_adder),
372           predicates(std::move(predicates)),
373           registration_source(registration_source),
374           version(version),
375           ordering(ordering) {}
376     UniqueTypeName name;
377     const grpc_channel_filter* filter;
378     const FilterAdder filter_adder;
379     std::vector<InclusionPredicate> predicates;
380     SourceLocation registration_source;
381     Version version;
382     Ordering ordering;
383     bool CheckPredicates(const ChannelArgs& args) const;
384   };
385   struct StackConfig {
386     std::vector<Filter> filters;
387     std::vector<Filter> terminators;
388     std::vector<PostProcessor> post_processors;
389   };
390 
391   StackConfig stack_configs_[GRPC_NUM_CHANNEL_STACK_TYPES];
392 
393   static StackConfig BuildStackConfig(
394       const std::vector<std::unique_ptr<FilterRegistration>>& registrations,
395       PostProcessor* post_processors, grpc_channel_stack_type type);
396   static void PrintChannelStackTrace(
397       grpc_channel_stack_type type,
398       const std::vector<std::unique_ptr<ChannelInit::FilterRegistration>>&
399           registrations,
400       const DependencyTracker& dependencies, const std::vector<Filter>& filters,
401       const std::vector<Filter>& terminal_filters);
402 };
403 
404 }  // namespace grpc_core
405 
406 #endif  // GRPC_SRC_CORE_LIB_SURFACE_CHANNEL_INIT_H
407