Skip to content
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

Rust support in Envoy #12155

Open
htuch opened this issue Jul 17, 2020 · 10 comments
Open

Rust support in Envoy #12155

htuch opened this issue Jul 17, 2020 · 10 comments
Labels
area/build design proposal Needs design doc/proposal before implementation help wanted Needs help!

Comments

@htuch
Copy link
Member

htuch commented Jul 17, 2020

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:

  • The access/header formatter if attention is paid to finding the right cut point.
  • Codecs
  • Incremental replacement of existing extensions; this will be a forcing function to sort out API stability proposal  #3390.
  • Load balancers
  • HeaderMap
  • ... suggestions welcome in this issue ...
@htuch htuch added area/build design proposal Needs design doc/proposal before implementation help wanted Needs help! labels Jul 17, 2020
@akonradi
Copy link
Contributor

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

The problems I encountered:

  • cxx isn't fully Bazel-ified, and depends on a bunch of Rust crates. To really make it work, we'd want to push on Bazel support for reading Cargo.toml files. Another option is compiling the code generator externally via Cargo and then using it in Bazel to generate C++ and Rust source
  • types that cross the FFI boundary need to be defined in Rust. cxx can generate C++ code but not the other way around.
  • Rust doesn't understand C++ dynamic dispatch. If we want to pass interface pointers (like Buffer::Instance) into Rust and allow methods to be called on them, every virtual function would need a corresponding free function that is implemented in C++ and calls the virtual function. So there would need to be a Buffer_Instance_add_string_view free function that just called Buffer::Instance::add. And each one would need a different name since Rust doesn't support function overloading.

@mattklein123
Copy link
Member

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link

sayrer commented Jul 18, 2020

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
Copy link
Member

Mythra commented Jul 20, 2020

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
Copy link
Member Author

htuch commented Jul 20, 2020

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
Copy link
Member Author

htuch commented Aug 19, 2020

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

@jplevyak
Copy link
Contributor

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
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/build design proposal Needs design doc/proposal before implementation help wanted Needs help!
Projects
None yet
Development

No branches or pull requests

9 participants