Skip to content

Commit 7edbc8d

Browse files
committed
dynamic_modules: add scheduler & HTTP callback API to bootstrap ABI
Signed-off-by: Rohit Agrawal <[email protected]>
1 parent 6c261a8 commit 7edbc8d

25 files changed

+508
-38
lines changed

source/extensions/access_loggers/dynamic_modules/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ envoy_cc_library(
3636
"//source/common/http:header_utility_lib",
3737
"//source/common/http:utility_lib",
3838
"//source/extensions/access_loggers/common:access_log_base",
39+
"//source/extensions/dynamic_modules:abi_impl",
3940
"//source/extensions/dynamic_modules:dynamic_modules_lib",
4041
],
4142
)

source/extensions/bootstrap/dynamic_modules/BUILD

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ envoy_cc_library(
1414
srcs = ["extension_config.cc"],
1515
hdrs = ["extension_config.h"],
1616
deps = [
17+
"//envoy/event:dispatcher_interface",
1718
"//source/common/common:assert_lib",
1819
"//source/extensions/dynamic_modules:dynamic_modules_lib",
1920
],
@@ -32,11 +33,21 @@ envoy_cc_library(
3233
],
3334
)
3435

36+
envoy_cc_library(
37+
name = "abi_impl",
38+
srcs = ["abi_impl.cc"],
39+
deps = [
40+
":extension_config_lib",
41+
"//source/extensions/dynamic_modules:dynamic_modules_lib",
42+
],
43+
)
44+
3545
envoy_cc_extension(
3646
name = "config",
3747
srcs = ["factory.cc"],
3848
hdrs = ["factory.h"],
3949
deps = [
50+
":abi_impl",
4051
":extension_lib",
4152
"//envoy/registry",
4253
"//envoy/server:bootstrap_extension_config_interface",
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// NOLINT(namespace-envoy)
2+
3+
// This file provides host-side implementations for ABI callbacks specific to bootstrap extensions.
4+
5+
#include "source/extensions/bootstrap/dynamic_modules/extension_config.h"
6+
#include "source/extensions/dynamic_modules/abi.h"
7+
8+
using Envoy::Extensions::Bootstrap::DynamicModules::DynamicModuleBootstrapExtensionConfig;
9+
using Envoy::Extensions::Bootstrap::DynamicModules::DynamicModuleBootstrapExtensionConfigScheduler;
10+
11+
extern "C" {
12+
13+
envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr
14+
envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_new(
15+
envoy_dynamic_module_type_bootstrap_extension_config_envoy_ptr extension_config_envoy_ptr) {
16+
auto* config = static_cast<DynamicModuleBootstrapExtensionConfig*>(extension_config_envoy_ptr);
17+
return new DynamicModuleBootstrapExtensionConfigScheduler(config->weak_from_this(),
18+
config->main_thread_dispatcher_);
19+
}
20+
21+
void envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_delete(
22+
envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr
23+
scheduler_module_ptr) {
24+
delete static_cast<DynamicModuleBootstrapExtensionConfigScheduler*>(scheduler_module_ptr);
25+
}
26+
27+
void envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_commit(
28+
envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr scheduler_module_ptr,
29+
uint64_t event_id) {
30+
auto* scheduler =
31+
static_cast<DynamicModuleBootstrapExtensionConfigScheduler*>(scheduler_module_ptr);
32+
scheduler->commit(event_id);
33+
}
34+
35+
} // extern "C"

source/extensions/bootstrap/dynamic_modules/extension_config.cc

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ namespace DynamicModules {
99

1010
DynamicModuleBootstrapExtensionConfig::DynamicModuleBootstrapExtensionConfig(
1111
const absl::string_view extension_name, const absl::string_view extension_config,
12-
Extensions::DynamicModules::DynamicModulePtr dynamic_module)
13-
: dynamic_module_(std::move(dynamic_module)) {
12+
Extensions::DynamicModules::DynamicModulePtr dynamic_module,
13+
Event::Dispatcher& main_thread_dispatcher)
14+
: dynamic_module_(std::move(dynamic_module)), main_thread_dispatcher_(main_thread_dispatcher) {
1415
ASSERT(dynamic_module_ != nullptr);
1516
ASSERT(extension_name.data() != nullptr);
1617
ASSERT(extension_config.data() != nullptr);
@@ -22,10 +23,17 @@ DynamicModuleBootstrapExtensionConfig::~DynamicModuleBootstrapExtensionConfig()
2223
}
2324
}
2425

26+
void DynamicModuleBootstrapExtensionConfig::onScheduled(uint64_t event_id) {
27+
if (in_module_config_ != nullptr && on_bootstrap_extension_config_scheduled_ != nullptr) {
28+
on_bootstrap_extension_config_scheduled_(thisAsVoidPtr(), in_module_config_, event_id);
29+
}
30+
}
31+
2532
absl::StatusOr<DynamicModuleBootstrapExtensionConfigSharedPtr>
2633
newDynamicModuleBootstrapExtensionConfig(
2734
const absl::string_view extension_name, const absl::string_view extension_config,
28-
Extensions::DynamicModules::DynamicModulePtr dynamic_module) {
35+
Extensions::DynamicModules::DynamicModulePtr dynamic_module,
36+
Event::Dispatcher& main_thread_dispatcher) {
2937

3038
// Resolve the required symbols from the dynamic module.
3139
auto constructor =
@@ -69,8 +77,15 @@ newDynamicModuleBootstrapExtensionConfig(
6977
return on_extension_destroy.status();
7078
}
7179

80+
auto on_config_scheduled =
81+
dynamic_module->getFunctionPointer<OnBootstrapExtensionConfigScheduledType>(
82+
"envoy_dynamic_module_on_bootstrap_extension_config_scheduled");
83+
if (!on_config_scheduled.ok()) {
84+
return on_config_scheduled.status();
85+
}
86+
7287
auto config = std::make_shared<DynamicModuleBootstrapExtensionConfig>(
73-
extension_name, extension_config, std::move(dynamic_module));
88+
extension_name, extension_config, std::move(dynamic_module), main_thread_dispatcher);
7489

7590
const void* extension_config_module_ptr = (*constructor.value())(
7691
static_cast<void*>(config.get()), {extension_name.data(), extension_name.size()},
@@ -85,6 +100,7 @@ newDynamicModuleBootstrapExtensionConfig(
85100
config->on_bootstrap_extension_server_initialized_ = on_server_initialized.value();
86101
config->on_bootstrap_extension_worker_thread_initialized_ = on_worker_thread_initialized.value();
87102
config->on_bootstrap_extension_destroy_ = on_extension_destroy.value();
103+
config->on_bootstrap_extension_config_scheduled_ = on_config_scheduled.value();
88104

89105
return config;
90106
}

source/extensions/bootstrap/dynamic_modules/extension_config.h

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <string>
44

5+
#include "envoy/event/dispatcher.h"
6+
57
#include "source/extensions/dynamic_modules/abi.h"
68
#include "source/extensions/dynamic_modules/dynamic_modules.h"
79

@@ -19,27 +21,43 @@ using OnBootstrapExtensionWorkerThreadInitializedType =
1921
decltype(&envoy_dynamic_module_on_bootstrap_extension_worker_thread_initialized);
2022
using OnBootstrapExtensionDestroyType =
2123
decltype(&envoy_dynamic_module_on_bootstrap_extension_destroy);
24+
using OnBootstrapExtensionConfigScheduledType =
25+
decltype(&envoy_dynamic_module_on_bootstrap_extension_config_scheduled);
2226

2327
class DynamicModuleBootstrapExtension;
2428

2529
/**
2630
* A config to create bootstrap extensions based on a dynamic module. This will be owned by the
2731
* bootstrap extension. This resolves and holds the symbols used for the bootstrap extension.
2832
*/
29-
class DynamicModuleBootstrapExtensionConfig {
33+
class DynamicModuleBootstrapExtensionConfig
34+
: public std::enable_shared_from_this<DynamicModuleBootstrapExtensionConfig> {
3035
public:
3136
/**
3237
* Constructor for the config.
3338
* @param extension_name the name of the extension.
3439
* @param extension_config the configuration for the module.
3540
* @param dynamic_module the dynamic module to use.
41+
* @param main_thread_dispatcher the main thread dispatcher.
3642
*/
37-
DynamicModuleBootstrapExtensionConfig(
38-
const absl::string_view extension_name, const absl::string_view extension_config,
39-
Extensions::DynamicModules::DynamicModulePtr dynamic_module);
43+
DynamicModuleBootstrapExtensionConfig(const absl::string_view extension_name,
44+
const absl::string_view extension_config,
45+
Extensions::DynamicModules::DynamicModulePtr dynamic_module,
46+
Event::Dispatcher& main_thread_dispatcher);
4047

4148
~DynamicModuleBootstrapExtensionConfig();
4249

50+
/**
51+
* This is called when an event is scheduled via
52+
* DynamicModuleBootstrapExtensionConfigScheduler::commit.
53+
*/
54+
void onScheduled(uint64_t event_id);
55+
56+
/**
57+
* Helper to get the `this` pointer as a void pointer.
58+
*/
59+
void* thisAsVoidPtr() { return static_cast<void*>(this); }
60+
4361
// The corresponding in-module configuration.
4462
envoy_dynamic_module_type_bootstrap_extension_config_module_ptr in_module_config_ = nullptr;
4563

@@ -52,26 +70,60 @@ class DynamicModuleBootstrapExtensionConfig {
5270
OnBootstrapExtensionWorkerThreadInitializedType
5371
on_bootstrap_extension_worker_thread_initialized_ = nullptr;
5472
OnBootstrapExtensionDestroyType on_bootstrap_extension_destroy_ = nullptr;
73+
OnBootstrapExtensionConfigScheduledType on_bootstrap_extension_config_scheduled_ = nullptr;
5574

5675
// The dynamic module.
5776
Extensions::DynamicModules::DynamicModulePtr dynamic_module_;
77+
78+
// The main thread dispatcher.
79+
Event::Dispatcher& main_thread_dispatcher_;
5880
};
5981

6082
using DynamicModuleBootstrapExtensionConfigSharedPtr =
6183
std::shared_ptr<DynamicModuleBootstrapExtensionConfig>;
6284

85+
/**
86+
* This class is used to schedule a bootstrap extension config event hook from a different thread
87+
* than the main thread. This is created via
88+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_new and deleted via
89+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_delete.
90+
*/
91+
class DynamicModuleBootstrapExtensionConfigScheduler {
92+
public:
93+
DynamicModuleBootstrapExtensionConfigScheduler(
94+
std::weak_ptr<DynamicModuleBootstrapExtensionConfig> config, Event::Dispatcher& dispatcher)
95+
: config_(std::move(config)), dispatcher_(dispatcher) {}
96+
97+
void commit(uint64_t event_id) {
98+
dispatcher_.post([config = config_, event_id]() {
99+
if (std::shared_ptr<DynamicModuleBootstrapExtensionConfig> config_shared = config.lock()) {
100+
config_shared->onScheduled(event_id);
101+
}
102+
});
103+
}
104+
105+
private:
106+
// The config that this scheduler is associated with. Using a weak pointer to avoid unnecessarily
107+
// extending the lifetime of the config.
108+
std::weak_ptr<DynamicModuleBootstrapExtensionConfig> config_;
109+
// The dispatcher is used to post the event to the main thread.
110+
Event::Dispatcher& dispatcher_;
111+
};
112+
63113
/**
64114
* Creates a new DynamicModuleBootstrapExtensionConfig from the given module and configuration.
65115
* @param extension_name the name of the extension.
66116
* @param extension_config the configuration for the module.
67117
* @param dynamic_module the dynamic module to use.
118+
* @param main_thread_dispatcher the main thread dispatcher.
68119
* @return an error status if the module could not be loaded or the configuration could not be
69120
* created, or a shared pointer to the config.
70121
*/
71122
absl::StatusOr<DynamicModuleBootstrapExtensionConfigSharedPtr>
72123
newDynamicModuleBootstrapExtensionConfig(
73124
const absl::string_view extension_name, const absl::string_view extension_config,
74-
Extensions::DynamicModules::DynamicModulePtr dynamic_module);
125+
Extensions::DynamicModules::DynamicModulePtr dynamic_module,
126+
Event::Dispatcher& main_thread_dispatcher);
75127

76128
} // namespace DynamicModules
77129
} // namespace Bootstrap

source/extensions/bootstrap/dynamic_modules/factory.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ Server::BootstrapExtensionPtr DynamicModuleBootstrapExtensionFactory::createBoot
3939
}
4040

4141
auto extension_config = newDynamicModuleBootstrapExtensionConfig(
42-
proto_config.extension_name(), extension_config_str, std::move(dynamic_module.value()));
42+
proto_config.extension_name(), extension_config_str, std::move(dynamic_module.value()),
43+
context.mainThreadDispatcher());
4344

4445
if (!extension_config.ok()) {
4546
throwEnvoyExceptionOrPanic("Failed to create extension config: " +

source/extensions/dynamic_modules/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ envoy_cc_library(
2727
srcs = ["abi_impl.cc"],
2828
deps = [
2929
":dynamic_modules_lib",
30+
"//source/common/common:assert_lib",
3031
"//source/common/common:logger_lib",
3132
],
3233
)

source/extensions/dynamic_modules/abi.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4979,6 +4979,20 @@ typedef void* envoy_dynamic_module_type_bootstrap_extension_envoy_ptr;
49794979
*/
49804980
typedef const void* envoy_dynamic_module_type_bootstrap_extension_module_ptr;
49814981

4982+
/**
4983+
* envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr is a raw pointer to
4984+
* the DynamicModuleBootstrapExtensionConfigScheduler class in Envoy.
4985+
*
4986+
* OWNERSHIP: The allocation is done by Envoy but the module is responsible for managing the
4987+
* lifetime of the pointer. Notably, it must be explicitly destroyed by the module
4988+
* when scheduling the bootstrap extension config event is done. The creation of this pointer is
4989+
* done by envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_new and the scheduling
4990+
* and destruction is done by
4991+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_delete. Since its lifecycle is
4992+
* owned/managed by the module, this has _module_ptr suffix.
4993+
*/
4994+
typedef void* envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr;
4995+
49824996
// =============================================================================
49834997
// Bootstrap Extension Event Hooks
49844998
// =============================================================================
@@ -5060,6 +5074,76 @@ void envoy_dynamic_module_on_bootstrap_extension_worker_thread_initialized(
50605074
void envoy_dynamic_module_on_bootstrap_extension_destroy(
50615075
envoy_dynamic_module_type_bootstrap_extension_module_ptr extension_module_ptr);
50625076

5077+
/**
5078+
* envoy_dynamic_module_on_bootstrap_extension_config_scheduled is called when the bootstrap
5079+
* extension configuration is scheduled to be executed on the main thread with
5080+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_commit callback.
5081+
*
5082+
* @param extension_config_envoy_ptr is the pointer to the DynamicModuleBootstrapExtensionConfig
5083+
* object.
5084+
* @param extension_config_ptr is the pointer to the in-module bootstrap extension configuration
5085+
* created by envoy_dynamic_module_on_bootstrap_extension_config_new.
5086+
* @param event_id is the ID of the event passed to
5087+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_commit.
5088+
*/
5089+
void envoy_dynamic_module_on_bootstrap_extension_config_scheduled(
5090+
envoy_dynamic_module_type_bootstrap_extension_config_envoy_ptr extension_config_envoy_ptr,
5091+
envoy_dynamic_module_type_bootstrap_extension_config_module_ptr extension_config_ptr,
5092+
uint64_t event_id);
5093+
5094+
// =============================================================================
5095+
// Bootstrap Extension Callbacks
5096+
// =============================================================================
5097+
5098+
/**
5099+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_new is called by the module
5100+
* to create a new bootstrap extension configuration scheduler. The scheduler is used to dispatch
5101+
* bootstrap extension configuration operations to the main thread from any thread including the
5102+
* ones managed by the module.
5103+
*
5104+
* @param extension_config_envoy_ptr is the pointer to the DynamicModuleBootstrapExtensionConfig
5105+
* object.
5106+
* @return envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr is the pointer
5107+
* to the created bootstrap extension configuration scheduler.
5108+
*
5109+
* NOTE: it is caller's responsibility to delete the scheduler using
5110+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_delete when it is no longer
5111+
* needed. See the comment on
5112+
* envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr.
5113+
*/
5114+
envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr
5115+
envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_new(
5116+
envoy_dynamic_module_type_bootstrap_extension_config_envoy_ptr extension_config_envoy_ptr);
5117+
5118+
/**
5119+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_delete is called by the
5120+
* module to delete the bootstrap extension configuration scheduler created by
5121+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_new.
5122+
*
5123+
* @param scheduler_module_ptr is the pointer to the bootstrap extension configuration scheduler
5124+
* created by envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_new.
5125+
*/
5126+
void envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_delete(
5127+
envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr scheduler_module_ptr);
5128+
5129+
/**
5130+
* envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_commit is called by the
5131+
* module to schedule a generic event to the bootstrap extension configuration on the main thread.
5132+
*
5133+
* This will eventually end up invoking envoy_dynamic_module_on_bootstrap_extension_config_scheduled
5134+
* event hook on the main thread.
5135+
*
5136+
* This can be called multiple times to schedule multiple events to the same configuration.
5137+
*
5138+
* @param scheduler_module_ptr is the pointer to the bootstrap extension configuration scheduler
5139+
* created by envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_new.
5140+
* @param event_id is the ID of the event. This can be used to differentiate between multiple
5141+
* events scheduled to the same configuration. It can be any module-defined value.
5142+
*/
5143+
void envoy_dynamic_module_callback_bootstrap_extension_config_scheduler_commit(
5144+
envoy_dynamic_module_type_bootstrap_extension_config_scheduler_module_ptr scheduler_module_ptr,
5145+
uint64_t event_id);
5146+
50635147
#ifdef __cplusplus
50645148
}
50655149
#endif

0 commit comments

Comments
 (0)