xref: /aosp_15_r20/external/grpc-grpc/src/core/lib/surface/channel_init.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 
24 #include <stdint.h>
25 
26 #include <initializer_list>
27 #include <memory>
28 #include <utility>
29 #include <vector>
30 
31 #include "absl/functional/any_invocable.h"
32 
33 #include <grpc/support/log.h>
34 
35 #include "src/core/lib/channel/channel_args.h"
36 #include "src/core/lib/channel/channel_fwd.h"
37 #include "src/core/lib/channel/channel_stack_builder.h"
38 #include "src/core/lib/gprpp/debug_location.h"
39 #include "src/core/lib/surface/channel_stack_type.h"
40 #include "src/core/lib/transport/call_filters.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 const char* (*NameFromChannelFilter)(const grpc_channel_filter*);
64 
65 class ChannelInit {
66  public:
67   // Predicate for if a filter registration applies
68   using InclusionPredicate = absl::AnyInvocable<bool(const ChannelArgs&) const>;
69   // Post processor for the channel stack - applied in PostProcessorSlot order
70   using PostProcessor = absl::AnyInvocable<void(ChannelStackBuilder&) const>;
71   // Post processing slots - up to one PostProcessor per slot can be registered
72   // They run after filters registered are added to the channel stack builder,
73   // but before Build is called - allowing ad-hoc mutation to the channel stack.
74   enum class PostProcessorSlot : uint8_t {
75     kAuthSubstitution,
76     kXdsChannelStackModifier,
77     kCount
78   };
79 
80   // Vtable-like data structure for channel data initialization
81   struct ChannelFilterVtable {
82     size_t size;
83     size_t alignment;
84     absl::Status (*init)(void* data, const ChannelArgs& args);
85     void (*destroy)(void* data);
86     void (*add_to_stack_builder)(void* data,
87                                  CallFilters::StackBuilder& builder);
88   };
89 
90   class FilterRegistration {
91    public:
92     // TODO(ctiller): Remove grpc_channel_filter* arg when that can be
93     // deprecated (once filter stack is removed).
FilterRegistration(const grpc_channel_filter * filter,const ChannelFilterVtable * vtable,SourceLocation registration_source)94     explicit FilterRegistration(const grpc_channel_filter* filter,
95                                 const ChannelFilterVtable* vtable,
96                                 SourceLocation registration_source)
97         : filter_(filter),
98           vtable_(vtable),
99           registration_source_(registration_source) {}
100     FilterRegistration(const FilterRegistration&) = delete;
101     FilterRegistration& operator=(const FilterRegistration&) = delete;
102 
103     // Ensure that this filter is placed *after* the filters listed here.
104     // By Build() time all filters listed here must also be registered against
105     // the same channel stack type as this registration.
106     template <typename Filter>
After()107     FilterRegistration& After() {
108       return After({&Filter::kFilter});
109     }
110     // Ensure that this filter is placed *before* the filters listed here.
111     // By Build() time all filters listed here must also be registered against
112     // the same channel stack type as this registration.
113     template <typename Filter>
Before()114     FilterRegistration& Before() {
115       return Before({&Filter::kFilter});
116     }
117 
118     // Ensure that this filter is placed *after* the filters listed here.
119     // By Build() time all filters listed here must also be registered against
120     // the same channel stack type as this registration.
121     // TODO(ctiller): remove in favor of the version that does not mention
122     // grpc_channel_filter
123     FilterRegistration& After(
124         std::initializer_list<const grpc_channel_filter*> filters);
125     // Ensure that this filter is placed *before* the filters listed here.
126     // By Build() time all filters listed here must also be registered against
127     // the same channel stack type as this registration.
128     // TODO(ctiller): remove in favor of the version that does not mention
129     // grpc_channel_filter
130     FilterRegistration& Before(
131         std::initializer_list<const grpc_channel_filter*> filters);
132     // Add a predicate for this filters inclusion.
133     // If the predicate returns true the filter will be included in the stack.
134     // Predicates do not affect the ordering of the filter stack: we first
135     // topologically sort (once, globally) and only later apply predicates
136     // per-channel creation.
137     // Multiple predicates can be added to each registration.
138     FilterRegistration& If(InclusionPredicate predicate);
139     FilterRegistration& IfNot(InclusionPredicate predicate);
140     // Add a predicate that only includes this filter if a channel arg is
141     // present.
142     FilterRegistration& IfHasChannelArg(const char* arg);
143     // Add a predicate that only includes this filter if a boolean channel arg
144     // is true (with default_value being used if the argument is not present).
145     FilterRegistration& IfChannelArg(const char* arg, bool default_value);
146     // Mark this filter as being terminal.
147     // Exactly one terminal filter will be added at the end of each filter
148     // stack.
149     // If multiple are defined they are tried in registration order, and the
150     // first terminal filter whos predicates succeed is selected.
Terminal()151     FilterRegistration& Terminal() {
152       terminal_ = true;
153       return *this;
154     }
155     // Ensure this filter appears at the top of the stack.
156     // Effectively adds a 'Before' constraint on every other filter.
157     // Adding this to more than one filter will cause a loop.
BeforeAll()158     FilterRegistration& BeforeAll() {
159       before_all_ = true;
160       return *this;
161     }
162     // Add a predicate that ensures this filter does not appear in the minimal
163     // stack.
164     FilterRegistration& ExcludeFromMinimalStack();
SkipV3()165     FilterRegistration& SkipV3() {
166       skip_v3_ = true;
167       return *this;
168     }
169 
170    private:
171     friend class ChannelInit;
172     const grpc_channel_filter* const filter_;
173     const ChannelFilterVtable* const vtable_;
174     std::vector<const grpc_channel_filter*> after_;
175     std::vector<const grpc_channel_filter*> before_;
176     std::vector<InclusionPredicate> predicates_;
177     bool terminal_ = false;
178     bool before_all_ = false;
179     bool skip_v3_ = false;
180     SourceLocation registration_source_;
181   };
182 
183   class Builder {
184    public:
185     // Register a builder in the normal filter registration pass.
186     // This occurs first during channel build time.
187     // The FilterRegistration methods can be called to declaratively define
188     // properties of the filter being registered.
189     // TODO(ctiller): remove in favor of the version that does not mention
190     // grpc_channel_filter
191     FilterRegistration& RegisterFilter(
192         grpc_channel_stack_type type, const grpc_channel_filter* filter,
193         const ChannelFilterVtable* vtable = nullptr,
194         SourceLocation registration_source = {});
195     template <typename Filter>
196     FilterRegistration& RegisterFilter(
197         grpc_channel_stack_type type, SourceLocation registration_source = {}) {
198       return RegisterFilter(type, &Filter::kFilter,
199                             VtableForType<Filter>::vtable(),
200                             registration_source);
201     }
202 
203     // Filter does not participate in v3
204     template <typename Filter>
205     FilterRegistration& RegisterV2Filter(
206         grpc_channel_stack_type type, SourceLocation registration_source = {}) {
207       return RegisterFilter(type, &Filter::kFilter, nullptr,
208                             registration_source)
209           .SkipV3();
210     }
211 
212     // Register a post processor for the builder.
213     // These run after the main graph has been placed into the builder.
214     // At most one filter per slot per channel stack type can be added.
215     // If at all possible, prefer to use the RegisterFilter() mechanism to add
216     // filters to the system - this should be a last resort escape hatch.
RegisterPostProcessor(grpc_channel_stack_type type,PostProcessorSlot slot,PostProcessor post_processor)217     void RegisterPostProcessor(grpc_channel_stack_type type,
218                                PostProcessorSlot slot,
219                                PostProcessor post_processor) {
220       auto& slot_value = post_processors_[type][static_cast<int>(slot)];
221       GPR_ASSERT(slot_value == nullptr);
222       slot_value = std::move(post_processor);
223     }
224 
225     /// Finalize registration.
226     ChannelInit Build();
227 
228    private:
229     std::vector<std::unique_ptr<FilterRegistration>>
230         filters_[GRPC_NUM_CHANNEL_STACK_TYPES];
231     PostProcessor post_processors_[GRPC_NUM_CHANNEL_STACK_TYPES]
232                                   [static_cast<int>(PostProcessorSlot::kCount)];
233   };
234 
235   // A set of channel filters that can be added to a call stack.
236   // TODO(ctiller): move this out so it can be used independently of
237   // the global registration mechanisms.
238   class StackSegment final {
239    public:
240     // Registration of one channel filter in the stack.
241     struct ChannelFilter {
242       size_t offset;
243       const ChannelFilterVtable* vtable;
244     };
245 
246     StackSegment() = default;
247     explicit StackSegment(std::vector<ChannelFilter> filters,
248                           uint8_t* channel_data);
249     StackSegment(const StackSegment& other) = delete;
250     StackSegment& operator=(const StackSegment& other) = delete;
251     StackSegment(StackSegment&& other) noexcept = default;
252     StackSegment& operator=(StackSegment&& other) = default;
253 
254     // Add this segment to a call filter stack builder
255     void AddToCallFilterStack(CallFilters::StackBuilder& builder);
256 
257    private:
258     // Combined channel data for the stack
259     class ChannelData : public RefCounted<ChannelData> {
260      public:
261       explicit ChannelData(std::vector<ChannelFilter> filters,
262                            uint8_t* channel_data);
263       ~ChannelData() override;
264 
265       void AddToCallFilterStack(CallFilters::StackBuilder& builder);
266 
267      private:
268       std::vector<ChannelFilter> filters_;
269       uint8_t* channel_data_;
270     };
271 
272     RefCountedPtr<ChannelData> data_;
273   };
274 
275   /// Construct a channel stack of some sort: see channel_stack.h for details
276   /// \a builder is the channel stack builder to build into.
277   GRPC_MUST_USE_RESULT
278   bool CreateStack(ChannelStackBuilder* builder) const;
279 
280   // Create a segment of a channel stack.
281   // Terminators and post processors are not included in this construction:
282   // terminators are a legacy filter-stack concept, and post processors
283   // need to migrate to other mechanisms.
284   // TODO(ctiller): figure out other mechanisms.
285   absl::StatusOr<StackSegment> CreateStackSegment(
286       grpc_channel_stack_type type, const ChannelArgs& args) const;
287 
288  private:
289   struct Filter {
FilterFilter290     Filter(const grpc_channel_filter* filter, const ChannelFilterVtable* vtable,
291            std::vector<InclusionPredicate> predicates, bool skip_v3,
292            SourceLocation registration_source)
293         : filter(filter),
294           vtable(vtable),
295           predicates(std::move(predicates)),
296           registration_source(registration_source),
297           skip_v3(skip_v3) {}
298     const grpc_channel_filter* filter;
299     const ChannelFilterVtable* vtable;
300     std::vector<InclusionPredicate> predicates;
301     SourceLocation registration_source;
302     bool skip_v3 = false;
303     bool CheckPredicates(const ChannelArgs& args) const;
304   };
305   struct StackConfig {
306     std::vector<Filter> filters;
307     std::vector<Filter> terminators;
308     std::vector<PostProcessor> post_processors;
309   };
310 
311   template <typename T, typename = void>
312   struct VtableForType {
vtableVtableForType313     static const ChannelFilterVtable* vtable() { return nullptr; }
314   };
315 
316   template <typename T>
317   struct VtableForType<T, absl::void_t<typename T::Call>> {
318     static const ChannelFilterVtable kVtable;
319     static const ChannelFilterVtable* vtable() { return &kVtable; }
320   };
321 
322   StackConfig stack_configs_[GRPC_NUM_CHANNEL_STACK_TYPES];
323 
324   static StackConfig BuildStackConfig(
325       const std::vector<std::unique_ptr<FilterRegistration>>& registrations,
326       PostProcessor* post_processors, grpc_channel_stack_type type);
327 };
328 
329 template <typename T>
330 const ChannelInit::ChannelFilterVtable
331     ChannelInit::VtableForType<T, absl::void_t<typename T::Call>>::kVtable = {
332         sizeof(T), alignof(T),
333         [](void* data, const ChannelArgs& args) -> absl::Status {
334           // TODO(ctiller): fill in ChannelFilter::Args (2nd arg)
335           absl::StatusOr<T> r = T::Create(args, {});
336           if (!r.ok()) return r.status();
337           new (data) T(std::move(*r));
338           return absl::OkStatus();
339         },
340         [](void* data) { static_cast<T*>(data)->~T(); },
341         [](void* data, CallFilters::StackBuilder& builder) {
342           builder.Add(static_cast<T*>(data));
343         }};
344 
345 }  // namespace grpc_core
346 
347 #endif  // GRPC_SRC_CORE_LIB_SURFACE_CHANNEL_INIT_H
348