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