pub struct BpfBuilder { /* private fields */ }
Expand description
§Build helpers for sched_ext schedulers with Rust userspace component
This is to be used from build.rs
of a cargo project which implements a
sched_ext scheduler with C BPF
component and Rust userspace component. BpfBuilder
provides everything
necessary to build the BPF component and generate Rust bindings.
BpfBuilder provides the following.
vmlinux.h
and other common BPF header files
All sched_ext BPF implementations require vmlinux.h
and many make use
of common constructs such as
user_exit_info
.
BpfBuilder
makes these headers available when compiling BPF source
code and generating bindings for it. The included headers can be browsed
at https://github.com/sched-ext/scx/tree/main/scheds/include.
These headers can be superseded using environment variables which will be discussed later.
- Header bindings using
bindgen
If enabled with .enable_intf()
, the input .h
file is processed by
bindgen
to generate Rust bindings. This is useful in establishing
shared constants and data types between the BPF and user components.
Note that the types generated with bindgen
are different from the
types used by the BPF skeleton even when they are the same types in BPF.
This is a source of ugliness and we are hoping to address it by
improving libbpf-cargo
in the future.
- BPF compilation and generation of the skeleton and its bindings
If enabled with .enable_skel()
, the input .bpf.c
file is compiled
and its skeleton and bindings are generated using libbpf-cargo
.
§An Example
This section shows how BpfBuilder
can be used in an example project.
For a concrete example, take a look at
scx_rusty
.
A minimal source tree using all features would look like the following:
scx_hello_world
|-- Cargo.toml
|-- build.rs
\-- src
|-- main.rs
|-- bpf_intf.rs
|-- bpf_skel.rs
\-- bpf
|-- intf.h
\-- main.c
The following three files would contain the actual implementation:
-
src/main.rs
: Rust userspace component which loads the BPF blob and interacts it using the generated bindings. -
src/bpf/intf.h
: C header file definining constants and structs that will be used by both the BPF and userspace components. -
src/bpf/main.c
: C source code implementing the BPF component - includingstruct sched_ext_ops
.
And then there are boilerplates to generate the bindings and make them
available as modules to main.rs
.
-
Cargo.toml
: Includesscx_utils
in the[build-dependencies]
section. -
build.rs
: Usesscx_utils::BpfBuilder
to build and generate bindings for the BPF component. For this project, it can look like the following.
fn main() {
scx_utils::BpfBuilder::new()
.unwrap()
.enable_intf("src/bpf/intf.h", "bpf_intf.rs")
.enable_skel("src/bpf/main.bpf.c", "bpf")
.build()
.unwrap();
}
bpf_intf.rs
: Import the bindings generated bybindgen
into a module. Above, we told.enable_intf()
to generate the bindings intobpf_intf.rs
, so the file would look like the following. Theallow
directives are useful if the header is includingvmlinux.h
.
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
include!(concat!(env!("OUT_DIR"), "/bpf_intf.rs"));
bpf_skel.rs
: Import the BPF skeleton bindings generated bylibbpf-cargo
into a module. Above, we told.enable_skel()
to use the skeleton namebpf
, so the file would look like the following.
include!(concat!(env!("OUT_DIR"), "/bpf_skel.rs"));
§Compiler Flags and Environment Variables
BPF being its own CPU architecture and independent runtime environment,
build environment and steps are already rather complex. The need to
interface between two different languages - C and Rust - adds further
complexities. BpfBuilder
automates most of the process. The determined
build environment is recorded in the build.rs
output and can be
obtained with a command like the following:
$ grep '^scx_utils:clang=' target/release/build/scx_rusty-*/output
While the automatic settings should work most of the time, there can be times when overriding them is necessary. The following environment variables can be used to customize the build environment.
-
BPF_CLANG
: The clang command to use. (Default:clang
) -
BPF_CFLAGS
: Compiler flags to use when building BPF source code. If specified, the flags from this variable are the only flags passed to the compiler.BpfBuilder
won’t generate any flags including-I
flags for the common header files and otherCFLAGS
related variables are ignored. -
BPF_BASE_CFLAGS
: Override the non-include part of cflags. -
BPF_EXTRA_CFLAGS_PRE_INCL
: Add cflags before the automic include search path options. Header files in the search paths added by this variable will supercede the automatic ones. -
BPF_EXTRA_CFLAGS_POST_INCL
: Add cflags after the automic include search path options. Header paths added by this variable will be searched only if the target header file can’t be found in the automatic header paths. -
RUSTFLAGS
: This is a genericcargo
flag and can be useful for specifying extra linker flags.
A common case for using the above flags is using the latest libbpf
from the kernel tree. Let’s say the kernel tree is at $KERNEL
and
libbpf
. The following builds libbpf
shipped with the kernel:
$ cd $KERNEL
$ make -C tools/bpf/bpftool
To link the scheduler against the resulting libbpf
:
$ env BPF_EXTRA_CFLAGS_POST_INCL=$KERNEL/tools/bpf/bpftool/libbpf/include \
RUSTFLAGS="-C link-args=-lelf -C link-args=-lz -C link-args=-lzstd \
-L$KERNEL/tools/bpf/bpftool/libbpf" cargo build --release
Implementations§
Source§impl BpfBuilder
impl BpfBuilder
Sourcepub fn new() -> Result<Self>
pub fn new() -> Result<Self>
Create a new BpfBuilder
struct. Call enable
and set
methods to
configure and build
method to compile and generate bindings. See
the struct documentation for details.
Sourcepub fn enable_intf(&mut self, input: &str, output: &str) -> &mut Self
pub fn enable_intf(&mut self, input: &str, output: &str) -> &mut Self
Enable generation of header bindings using bindgen
. @input
is
the .h
file defining the constants and types to be shared between
BPF and Rust components. @output
is the .rs
file to be
generated.
Sourcepub fn enable_skel(&mut self, input: &str, name: &str) -> &mut Self
pub fn enable_skel(&mut self, input: &str, name: &str) -> &mut Self
Enable compilation of BPF code and generation of the skeleton and
its Rust bindings. @input
is the .bpf.c
file containing the BPF
source code and @output
is the .rs
file to be generated.
pub fn add_source(&mut self, input: &str) -> &mut Self
pub fn compile_link_gen(&mut self) -> Result<()>
Trait Implementations§
Auto Trait Implementations§
impl Freeze for BpfBuilder
impl RefUnwindSafe for BpfBuilder
impl Send for BpfBuilder
impl Sync for BpfBuilder
impl Unpin for BpfBuilder
impl UnwindSafe for BpfBuilder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.