DPDK patches and discussions
 help / color / mirror / Atom feed
From: "Etelson, Gregory" <getelson@nvidia.com>
To: Bruce Richardson <bruce.richardson@intel.com>
Cc: dev@dpdk.org
Subject: Re: [RFC PATCH] add rust binding support to DPDK
Date: Thu, 10 Apr 2025 08:28:32 +0300 (IDT)	[thread overview]
Message-ID: <187447a-fb49-2833-7e44-ad5bb0d67a99@nvidia.com> (raw)
In-Reply-To: <20250408145838.2501034-1-bruce.richardson@intel.com>

Hello Bruce,

> 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.richardson@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.
My concern is how to properly maintain Rust crate once DPDK starts to implement
it's own API.
Rust files may need a separate directories to host libraries, applications 
and PMD.

> diff --git a/Cargo.toml b/Cargo.toml
> new file mode 100644
> index 0000000000..fe0843975a
> --- /dev/null
> +++ b/Cargo.toml
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2025 Intel Corporation
> +
> +[package]
> +name = "dpdk-c"
> +version = "25.0.7"
> +build = "buildtools/rust/build.rs"
> +edition = "2021"
> +
> +[lib]
> +path = "buildtools/rust/lib.rs"
> +doctest = false
> +
> +[build-dependencies]
> +bindgen = "0.71"
> +meson-next = "1"
> diff --git a/buildtools/meson.build b/buildtools/meson.build
> index 4e2c1217a2..a13b5189c1 100644
> --- a/buildtools/meson.build
> +++ b/buildtools/meson.build
> @@ -26,6 +26,7 @@ header_gen_cmd = py3 + files('gen-header.py')
> has_hugepages_cmd = py3 + files('has-hugepages.py')
> cmdline_gen_cmd = py3 + files('dpdk-cmdline-gen.py')
> check_dts_requirements = py3 + files('check-dts-requirements.py')
> +gen_cargo_bindgen_info = py3 + files('rust/gen-cargo-bindgen-info.py')
>
> # install any build tools that end-users might want also
> install_data([
> 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
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2025 Intel Corporation
> + */
> +
> +extern crate meson_next as meson;
> +use std::collections::HashMap;
> +use std::env;
> +use std::path::PathBuf;
> +
> +fn main() {
> +    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
> +    let build_dir = out_path.join("build");
> +
> +    let meson_cfg = meson::Config::new().options(HashMap::from([
> +        ("enable_libs", "eal"),
> +        ("enable_drivers", "net/*,net/intel/*"),
> +        ("enable_apps", "test")
> +    ]));
> +    meson::build(".", build_dir.to_str().unwrap(), meson_cfg);
> +
> +    /* open and print file 'cargo_rules.txt' from build_dir */
> +    let cargo_ldflags_file = build_dir.join("cargo_ldflags.txt");
> +    println!("cargo:rerun-if-changed={}", cargo_ldflags_file.display());
> +    print!("{}", std::fs::read_to_string(cargo_ldflags_file).unwrap());
> +
> +    let bindgen_include_file = build_dir.join("bindgen_cflags.txt");
> +    let mut bindings = bindgen::Builder::default();
> +    for line in std::fs::read_to_string(bindgen_include_file).unwrap().lines() {
> +            bindings = bindings.clang_arg(line);
> +    }
> +
> +    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.

> +        // Tell cargo to invalidate the built crate whenever any of the
> +        // included header files changed.
> +        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
> +        .generate()
> +        .expect("Unable to generate bindings");
> +
> +    bindings
> +        .write_to_file(out_path.join("bindings.rs"))
> +        .expect("Couldn't write bindings!");
> +}

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.

> diff --git a/buildtools/rust/gen-cargo-bindgen-info.py b/buildtools/rust/gen-cargo-bindgen-info.py
> new file mode 100644
> index 0000000000..bea432ead3
> --- /dev/null
> +++ b/buildtools/rust/gen-cargo-bindgen-info.py
> @@ -0,0 +1,52 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2025 Intel Corporation
> +
> +# Script to generate cargo rules for static linking in rust builds
> +# outputs one line per library, for drivers and libraries
> +
> +import os
> +import os.path
> +import sys
> +import subprocess
> +
> +if 'MESON_BUILD_ROOT' not in os.environ:
> +    print('This script must be called from a meson build environment')
> +    sys.exit(1)
> +
> +pkgconf = sys.argv[1]
> +os.environ['PKG_CONFIG_PATH'] = os.path.join(os.environ['MESON_BUILD_ROOT'], 'meson-uninstalled')
> +linker_flags = subprocess.check_output([pkgconf, '--libs', '--static', 'libdpdk']).decode('utf-8')
> +cflags = subprocess.check_output([pkgconf, '--cflags', 'libdpdk']).decode('utf-8')
> +
> +whole_archive = False
> +with open(os.path.join(os.environ['MESON_BUILD_ROOT'], 'cargo_ldflags.txt'), 'w') as dst:
> +    for flag in linker_flags.split():
> +        if flag == '-pthread':
> +            continue
> +        elif flag == '-Wl,--whole-archive':
> +            whole_archive = True
> +        elif flag == '-Wl,--no-whole-archive':
> +            whole_archive = False
> +        elif flag.startswith('-L'):
> +            dst.write(f'cargo:rustc-link-search=native={flag[2:]}\n')
> +        elif flag.startswith('-l:'):
> +            libname = flag[3:]
> +            if libname.startswith('lib'):
> +                libname = libname[3:]
> +            if libname.endswith('.a'):
> +                libname = libname[:-2]
> +            if whole_archive:
> +                dst.write(f'cargo:rustc-link-lib=static:+whole-archive={libname}\n')
> +            else:
> +                dst.write(f'cargo:rustc-link-lib=static={libname}\n')
> +        elif flag.startswith('-lrte_'):
> +            # skip any other DPDK lib flags, we already have them above
> +            continue
> +        elif flag.startswith('-l'):
> +            dst.write(f'cargo:rustc-link-lib={flag[2:]}\n')
> +        else:
> +            print(f'Warning: Unknown flag: {flag}', file=sys.stderr)
> +
> +with open(os.path.join(os.environ['MESON_BUILD_ROOT'], 'bindgen_cflags.txt'), 'w') as dst:
> +    for flag in cflags.split():
> +        dst.write(f'{flag}\n')
> diff --git a/buildtools/rust/lib.rs b/buildtools/rust/lib.rs
> new file mode 100644
> index 0000000000..f99c54ac42
> --- /dev/null
> +++ b/buildtools/rust/lib.rs
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2025 Intel Corporation
> + */
> +
> +#![allow(non_upper_case_globals)]
> +#![allow(non_camel_case_types)]
> +#![allow(non_snake_case)]
> +
> +include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
> +
> +#[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.

> +       };
> +       assert!(ret >= 0, "rte_eal_init failed");
> +        unsafe { rte_eal_cleanup() };
> +    }
> +}
> diff --git a/buildtools/rust/wrapper.h b/buildtools/rust/wrapper.h
> new file mode 100644
> index 0000000000..25f5bf94e2
> --- /dev/null
> +++ b/buildtools/rust/wrapper.h
> @@ -0,0 +1,5 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2025 Intel Corporation
> + */
> +
> +#include <rte_eal.h>
> diff --git a/meson.build b/meson.build
> index 8436d1dff8..72c82178e1 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -114,6 +114,9 @@ configure_file(output: build_cfg,
> # build pkg-config files for dpdk
> subdir('buildtools/pkg-config')
>
> +# output a list of cargo parameters if DPDK is being built for rust use
> +run_command([gen_cargo_bindgen_info, pkgconf], check: true)
> +
> if meson.is_subproject()
>     subdir('buildtools/subproject')
> endif
> --
> 2.45.2
>
>

Regards,
Gregory

  parent reply	other threads:[~2025-04-10  5:28 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-06 13:37 [PATCH] rust: support DPDK API Gregory Etelson
2025-03-06 19:26 ` Van Haaren, Harry
2025-03-07 16:56   ` Etelson, Gregory
2025-03-07 15:54 ` Van Haaren, Harry
2025-03-07 16:20   ` Bruce Richardson
2025-03-07 18:15     ` Etelson, Gregory
2025-03-07 18:00   ` Etelson, Gregory
2025-03-08 14:28 ` Igor Gutorov
2025-03-08 19:14   ` Etelson, Gregory
2025-03-10 15:31     ` Stephen Hemminger
2025-03-12  5:21       ` Etelson, Gregory
2025-03-08 18:50 ` [PATCH v2] rust: support raw " Gregory Etelson
2025-03-10 16:13   ` Van Haaren, Harry
2025-03-10 16:25     ` Bruce Richardson
2025-03-12 17:19       ` Thomas Monjalon
2025-03-14 19:12     ` Etelson, Gregory
2025-03-10 15:00 ` [PATCH] rust: support " Stephen Hemminger
2025-03-12  5:12   ` Etelson, Gregory
2025-03-10 16:18 ` Stephen Hemminger
2025-03-10 16:30   ` Bruce Richardson
2025-03-12 14:30   ` Etelson, Gregory
2025-03-13  7:56     ` Igor Gutorov
2025-03-12 15:29   ` Igor Gutorov
2025-03-12 17:24     ` Thomas Monjalon
2025-03-14 18:38 ` [PATCH v3] rust: support raw " Gregory Etelson
2025-03-18  8:51   ` Dariusz Sosnowski
2025-03-18  9:12     ` Dariusz Sosnowski
2025-03-22 10:59 ` [PATCH v4] " Gregory Etelson
2025-03-22 17:39   ` Bruce Richardson
2025-03-27  5:51     ` Etelson, Gregory
2025-03-27 16:22   ` Bruce Richardson
2025-03-28 18:30     ` Etelson, Gregory
2025-03-27  8:23 ` DPDK for rust Morten Brørup
2025-03-27  9:00   ` Etelson, Gregory
2025-03-27 16:17     ` Bruce Richardson
2025-03-28 18:09       ` Etelson, Gregory
2025-03-28 19:25         ` Stephen Hemminger
2025-03-31  9:11           ` Bruce Richardson
2025-03-31 10:26             ` Luca Boccassi
2025-04-01 13:08               ` Etelson, Gregory
2025-03-31  9:03       ` Thomas Monjalon
2025-03-31  9:10         ` Bruce Richardson
2025-04-08 14:58 ` [RFC PATCH] add rust binding support to DPDK Bruce Richardson
2025-04-08 15:05   ` Bruce Richardson
2025-04-10  5:28   ` Etelson, Gregory [this message]
2025-04-11 13:13     ` Van Haaren, Harry
2025-04-11 15:39       ` Etelson, Gregory
2025-04-11 16:22         ` Van Haaren, Harry
2025-04-13  8:07           ` Etelson, Gregory
2025-04-13 17:09             ` Owen Hilyard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=187447a-fb49-2833-7e44-ad5bb0d67a99@nvidia.com \
    --to=getelson@nvidia.com \
    --cc=bruce.richardson@intel.com \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).