Browse Source

aya: Implement attach_to_link for XDP

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

+ 42 - 2
aya/src/programs/xdp.rs

@@ -1,7 +1,7 @@
 //! eXpress Data Path (XDP) programs.
 use bitflags;
 use libc::if_nametoindex;
-use std::{ffi::CString, hash::Hash, io, os::unix::io::RawFd};
+use std::{ffi::CString, hash::Hash, io, mem, os::unix::io::RawFd};
 use thiserror::Error;
 
 use crate::{
@@ -14,7 +14,7 @@ use crate::{
     programs::{
         define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgramData, ProgramError,
     },
-    sys::{bpf_link_create, kernel_version, netlink_set_xdp_fd},
+    sys::{bpf_link_create, bpf_link_update, kernel_version, netlink_set_xdp_fd},
 };
 
 /// The type returned when attaching an [`Xdp`] program fails on kernels `< 5.9`.
@@ -141,6 +141,46 @@ impl Xdp {
     pub fn take_link(&mut self, link_id: XdpLinkId) -> Result<OwnedLink<XdpLink>, ProgramError> {
         Ok(OwnedLink::new(self.data.take_link(link_id)?))
     }
+
+    /// Atomically replaces the program referenced by the provided link.
+    ///
+    /// Ownership of the link will transfer to this program.
+    pub fn attach_to_link(&mut self, link: OwnedLink<XdpLink>) -> Result<XdpLinkId, ProgramError> {
+        let prog_fd = self.data.fd_or_err()?;
+        match &link.0 {
+            XdpLinkInner::FdLink(fd_link) => {
+                let link_fd = fd_link.fd;
+                bpf_link_update(link_fd, prog_fd, None, 0).map_err(|(_, io_error)| {
+                    ProgramError::SyscallError {
+                        call: "bpf_link_update".to_string(),
+                        io_error,
+                    }
+                })?;
+                // dispose of link and avoid detach on drop
+                mem::forget(link);
+                self.data
+                    .links
+                    .insert(XdpLink(XdpLinkInner::FdLink(FdLink::new(link_fd))))
+            }
+            XdpLinkInner::NlLink(nl_link) => {
+                let if_index = nl_link.if_index;
+                let old_prog_fd = nl_link.prog_fd;
+                let flags = nl_link.flags;
+                let replace_flags = flags | XdpFlags::REPLACE;
+                unsafe {
+                    netlink_set_xdp_fd(if_index, prog_fd, Some(old_prog_fd), replace_flags.bits())
+                        .map_err(|io_error| XdpError::NetlinkError { io_error })?;
+                }
+                // dispose of link and avoid detach on drop
+                mem::forget(link);
+                self.data.links.insert(XdpLink(XdpLinkInner::NlLink(NlLink {
+                    if_index,
+                    prog_fd,
+                    flags,
+                })))
+            }
+        }
+    }
 }
 
 #[derive(Debug)]