Line data Source code
1 : #pragma once 2 : 3 : #include <atomic> 4 : #include <chrono> 5 : #include <map> 6 : #include <memory> 7 : 8 : #include "envoy/common/exception.h" 9 : #include "envoy/extensions/wasm/v3/wasm.pb.validate.h" 10 : #include "envoy/http/filter.h" 11 : #include "envoy/server/lifecycle_notifier.h" 12 : #include "envoy/stats/scope.h" 13 : #include "envoy/stats/stats.h" 14 : #include "envoy/thread_local/thread_local_object.h" 15 : #include "envoy/upstream/cluster_manager.h" 16 : 17 : #include "source/common/common/assert.h" 18 : #include "source/common/common/logger.h" 19 : #include "source/common/config/datasource.h" 20 : #include "source/common/stats/symbol_table.h" 21 : #include "source/common/version/version.h" 22 : #include "source/extensions/common/wasm/context.h" 23 : #include "source/extensions/common/wasm/plugin.h" 24 : #include "source/extensions/common/wasm/stats_handler.h" 25 : #include "source/extensions/common/wasm/wasm_vm.h" 26 : 27 : #include "include/proxy-wasm/exports.h" 28 : #include "include/proxy-wasm/wasm.h" 29 : 30 : namespace Envoy { 31 : namespace Extensions { 32 : namespace Common { 33 : namespace Wasm { 34 : 35 : using CreateContextFn = 36 : std::function<ContextBase*(Wasm* wasm, const std::shared_ptr<Plugin>& plugin)>; 37 : 38 : class WasmHandle; 39 : 40 : // Wasm execution instance. Manages the Envoy side of the Wasm interface. 41 : class Wasm : public WasmBase, Logger::Loggable<Logger::Id::wasm> { 42 : public: 43 : Wasm(WasmConfig& config, absl::string_view vm_key, const Stats::ScopeSharedPtr& scope, 44 : Api::Api& api, Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher); 45 : Wasm(std::shared_ptr<WasmHandle> other, Event::Dispatcher& dispatcher); 46 : ~Wasm() override; 47 : 48 0 : Upstream::ClusterManager& clusterManager() const { return cluster_manager_; } 49 0 : Event::Dispatcher& dispatcher() { return dispatcher_; } 50 0 : Api::Api& api() { return api_; } 51 0 : Context* getRootContext(const std::shared_ptr<PluginBase>& plugin, bool allow_closed) { 52 0 : return static_cast<Context*>(WasmBase::getRootContext(plugin, allow_closed)); 53 0 : } 54 : void setTimerPeriod(uint32_t root_context_id, std::chrono::milliseconds period) override; 55 : virtual void tickHandler(uint32_t root_context_id); 56 0 : std::shared_ptr<Wasm> sharedThis() { return std::static_pointer_cast<Wasm>(shared_from_this()); } 57 0 : Network::DnsResolverSharedPtr& dnsResolver() { return dns_resolver_; } 58 : 59 : // WasmBase 60 : void error(std::string_view message) override; 61 : proxy_wasm::CallOnThreadFunction callOnThreadFunction() override; 62 : ContextBase* createContext(const std::shared_ptr<PluginBase>& plugin) override; 63 : ContextBase* createRootContext(const std::shared_ptr<PluginBase>& plugin) override; 64 : ContextBase* createVmContext() override; 65 : void registerCallbacks() override; 66 : void getFunctions() override; 67 : 68 : // AccessLog::Instance 69 : void log(const PluginSharedPtr& plugin, const Formatter::HttpFormatterContext& log_context, 70 : const StreamInfo::StreamInfo& info); 71 : 72 : void onStatsUpdate(const PluginSharedPtr& plugin, Envoy::Stats::MetricSnapshot& snapshot); 73 : 74 0 : virtual std::string buildVersion() { return BUILD_VERSION_NUMBER; } 75 : 76 : void initializeLifecycle(Server::ServerLifecycleNotifier& lifecycle_notifier); 77 0 : uint32_t nextDnsToken() { 78 0 : do { 79 0 : dns_token_++; 80 0 : } while (!dns_token_); 81 0 : return dns_token_; 82 0 : } 83 : 84 : void setCreateContextForTesting(CreateContextFn create_context, 85 0 : CreateContextFn create_root_context) { 86 0 : create_context_for_testing_ = create_context; 87 0 : create_root_context_for_testing_ = create_root_context; 88 0 : } 89 0 : void setFailStateForTesting(proxy_wasm::FailState fail_state) { failed_ = fail_state; } 90 : 91 : protected: 92 : friend class Context; 93 : 94 : void initializeStats(); 95 : // Calls into the VM. 96 : proxy_wasm::WasmCallVoid<3> on_resolve_dns_; 97 : proxy_wasm::WasmCallVoid<2> on_stats_update_; 98 : 99 : Stats::ScopeSharedPtr scope_; 100 : Api::Api& api_; 101 : Stats::StatNamePool stat_name_pool_; 102 : const Stats::StatName custom_stat_namespace_; 103 : Upstream::ClusterManager& cluster_manager_; 104 : Event::Dispatcher& dispatcher_; 105 : Event::PostCb server_shutdown_post_cb_; 106 : absl::flat_hash_map<uint32_t, Event::TimerPtr> timer_; // per root_id. 107 : TimeSource& time_source_; 108 : 109 : // Lifecycle stats 110 : LifecycleStatsHandler lifecycle_stats_handler_; 111 : 112 : // Plugin stats 113 : absl::flat_hash_map<uint32_t, Stats::Counter*> counters_; 114 : absl::flat_hash_map<uint32_t, Stats::Gauge*> gauges_; 115 : absl::flat_hash_map<uint32_t, Stats::Histogram*> histograms_; 116 : 117 : CreateContextFn create_context_for_testing_; 118 : CreateContextFn create_root_context_for_testing_; 119 : Network::DnsResolverSharedPtr dns_resolver_; 120 : uint32_t dns_token_ = 1; 121 : }; 122 : using WasmSharedPtr = std::shared_ptr<Wasm>; 123 : 124 : class WasmHandle : public WasmHandleBase, public ThreadLocal::ThreadLocalObject { 125 : public: 126 : explicit WasmHandle(const WasmSharedPtr& wasm) 127 0 : : WasmHandleBase(std::static_pointer_cast<WasmBase>(wasm)), wasm_(wasm) {} 128 : 129 0 : WasmSharedPtr& wasm() { return wasm_; } 130 : 131 : private: 132 : WasmSharedPtr wasm_; 133 : }; 134 : 135 : using WasmHandleSharedPtr = std::shared_ptr<WasmHandle>; 136 : 137 : class PluginHandle : public PluginHandleBase { 138 : public: 139 : explicit PluginHandle(const WasmHandleSharedPtr& wasm_handle, const PluginSharedPtr& plugin) 140 : : PluginHandleBase(std::static_pointer_cast<WasmHandleBase>(wasm_handle), 141 : std::static_pointer_cast<PluginBase>(plugin)), 142 4 : plugin_(plugin), wasm_handle_(wasm_handle) {} 143 : 144 0 : WasmHandleSharedPtr& wasmHandle() { return wasm_handle_; } 145 0 : uint32_t rootContextId() { return wasm_handle_->wasm()->getRootContext(plugin_, false)->id(); } 146 : 147 : private: 148 : PluginSharedPtr plugin_; 149 : WasmHandleSharedPtr wasm_handle_; 150 : }; 151 : 152 : using PluginHandleSharedPtr = std::shared_ptr<PluginHandle>; 153 : 154 : class PluginHandleSharedPtrThreadLocal : public ThreadLocal::ThreadLocalObject { 155 : public: 156 4 : PluginHandleSharedPtrThreadLocal(PluginHandleSharedPtr handle) : handle_(handle){}; 157 0 : PluginHandleSharedPtr& handle() { return handle_; } 158 : 159 : private: 160 : PluginHandleSharedPtr handle_; 161 : }; 162 : 163 : using CreateWasmCallback = std::function<void(WasmHandleSharedPtr)>; 164 : 165 : // Returns false if createWasm failed synchronously. This is necessary because xDS *MUST* report 166 : // all failures synchronously as it has no facility to report configuration update failures 167 : // asynchronously. Callers should throw an exception if they are part of a synchronous xDS update 168 : // because that is the mechanism for reporting configuration errors. 169 : bool createWasm(const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scope, 170 : Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager, 171 : Event::Dispatcher& dispatcher, Api::Api& api, 172 : Envoy::Server::ServerLifecycleNotifier& lifecycle_notifier, 173 : Config::DataSource::RemoteAsyncDataProviderPtr& remote_data_provider, 174 : CreateWasmCallback&& callback, 175 : CreateContextFn create_root_context_for_testing = nullptr); 176 : 177 : PluginHandleSharedPtr 178 : getOrCreateThreadLocalPlugin(const WasmHandleSharedPtr& base_wasm, const PluginSharedPtr& plugin, 179 : Event::Dispatcher& dispatcher, 180 : CreateContextFn create_root_context_for_testing = nullptr); 181 : 182 : void clearCodeCacheForTesting(); 183 : void setTimeOffsetForCodeCacheForTesting(MonotonicTime::duration d); 184 : WasmEvent toWasmEvent(const std::shared_ptr<WasmHandleBase>& wasm); 185 : 186 : } // namespace Wasm 187 : } // namespace Common 188 : } // namespace Extensions 189 : } // namespace Envoy