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