Skip to content

Support multiple versions of the Proxy-Wasm ABI. #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/proxy-wasm/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ class ContextBase : public RootInterface,
t += tpe.tv_nsec;
return t;
}
std::string_view getConfiguration() override {
unimplemented();
return "";
}
std::pair<uint32_t, std::string_view> getStatus() override {
unimplemented();
return std::make_pair(1, "unimplmemented");
Expand Down Expand Up @@ -316,6 +320,7 @@ class ContextBase : public RootInterface,
std::string_view /* details */) override {
return unimplemented();
}
void clearRouteCache() override { unimplemented(); }
void failStream(WasmStreamType stream_type) override { closeStream(stream_type); }

// Shared Data
Expand Down
6 changes: 6 additions & 0 deletions include/proxy-wasm/context_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ struct HttpInterface {
Pairs additional_headers, uint32_t grpc_status,
std::string_view details) = 0;

// Clears the route cache for the current request.
virtual void clearRouteCache() = 0;

// Call when the stream closes. See RootInterface.
virtual bool onDone() = 0;

Expand Down Expand Up @@ -551,6 +554,9 @@ struct GeneralInterface {
// Provides the current time in nanoseconds since the Unix epoch.
virtual uint64_t getCurrentTimeNanoseconds() = 0;

// Returns plugin configuration.
virtual std::string_view getConfiguration() = 0;

/**
* Provides the status of the last call into the VM or out of the VM, similar to errno.
* @return the status code and a descriptive string.
Expand Down
4 changes: 4 additions & 0 deletions include/proxy-wasm/exports.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,22 @@ namespace exports {

// ABI functions exported from envoy to wasm.

Word get_configuration(void *raw_context, Word address, Word size);
Word get_status(void *raw_context, Word status_code, Word address, Word size);
Word log(void *raw_context, Word level, Word address, Word size);
Word get_log_level(void *raw_context, Word result_level_uint32_ptr);
Word get_property(void *raw_context, Word path_ptr, Word path_size, Word value_ptr_ptr,
Word value_size_ptr);
Word set_property(void *raw_context, Word key_ptr, Word key_size, Word value_ptr, Word value_size);
Word continue_request(void *raw_context);
Word continue_response(void *raw_context);
Word continue_stream(void *raw_context, Word stream_type);
Word close_stream(void *raw_context, Word stream_type);
Word send_local_response(void *raw_context, Word response_code, Word response_code_details_ptr,
Word response_code_details_size, Word body_ptr, Word body_size,
Word additional_response_header_pairs_ptr,
Word additional_response_header_pairs_size, Word grpc_status);
Word clear_route_cache(void *raw_context);
Word get_shared_data(void *raw_context, Word key_ptr, Word key_size, Word value_ptr_ptr,
Word value_size_ptr, Word cas_ptr);
Word set_shared_data(void *raw_context, Word key_ptr, Word key_size, Word value_ptr,
Expand Down
1 change: 1 addition & 0 deletions include/proxy-wasm/null_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace proxy_wasm {
*/
struct NullPluginRegistry {
void (*proxy_abi_version_0_1_0_)() = nullptr;
void (*proxy_abi_version_0_2_0_)() = nullptr;
void (*proxy_on_log_)(uint32_t context_id) = nullptr;
uint32_t (*proxy_validate_configuration_)(uint32_t root_context_id,
uint32_t plugin_configuration_size) = nullptr;
Expand Down
1 change: 1 addition & 0 deletions include/proxy-wasm/null_vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct NullVm : public WasmVm {
Cloneable cloneable() override { return Cloneable::InstantiatedModule; };
std::unique_ptr<WasmVm> clone() override;
bool load(const std::string &code, bool allow_precompiled) override;
AbiVersion getAbiVersion() override;
bool link(std::string_view debug_name) override;
uint64_t getMemorySize() override;
std::optional<std::string_view> getMemory(uint64_t pointer, uint64_t size) override;
Expand Down
13 changes: 9 additions & 4 deletions include/proxy-wasm/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
virtual void error(std::string_view message) { std::cerr << message << "\n"; }
virtual void unimplemented() { error("unimplemented proxy-wasm API"); }

AbiVersion abiVersion() { return abi_version_; }

bool getEmscriptenVersion(uint32_t *emscripten_metadata_major_version,
uint32_t *emscripten_metadata_minor_version,
uint32_t *emscripten_abi_major_version,
Expand Down Expand Up @@ -184,8 +186,6 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
std::unique_ptr<ShutdownHandle> shutdown_handle_;
std::unordered_set<ContextBase *> pending_done_; // Root contexts not done during shutdown.

WasmCallVoid<0> abi_version_0_1_0_;

WasmCallVoid<0> _start_; /* Emscripten v1.39.0+ */
WasmCallVoid<0> __wasm_call_ctors_;

Expand All @@ -205,12 +205,14 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
WasmCallVoid<2> on_downstream_connection_close_;
WasmCallVoid<2> on_upstream_connection_close_;

WasmCallWord<3> on_request_headers_;
WasmCallWord<2> on_request_headers_abi_01_;
WasmCallWord<3> on_request_headers_abi_02_;
WasmCallWord<3> on_request_body_;
WasmCallWord<2> on_request_trailers_;
WasmCallWord<2> on_request_metadata_;

WasmCallWord<3> on_response_headers_;
WasmCallWord<2> on_response_headers_abi_01_;
WasmCallWord<3> on_response_headers_abi_02_;
WasmCallWord<3> on_response_body_;
WasmCallWord<2> on_response_trailers_;
WasmCallWord<2> on_response_metadata_;
Expand Down Expand Up @@ -238,6 +240,9 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
bool allow_precompiled_ = false;
FailState failed_ = FailState::Ok; // Wasm VM fatal error.

// ABI version.
AbiVersion abi_version_ = AbiVersion::Unknown;

bool is_emscripten_ = false;
uint32_t emscripten_metadata_major_version_ = 0;
uint32_t emscripten_metadata_minor_version_ = 0;
Expand Down
17 changes: 17 additions & 0 deletions include/proxy-wasm/wasm_api_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ namespace null_plugin {

inline WasmResult wordToWasmResult(Word w) { return static_cast<WasmResult>(w.u64_); }

// Configuration and Status
inline WasmResult proxy_get_configuration(const char **configuration_ptr,
size_t *configuration_size) {
return wordToWasmResult(
exports::get_configuration(current_context_, WR(configuration_ptr), WR(configuration_size)));
}

inline WasmResult proxy_get_status(uint32_t *code_ptr, const char **ptr, size_t *size) {
return wordToWasmResult(exports::get_status(current_context_, WR(code_ptr), WR(ptr), WR(size)));
}
Expand Down Expand Up @@ -58,6 +65,12 @@ inline WasmResult proxy_set_property(const char *key_ptr, size_t key_size, const
}

// Continue
inline WasmResult proxy_continue_request() {
return wordToWasmResult(exports::continue_request(current_context_));
}
inline WasmResult proxy_continue_response() {
return wordToWasmResult(exports::continue_response(current_context_));
}
inline WasmResult proxy_continue_stream(WasmStreamType stream_type) {
return wordToWasmResult(exports::continue_stream(current_context_, WS(stream_type)));
}
Expand All @@ -76,6 +89,10 @@ proxy_send_local_response(uint32_t response_code, const char *response_code_deta
WS(grpc_status)));
}

inline WasmResult proxy_clear_route_cache() {
return wordToWasmResult(exports::clear_route_cache(current_context_));
}

// SharedData
inline WasmResult proxy_get_shared_data(const char *key_ptr, size_t key_size,
const char **value_ptr, size_t *value_size, uint32_t *cas) {
Expand Down
8 changes: 8 additions & 0 deletions include/proxy-wasm/wasm_vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ enum class Cloneable {
InstantiatedModule // VMs can be cloned from an instantiated module.
};

enum class AbiVersion { ProxyWasm_0_1_0, ProxyWasm_0_2_0, Unknown };

class NullPlugin;

// Integrator specific WasmVm operations.
Expand Down Expand Up @@ -185,6 +187,12 @@ class WasmVm {
*/
virtual bool link(std::string_view debug_name) = 0;

/**
* Get ABI version of the module.
* @return the ABI version.
*/
virtual AbiVersion getAbiVersion() = 0;

/**
* Get size of the currently allocated memory in the VM.
* @return the size of memory in bytes.
Expand Down
40 changes: 32 additions & 8 deletions src/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,24 @@
} \
}

#define CHECK_FAIL2(_call1, _call2, _stream_type, _return_open, _return_closed) \
if (isFailed()) { \
if (plugin_->fail_open_) { \
return _return_open; \
} else { \
failStream(_stream_type); \
return _return_closed; \
} \
} else { \
if (!wasm_->_call1 && !wasm_->_call2) { \
return _return_open; \
} \
}

#define CHECK_HTTP(_call, _return_open, _return_closed) \
CHECK_FAIL(_call, WasmStreamType::Request, _return_open, _return_closed)
#define CHECK_HTTP2(_call1, _call2, _return_open, _return_closed) \
CHECK_FAIL2(_call1, _call2, WasmStreamType::Request, _return_open, _return_closed)
#define CHECK_NET(_call, _return_open, _return_closed) \
CHECK_FAIL(_call, WasmStreamType::Downstream, _return_open, _return_closed)

Expand Down Expand Up @@ -443,11 +459,15 @@ void ContextBase::onUpstreamConnectionClose(CloseType close_type) {
template <typename P> static uint32_t headerSize(const P &p) { return p ? p->size() : 0; }

FilterHeadersStatus ContextBase::onRequestHeaders(uint32_t headers, bool end_of_stream) {
CHECK_HTTP(on_request_headers_, FilterHeadersStatus::Continue,
FilterHeadersStatus::StopIteration);
CHECK_HTTP2(on_request_headers_abi_01_, on_request_headers_abi_02_, FilterHeadersStatus::Continue,
FilterHeadersStatus::StopIteration);
DeferAfterCallActions actions(this);
auto result =
wasm_->on_request_headers_(this, id_, headers, static_cast<uint32_t>(end_of_stream)).u64_;
auto result = wasm_->on_request_headers_abi_01_
? wasm_->on_request_headers_abi_01_(this, id_, headers).u64_
: wasm_
->on_request_headers_abi_02_(this, id_, headers,
static_cast<uint32_t>(end_of_stream))
.u64_;
if (result > static_cast<uint64_t>(FilterHeadersStatus::StopAllIterationAndWatermark))
return FilterHeadersStatus::StopAllIterationAndWatermark;
return static_cast<FilterHeadersStatus>(result);
Expand Down Expand Up @@ -485,11 +505,15 @@ FilterMetadataStatus ContextBase::onRequestMetadata(uint32_t elements) {
}

FilterHeadersStatus ContextBase::onResponseHeaders(uint32_t headers, bool end_of_stream) {
CHECK_HTTP(on_response_headers_, FilterHeadersStatus::Continue,
FilterHeadersStatus::StopIteration);
CHECK_HTTP2(on_response_headers_abi_01_, on_response_headers_abi_02_,
FilterHeadersStatus::Continue, FilterHeadersStatus::StopIteration);
DeferAfterCallActions actions(this);
auto result =
wasm_->on_response_headers_(this, id_, headers, static_cast<uint32_t>(end_of_stream)).u64_;
auto result = wasm_->on_response_headers_abi_01_
? wasm_->on_response_headers_abi_01_(this, id_, headers).u64_
: wasm_
->on_response_headers_abi_02_(this, id_, headers,
static_cast<uint32_t>(end_of_stream))
.u64_;
if (result > static_cast<uint64_t>(FilterHeadersStatus::StopAllIterationAndWatermark))
return FilterHeadersStatus::StopAllIterationAndWatermark;
return static_cast<FilterHeadersStatus>(result);
Expand Down
25 changes: 25 additions & 0 deletions src/exports.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ Word get_property(void *raw_context, Word path_ptr, Word path_size, Word value_p
return WasmResult::Ok;
}

Word get_configuration(void *raw_context, Word value_ptr_ptr, Word value_size_ptr) {
auto context = WASM_CONTEXT(raw_context);
auto value = context->getConfiguration();
if (!context->wasm()->copyToPointerSize(value, value_ptr_ptr, value_size_ptr)) {
return WasmResult::InvalidMemoryAccess;
}
return WasmResult::Ok;
}

Word get_status(void *raw_context, Word code_ptr, Word value_ptr_ptr, Word value_size_ptr) {
auto context = WASM_CONTEXT(raw_context);
auto status = context->getStatus();
Expand All @@ -163,6 +172,16 @@ Word get_status(void *raw_context, Word code_ptr, Word value_ptr_ptr, Word value
// HTTP

// Continue/Reply/Route
Word continue_request(void *raw_context) {
auto context = WASM_CONTEXT(raw_context);
return context->continueStream(WasmStreamType::Request);
}

Word continue_response(void *raw_context) {
auto context = WASM_CONTEXT(raw_context);
return context->continueStream(WasmStreamType::Response);
}

Word continue_stream(void *raw_context, Word type) {
auto context = WASM_CONTEXT(raw_context);
if (type > static_cast<uint64_t>(WasmStreamType::MAX)) {
Expand Down Expand Up @@ -198,6 +217,12 @@ Word send_local_response(void *raw_context, Word response_code, Word response_co
return WasmResult::Ok;
}

Word clear_route_cache(void *raw_context) {
auto context = WASM_CONTEXT(raw_context);
context->clearRouteCache();
return WasmResult::Ok;
}

Word set_effective_context(void *raw_context, Word context_id) {
auto context = WASM_CONTEXT(raw_context);
uint32_t cid = static_cast<uint32_t>(context_id);
Expand Down
4 changes: 1 addition & 3 deletions src/null/null_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@
namespace proxy_wasm {

void NullPlugin::getFunction(std::string_view function_name, WasmCallVoid<0> *f) {
if (function_name == "proxy_abi_version_0_1_0") {
*f = [](ContextBase *) { /* dummy function */ };
} else if (function_name == "_start") {
if (function_name == "_start") {
*f = nullptr;
} else if (function_name == "__wasm_call_ctors") {
*f = nullptr;
Expand Down
2 changes: 2 additions & 0 deletions src/null/null_vm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ bool NullVm::load(const std::string &name, bool /* allow_precompiled */) {
return true;
}

AbiVersion NullVm::getAbiVersion() { return AbiVersion::ProxyWasm_0_2_0; }

bool NullVm::link(std::string_view /* name */) { return true; }

uint64_t NullVm::getMemorySize() { return std::numeric_limits<uint64_t>::max(); }
Expand Down
19 changes: 19 additions & 0 deletions src/v8/v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class V8 : public WasmVm {
std::string_view runtime() override { return "v8"; }

bool load(const std::string &code, bool allow_precompiled) override;
AbiVersion getAbiVersion() override;
std::string_view getCustomSection(std::string_view name) override;
std::string_view getPrecompiledSectionName() override;
bool link(std::string_view debug_name) override;
Expand Down Expand Up @@ -366,6 +367,24 @@ std::string_view V8::getPrecompiledSectionName() {
return name;
}

AbiVersion V8::getAbiVersion() {
assert(module_ != nullptr);

const auto export_types = module_.get()->exports();
for (size_t i = 0; i < export_types.size(); i++) {
if (export_types[i]->type()->kind() == wasm::EXTERN_FUNC) {
std::string_view name(export_types[i]->name().get(), export_types[i]->name().size());
if (name == "proxy_abi_version_0_1_0") {
return AbiVersion::ProxyWasm_0_1_0;
} else if (name == "proxy_abi_version_0_2_0") {
return AbiVersion::ProxyWasm_0_2_0;
}
}
}

return AbiVersion::Unknown;
}

bool V8::link(std::string_view debug_name) {
assert(module_ != nullptr);

Expand Down
Loading