Repository: aya-rs/aya (language: rust)

Issue:
allow multiple BPF programs to share the same BTF
I've noticed that multiple BPF programs loaded by the same userspace process can't share the same host BTF because [this method](https://github.com/alessandrod/aya/blob/d996a88de47d60053504695036a14157ce6b3aa6/aya/src/bpf.rs#L114) consumes the `target_btf` object instead of accepting it by reference. However, [later in the code](https://github.com/alessandrod/aya/blob/d996a88de47d60053504695036a14157ce6b3aa6/aya/src/obj/btf/relocation.rs#L181), in the only part where `target_btf` is used (immutably), its reference is used. If i'm not mistaken this means that the very first method could accept a reference instead of a value to begin with.

On my Ubuntu each BTF object is around 13MB (in debug mode) and I'm loading several different eBPF programs, so it'd be nice to be able to share the relocation info among them and save a lot of memory.


Discussion / hints:
Yup, makes sense.
since (at least in my case) it'd be a BTF instance shared among different threads, should it be an `Arc<Mutex<&Btf>>` ?
mmm nevermind this was a dumb question, the logic to access it should not be coupled with the library, so i'd say Btf::load should just accept an `Option<&Btf>` and then one can handle the more appropriate borrowing strategy from the outside (in my case it'd be `Arc<Mutex<&Btf>>`) ... thoughts?
Yep that sounds right!
great, working on a PR

Fix patch:
diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs
index 778632615..bc1f8f1aa 100644
--- a/aya/src/bpf.rs
+++ b/aya/src/bpf.rs
@@ -90,7 +90,7 @@ impl Bpf {
                 path: path.to_owned(),
                 error,
             })?,
-            Btf::from_sys_fs().ok(),
+            Btf::from_sys_fs().ok().as_ref(),
         )
     }
 
@@ -98,7 +98,8 @@ impl Bpf {
     ///
     /// Parses the object code contained in `data` and initializes the [maps](crate::maps) defined
     /// in it. If `target_btf` is not `None` and `data` includes BTF debug info, [BTF](Btf) relocations
-    /// are applied as well.
+    /// are applied as well. In order to allow sharing of a single [BTF](Btf) object among multiple
+    /// eBPF programs, `target_btf` is passed by reference.
     ///
     /// # Examples
     ///
@@ -108,10 +109,10 @@ impl Bpf {
     ///
     /// let data = fs::read("file.o").unwrap();
     /// // load the BTF data from /sys/kernel/btf/vmlinux
-    /// let bpf = Bpf::load(&data, Some(Btf::from_sys_fs()?));
+    /// let bpf = Bpf::load(&data, Btf::from_sys_fs().ok().as_ref());
     /// # Ok::<(), aya::BpfError>(())
     /// ```
-    pub fn load(data: &[u8], target_btf: Option<Btf>) -> Result<Bpf, BpfError> {
+    pub fn load(data: &[u8], target_btf: Option<&Btf>) -> Result<Bpf, BpfError> {
         let mut obj = Object::parse(data)?;
 
         if let Some(btf) = target_btf {
diff --git a/aya/src/obj/btf/relocation.rs b/aya/src/obj/btf/relocation.rs
index a21a2c96c..e4c91ca72 100644
--- a/aya/src/obj/btf/relocation.rs
+++ b/aya/src/obj/btf/relocation.rs
@@ -151,7 +151,7 @@ impl Relocation {
 }
 
 impl Object {
-    pub fn relocate_btf(&mut self, target_btf: Btf) -> Result<(), BpfError> {
+    pub fn relocate_btf(&mut self, target_btf: &Btf) -> Result<(), BpfError> {
         let (local_btf, btf_ext) = match (&self.btf, &self.btf_ext) {
             (Some(btf), Some(btf_ext)) => (btf, btf_ext),
             _ => return Ok(()),
@@ -174,13 +174,8 @@ impl Object {
                     function: section_name.to_owned(),
                     error: Box::new(RelocationError::ProgramNotFound),
                 })?;
-            match relocate_btf_program(
-                program,
-                relos,
-                local_btf,
-                &target_btf,
-                &mut candidates_cache,
-            ) {
+            match relocate_btf_program(program, relos, local_btf, target_btf, &mut candidates_cache)
+            {
                 Ok(_) => {}
                 Err(ErrorWrapper::BtfError(e)) => return Err(e.into()),
                 Err(ErrorWrapper::RelocationError(error)) => {


Test patch: