> 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

Reply via email to