> From: Etelson, Gregory > Sent: Thursday, April 10, 2025 6:28 AM > To: Richardson, Bruce > Cc: dev@dpdk.org > Subject: Re: [RFC PATCH] add rust binding support to DPDK > > Hello Bruce,
Hi Bruce & Gregory, > > Add a Cargo.toml file in the root folder and a number of other scripts > > and rust-related files into buildtools/rust, which then enables DPDK to > > be cloned and built as a rust crate - all-be-it one with only two > > functions: rte_eal_init and rte_eal_cleanup. > > > > Signed-off-by: Bruce Richardson <bruce.richard...@intel.com> > > --- > > > > This RFC is proposed as an alternative approach to enabling rust support > > in DPDK. The key difference vs previous is that we are taking the whole > > DPDK project here as a rust "crate", which can then be used by other > > higher-level crates as a dependency. Building the crate does a > > (minimal) build of DPDK and statically links it in, so there is no > > "install" step or anything needed - the Rust app just adds DPDK to their > > Cargo.toml file and then should have everything they need. > > > > Having a shared source directory for both for C and Rust DPDK infrastructure > is > the correct approach. It seems so, with the various approaches so far, agreed. I've tested Bruce's repo, and Cargo.toml. The initial build takes some time.. but it works! The experience of "Adding DPDK to a Rust project" is very similar to adding any other Rust crate. I like this - it makes the "strangeness" of depending on DPDK near-zero :) > My concern is how to properly maintain Rust crate once DPDK starts to > implement > it's own API. I'm not really sure what is meant here. I don't understand what "own" word refers to? I see it like this: - DPDK has the public C API exported (and that stays the same as today, with ABI rules, version.map files, etc) - The Rust crate consumes the public C API (via bindgen, as done in this patch. More detail about bindgen below.) So DPDK changing APIs is API/ABI breaking for *all* consumers of DPDK, not just the Rust bindings. No special treatment required, just identify API/ABI changes when they occur (as per ABI policy) and fix. Some approaches to how CI could help, and when to identify/fix Rust bindings took place on the last TechBoard call (minutes not yet available on https://core.dpdk.org/techboard/minutes/). No decision made on how - we're still at prototyping phase anyway. > Rust files may need a separate directories to host libraries, applications > and PMD. I'm not sure this is strictly required - perhaps "nice to have". Bruce's approach has been to minimize changes in the "DPDK C repo", doing just enough to enable building "Safe Rust" wrappers on top in a seperate "DPDK Rust" repo. I like this approach - use what bindgen gives access to - and incrementally export/expose more DPDK APIs *as they are consumed*. This ensures we don't accidentally over-export, or have mistakes go unnoticed because nobody tested/used the APIs yet. More on this below in the context of bindgen usage. <snip> > > diff --git a/buildtools/rust/build.rs b/buildtools/rust/build.rs > > new file mode 100644 > > index 0000000000..1ffdf03d2f > > --- /dev/null > > +++ b/buildtools/rust/build.rs <snip> > > + let bindings = bindings.header("buildtools/rust/wrapper.h") > > + .derive_default(true) > > + .allowlist_function("rte_eal_init") > > + .allowlist_function("rte_eal_cleanup") > > Calling the `allowlist_function()` method generates well-maintained target > bindings. > That approach requires to specify each DPDK symbol for Rust > library API explicitly. There are way too many symbols to bind even for > a simple network application. The "allowlist" approach ensures that DPDK C functions, bindgen-converted in Rust are used, and reviewed. If all DPDK C APIs are exported, there is additional and unknown risk of bugs, that the users of the DPDK-rust-bindings will hit: providing bad user-experience. I do not believe it is a good idea to export all API structs & symbols without any tests, reviews, and quality control. If it is really desired by a end user to export all C API as "unsafe Rust" bindings, there are many crates existing already doing this (and your patch Gregory also provides that method?). I do not feel this adds value for DPDK community to maintain: the end-goal must be an ergonomic and safe Rust API. My vote is to incrementally "allowlist" new APIs, and having a "Safe Rust" (or "idiomatic Rust APIs") wrapping them to export public functions in the "end-user facing" DPDK Rust crate. This ensures that any public function in the "DPDK Rust" crate has been built, reviewed and tested. This will cause the initial versions of the "DPDK Rust" to be very minimal, and to gradually export more functionality and APIs in a safe way. From my perspective, this is the only way to give a consistent high-quality user-experience that is the norm for the Rust ecosystem. > Bindings file or directory for RTE library API is not enough. > Each PMD has it's own symbols set and will need a separate bindings library. As per above, I recommend we focus on minimal functionality, exported and exposed in an ergonomic way. That means initial focus on EAL, Lcore management, Mempools, Ethdev, and Mbufs. Or from a "use-case" perspective, enough to get L2-macswap to work using "Safe Rust" bindings. This means that things like "PMD specific symbols" are not going to be high on the priority list initially. Once the above L2 forward use-case is satisfied, I'm happy to provide input on designing an API which is "PMD specific" in a generic way (initial technical thoughts, a "dyn Trait" with downcast to a PMD specific trait). <snip> > > +#[cfg(test)] > > +mod tests { > > + use super::*; > > + > > + #[test] > > + fn test_helloworld() { > > + let appname = std::ffi::CString::new("test-rs").unwrap(); > > + let mut argv = [appname.into_raw()]; > > + let ret = unsafe { > > + rte_eal_init(argv.len().try_into().unwrap(), > > argv.as_mut_ptr()) > > Activating rte_eal_init() proves that Rust crate has properly linked with DPDK > libraries. > That is more like infrastructure test. > An active network port with IO capabilities is a real Rust-DPDK POC. Agreed - as you can see, this is a #[test]. It is intended only to show that eal_init() and cleanup() work. Next steps are to "allowlist" more DPDK public API functions, and start building "Safe Rust" APIs over them, in order to expose an ergonomic and misuse-resistant API. As you note, this is where a network ports, lcores, mempools, and ethdev configuration are all required. First goal something like "Safe L2 macswap"? I will make some Safe-Rust API suggestions for EAL, and send a patch sometime next week to discuss. Thanks for the inputs! Regards, -Harry