envoyproxy / envoy

Cloud-native high-performance edge/middle/service proxy
https://www.envoyproxy.io
Apache License 2.0
24.77k stars 4.76k forks source link

Rust support in Envoy #12155

Open htuch opened 4 years ago

htuch commented 4 years ago

I'm opening this as a top-level tracking issue for some initial possible projects for incrementally introducing Rust to Envoy. The idea is to benefit from the memory safety and ecosystem growth in Rust while retaining high performance, without boiling the ocean. Given Rust's use in places such as Mozilla, Tor, Linkerd and Linux kernel, it seems to make sense to scope out what we can achieve here.

Any use of Rust in Envoy will need to navigate build system (i.e. Bazel) and FFI integration. Some initial projects that could be possible:

  1. HelloWorld filter (e.g. simple header replacement) in Rust. This would force a fair bit of complexity in dealing with C++-Rust FFI, but open up the possibility of arbitrary Rust filters. A non-trivial candidate for porting to Rust would be the Lua filter, which already needs to interoperate with C.
  2. Rust use in strategic locations in Envoy core, e.g. parsers, where we can largely isolate the Rust and C++ world and communicate via a simple string or a very limited set of types between the two. The proto header parser is a good starting place.

More advanced uses in the future could include:

akonradi commented 4 years ago

I looked at this briefly using the cxx library for the interop. You can see my attempt here.

The problems I encountered:

mattklein123 commented 4 years ago

Thanks @akonradi. FWIW my view is we should avoid C++ interop for now and just stick with C which I think should be not that bad for some initial use cases.

akonradi commented 4 years ago

Yeah to be fair, C++ interop isn't a thing because there's no C++ ABI. Everybody just uses C as the lowest common denominator, including Rust. cxx generates bindings in both languages that, at the bottom, use C-style FFI calls, but allow passing things like std::unique_ptr, which has ownership semantics. IMO Rust's lifetime enforcement doesn't offer you much if you're limited to passing ints and raw pointers across.

One other "problem" I encountered, at least for Google, is that any non-trivial Rust usage is going to require either pulling in external crates or duplicating a bunch of functionality that Envoy already has or depends on in C++, but in Rust. That's going to increase the size of Envoy's trusted codebase significantly.

antoniovicente commented 4 years ago

We should be clear about what we expect to gain in each case. Having wrappers that allow implementing filter extensions in other languages including Rust seems a nice thing to have.

Having to jump through C callback APIs in codec dispatch if we attempt to write protocol parsers in Rust seems as brittle as the current interaction between Envoy code and C-based parsers like http-parser and nghttp2.

sayrer commented 4 years ago

I use https://github.com/dtolnay/cxx with Bazel. It works fine. If you want to use external cargo crates, you'll end up using cargo-raze anyway.

This little patch shows you how to update in-tree cargo deps for use with cxx and Bazel:

https://github.com/dtolnay/cxx/pull/59/files#diff-c0a5305a356389c2faccfb74e002f153

Mythra commented 4 years ago

I'd also like to make sure we have clear goals for each use case. I'm excited to get rust in, and it sounds very possible given the state of tooling. But I'd hate to end up in a place where we end up we use rust in perhaps not the best scenario and people just see it as "that thing that's annoying to deal with, or we have to do $X in C interface cause rust needs it :sigh: ".

Ideally we'd start with very high visibility, low friction to many contributor places where rust would work well. Particularly I'm thinking of parsers/headermap. These would also really put rust through the paces forcing us to figure out a sane interface at the beginning. While filters would be nice I feel like the chance to cause churn for people is a bit higher, and if someone really wants it they can use WASM filters where lots of tooling has been developed already.

htuch commented 4 years ago

Yeah, I agree that the Wasm Nullvm and Rust are likely the ideal filter integration point for extensions. @PiotrSikora @jplevyak do you have any pointers on how folks would be able to get started writing NullVm Rust filters?

htuch commented 4 years ago

Interesting take from Chrome on C++ interop: https://www.chromium.org/Home/chromium-security/memory-safety/rust-and-c-interoperability

jplevyak commented 4 years ago

The NullVm is nice because it works around the issues that Chrome would be facing as it already has a language level translator including explicit memory management and ownership transfers.

We would have to create a NullVM SDK for rust. This wouldn't be that hard as most of the work from the C++ NullVM code could be repurposed transparently. There is a bit of code required in the "VM runtime" which is different and will have to be written specifically to support rust, in particular the code which registers the in-VM Context and RootContext factories.

@PiotrSikora what is your take on this. How much work do you think it would be?

mathetake commented 3 years ago

FWIW here, we are already able to write extensions in Rust via Wasm NullVm mechanism: https://github.com/mathetake/proxy-wasm-rust-nullvm and link them statically.