Browse Source

aya: Implement FdLink::pin()

This allows for FdLinks to also be pinned to BpfFs.
In order for it to be called, the user would first call
`take_link` to get the underlying link. This can then
be destructured to an FdLink where FdLink::pin() may be called.

Signed-off-by: Dave Tucker <[email protected]>
Dave Tucker 2 years ago
parent
commit
64f8a434d2
1 changed files with 45 additions and 1 deletions
  1. 45 1
      aya/src/programs/links.rs

+ 45 - 1
aya/src/programs/links.rs

@@ -1,14 +1,40 @@
 //! Program links.
 use libc::{close, dup};
+use thiserror::Error;
 
 use std::{
     borrow::Borrow,
     collections::{hash_map::Entry, HashMap},
+    ffi::CString,
+    io,
     ops::Deref,
     os::unix::prelude::RawFd,
+    path::Path,
 };
 
-use crate::{generated::bpf_attach_type, programs::ProgramError, sys::bpf_prog_detach};
+use crate::{
+    generated::bpf_attach_type,
+    programs::ProgramError,
+    sys::{bpf_pin_object, bpf_prog_detach},
+};
+
+/// An error ocurred working with a Link.
+#[derive(Error, Debug)]
+pub enum LinkError {
+    /// Invalid Pin Path.
+    #[error("invalid pin path `{error}`")]
+    InvalidPinPath {
+        /// The error message.
+        error: String,
+    },
+    /// Pinning error.
+    #[error("BPF_OBJ_PIN failed")]
+    PinError {
+        /// The [`io::Error`] returned by the syscall.
+        #[source]
+        io_error: io::Error,
+    },
+}
 
 /// A Link.
 pub trait Link: std::fmt::Debug + 'static {
@@ -111,6 +137,24 @@ impl FdLink {
     pub(crate) fn new(fd: RawFd) -> FdLink {
         FdLink { fd }
     }
+
+    /// Pins the FdLink to a BPF filesystem.
+    ///
+    /// When a BPF object is pinned to a BPF filesystem it will remain attached after
+    /// Aya has detached the link.
+    /// To remove the attachment, the file on the BPF filesystem must be remove.
+    /// Any directories in the the path provided should have been created by the caller.
+    pub fn pin<P: AsRef<Path>>(&self, path: P) -> Result<(), LinkError> {
+        let path_string =
+            CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
+                LinkError::InvalidPinPath {
+                    error: e.to_string(),
+                }
+            })?;
+        bpf_pin_object(self.fd, &path_string)
+            .map_err(|(_code, io_error)| LinkError::PinError { io_error })?;
+        Ok(())
+    }
 }
 
 impl Link for FdLink {