aya: fix detaching links on drop

https://github.com/aya-rs/aya/pull/366 broke detaching links on drop for
everything but FdLink. This restores detach on drop for all links.
pull/474/head
Alessandro Decina 2 years ago
parent 9f5d157628
commit b3ae7786d3

@ -72,9 +72,9 @@ impl CgroupDevice {
)? as RawFd; )? as RawFd;
self.data self.data
.links .links
.insert(CgroupDeviceLink(CgroupDeviceLinkInner::Fd(FdLink::new( .insert(CgroupDeviceLink::new(CgroupDeviceLinkInner::Fd(
link_fd, FdLink::new(link_fd),
)))) )))
} else { } else {
bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE).map_err(|(_, io_error)| {
ProgramError::SyscallError { ProgramError::SyscallError {
@ -84,7 +84,7 @@ impl CgroupDevice {
})?; })?;
self.data self.data
.links .links
.insert(CgroupDeviceLink(CgroupDeviceLinkInner::ProgAttach( .insert(CgroupDeviceLink::new(CgroupDeviceLinkInner::ProgAttach(
ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE), ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE),
))) )))
} }

@ -105,7 +105,9 @@ impl CgroupSkb {
)? as RawFd; )? as RawFd;
self.data self.data
.links .links
.insert(CgroupSkbLink(CgroupSkbLinkInner::Fd(FdLink::new(link_fd)))) .insert(CgroupSkbLink::new(CgroupSkbLinkInner::Fd(FdLink::new(
link_fd,
))))
} else { } else {
bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| {
ProgramError::SyscallError { ProgramError::SyscallError {
@ -116,7 +118,7 @@ impl CgroupSkb {
self.data self.data
.links .links
.insert(CgroupSkbLink(CgroupSkbLinkInner::ProgAttach( .insert(CgroupSkbLink::new(CgroupSkbLinkInner::ProgAttach(
ProgAttachLink::new(prog_fd, cgroup_fd, attach_type), ProgAttachLink::new(prog_fd, cgroup_fd, attach_type),
))) )))
} }

@ -81,7 +81,7 @@ impl CgroupSock {
)? as RawFd; )? as RawFd;
self.data self.data
.links .links
.insert(CgroupSockLink(CgroupSockLinkInner::Fd(FdLink::new( .insert(CgroupSockLink::new(CgroupSockLinkInner::Fd(FdLink::new(
link_fd, link_fd,
)))) ))))
} else { } else {
@ -94,7 +94,7 @@ impl CgroupSock {
self.data self.data
.links .links
.insert(CgroupSockLink(CgroupSockLinkInner::ProgAttach( .insert(CgroupSockLink::new(CgroupSockLinkInner::ProgAttach(
ProgAttachLink::new(prog_fd, cgroup_fd, attach_type), ProgAttachLink::new(prog_fd, cgroup_fd, attach_type),
))) )))
} }

@ -82,7 +82,7 @@ impl CgroupSockAddr {
)? as RawFd; )? as RawFd;
self.data self.data
.links .links
.insert(CgroupSockAddrLink(CgroupSockAddrLinkInner::Fd( .insert(CgroupSockAddrLink::new(CgroupSockAddrLinkInner::Fd(
FdLink::new(link_fd), FdLink::new(link_fd),
))) )))
} else { } else {
@ -93,11 +93,13 @@ impl CgroupSockAddr {
} }
})?; })?;
self.data self.data.links.insert(CgroupSockAddrLink::new(
.links CgroupSockAddrLinkInner::ProgAttach(ProgAttachLink::new(
.insert(CgroupSockAddrLink(CgroupSockAddrLinkInner::ProgAttach( prog_fd,
ProgAttachLink::new(prog_fd, cgroup_fd, attach_type), cgroup_fd,
))) attach_type,
)),
))
} }
} }

@ -79,9 +79,9 @@ impl CgroupSockopt {
)? as RawFd; )? as RawFd;
self.data self.data
.links .links
.insert(CgroupSockoptLink(CgroupSockoptLinkInner::Fd(FdLink::new( .insert(CgroupSockoptLink::new(CgroupSockoptLinkInner::Fd(
link_fd, FdLink::new(link_fd),
)))) )))
} else { } else {
bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| {
ProgramError::SyscallError { ProgramError::SyscallError {
@ -92,7 +92,7 @@ impl CgroupSockopt {
self.data self.data
.links .links
.insert(CgroupSockoptLink(CgroupSockoptLinkInner::ProgAttach( .insert(CgroupSockoptLink::new(CgroupSockoptLinkInner::ProgAttach(
ProgAttachLink::new(prog_fd, cgroup_fd, attach_type), ProgAttachLink::new(prog_fd, cgroup_fd, attach_type),
))) )))
} }

@ -74,9 +74,9 @@ impl CgroupSysctl {
)? as RawFd; )? as RawFd;
self.data self.data
.links .links
.insert(CgroupSysctlLink(CgroupSysctlLinkInner::Fd(FdLink::new( .insert(CgroupSysctlLink::new(CgroupSysctlLinkInner::Fd(
link_fd, FdLink::new(link_fd),
)))) )))
} else { } else {
bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL).map_err(|(_, io_error)| {
ProgramError::SyscallError { ProgramError::SyscallError {
@ -87,7 +87,7 @@ impl CgroupSysctl {
self.data self.data
.links .links
.insert(CgroupSysctlLink(CgroupSysctlLinkInner::ProgAttach( .insert(CgroupSysctlLink::new(CgroupSysctlLinkInner::ProgAttach(
ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL), ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL),
))) )))
} }

@ -95,7 +95,9 @@ impl Extension {
call: "bpf_link_create".to_owned(), call: "bpf_link_create".to_owned(),
io_error, io_error,
})? as RawFd; })? as RawFd;
self.data.links.insert(ExtensionLink(FdLink::new(link_fd))) self.data
.links
.insert(ExtensionLink::new(FdLink::new(link_fd)))
} }
/// Attaches the extension to another program. /// Attaches the extension to another program.
@ -123,7 +125,9 @@ impl Extension {
call: "bpf_link_create".to_owned(), call: "bpf_link_create".to_owned(),
io_error, io_error,
})? as RawFd; })? as RawFd;
self.data.links.insert(ExtensionLink(FdLink::new(link_fd))) self.data
.links
.insert(ExtensionLink::new(FdLink::new(link_fd)))
} }
/// Detaches the extension. /// Detaches the extension.

@ -79,17 +79,17 @@ impl<T: Link> Drop for LinkMap<T> {
/// The identifier of an `FdLink`. /// The identifier of an `FdLink`.
#[derive(Debug, Hash, Eq, PartialEq)] #[derive(Debug, Hash, Eq, PartialEq)]
pub struct FdLinkId(pub(crate) Option<RawFd>); pub struct FdLinkId(pub(crate) RawFd);
/// A file descriptor link. /// A file descriptor link.
#[derive(Debug)] #[derive(Debug)]
pub struct FdLink { pub struct FdLink {
pub(crate) fd: Option<RawFd>, pub(crate) fd: RawFd,
} }
impl FdLink { impl FdLink {
pub(crate) fn new(fd: RawFd) -> FdLink { pub(crate) fn new(fd: RawFd) -> FdLink {
FdLink { fd: Some(fd) } FdLink { fd }
} }
/// Pins the link to a BPF file system. /// Pins the link to a BPF file system.
@ -121,21 +121,18 @@ impl FdLink {
/// let pinned_link = fd_link.pin("/sys/fs/bpf/example")?; /// let pinned_link = fd_link.pin("/sys/fs/bpf/example")?;
/// # Ok::<(), Error>(()) /// # Ok::<(), Error>(())
/// ``` /// ```
pub fn pin<P: AsRef<Path>>(mut self, path: P) -> Result<PinnedLink, PinError> { pub fn pin<P: AsRef<Path>>(self, path: P) -> Result<PinnedLink, PinError> {
let fd = self.fd.take().ok_or_else(|| PinError::NoFd {
name: "link".to_string(),
})?;
let path_string = let path_string =
CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| { CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
PinError::InvalidPinPath { PinError::InvalidPinPath {
error: e.to_string(), error: e.to_string(),
} }
})?; })?;
bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError { bpf_pin_object(self.fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError {
name: "BPF_OBJ_PIN".to_string(), name: "BPF_OBJ_PIN".to_string(),
io_error, io_error,
})?; })?;
Ok(PinnedLink::new(PathBuf::from(path.as_ref()), fd)) Ok(PinnedLink::new(PathBuf::from(path.as_ref()), self))
} }
} }
@ -147,27 +144,27 @@ impl Link for FdLink {
} }
fn detach(self) -> Result<(), ProgramError> { fn detach(self) -> Result<(), ProgramError> {
// detach is a noop since it consumes self. once self is consumed, // detach is a noop since it consumes self. once self is consumed, drop will be triggered
// drop will be triggered and the link will be detached. // and the link will be detached.
//
// Other links don't need to do this since they use define_link_wrapper!, but FdLink is a
// bit special in that it defines a custom ::new() so it can't use the macro.
Ok(()) Ok(())
} }
} }
impl Drop for FdLink {
fn drop(&mut self) {
if let Some(fd) = self.fd.take() {
// Safety: libc
unsafe { close(fd) };
}
}
}
impl From<PinnedLink> for FdLink { impl From<PinnedLink> for FdLink {
fn from(p: PinnedLink) -> Self { fn from(p: PinnedLink) -> Self {
p.inner p.inner
} }
} }
impl Drop for FdLink {
fn drop(&mut self) {
unsafe { close(self.fd) };
}
}
/// A pinned file descriptor link. /// A pinned file descriptor link.
/// ///
/// This link has been pinned to the BPF filesystem. On drop, the file descriptor that backs /// This link has been pinned to the BPF filesystem. On drop, the file descriptor that backs
@ -180,11 +177,8 @@ pub struct PinnedLink {
} }
impl PinnedLink { impl PinnedLink {
fn new(path: PathBuf, fd: RawFd) -> Self { fn new(path: PathBuf, link: FdLink) -> Self {
PinnedLink { PinnedLink { inner: link, path }
inner: FdLink::new(fd),
path,
}
} }
/// Creates a [`PinnedLink`] from a valid path on bpffs. /// Creates a [`PinnedLink`] from a valid path on bpffs.
@ -196,7 +190,10 @@ impl PinnedLink {
code, code,
io_error, io_error,
})? as RawFd; })? as RawFd;
Ok(PinnedLink::new(path.as_ref().to_path_buf(), fd)) Ok(PinnedLink::new(
path.as_ref().to_path_buf(),
FdLink::new(fd),
))
} }
/// Removes the pinned link from the filesystem and returns an [`FdLink`]. /// Removes the pinned link from the filesystem and returns an [`FdLink`].
@ -254,29 +251,56 @@ macro_rules! define_link_wrapper {
#[$doc1] #[$doc1]
#[derive(Debug)] #[derive(Debug)]
pub struct $wrapper($base); pub struct $wrapper(Option<$base>);
#[allow(dead_code)]
// allow dead code since currently XDP is the only consumer of inner and
// into_inner
impl $wrapper {
fn new(base: $base) -> $wrapper {
$wrapper(Some(base))
}
fn inner(&self) -> &$base {
self.0.as_ref().unwrap()
}
fn into_inner(mut self) -> $base {
self.0.take().unwrap()
}
}
impl Drop for $wrapper {
fn drop(&mut self) {
use crate::programs::links::Link;
if let Some(base) = self.0.take() {
let _ = base.detach();
}
}
}
impl crate::programs::Link for $wrapper { impl crate::programs::Link for $wrapper {
type Id = $wrapper_id; type Id = $wrapper_id;
fn id(&self) -> Self::Id { fn id(&self) -> Self::Id {
$wrapper_id(self.0.id()) $wrapper_id(self.0.as_ref().unwrap().id())
} }
fn detach(self) -> Result<(), ProgramError> { fn detach(mut self) -> Result<(), ProgramError> {
self.0.detach() self.0.take().unwrap().detach()
} }
} }
impl From<$base> for $wrapper { impl From<$base> for $wrapper {
fn from(b: $base) -> $wrapper { fn from(b: $base) -> $wrapper {
$wrapper(b) $wrapper(Some(b))
} }
} }
impl From<$wrapper> for $base { impl From<$wrapper> for $base {
fn from(w: $wrapper) -> $base { fn from(mut w: $wrapper) -> $base {
w.0 w.0.take().unwrap()
} }
} }
}; };

@ -70,7 +70,9 @@ impl SkLookup {
io_error, io_error,
}, },
)? as RawFd; )? as RawFd;
self.data.links.insert(SkLookupLink(FdLink::new(link_fd))) self.data
.links
.insert(SkLookupLink::new(FdLink::new(link_fd)))
} }
/// Takes ownership of the link referenced by the provided link_id. /// Takes ownership of the link referenced by the provided link_id.

@ -88,7 +88,7 @@ impl SkMsg {
io_error, io_error,
} }
})?; })?;
self.data.links.insert(SkMsgLink(ProgAttachLink::new( self.data.links.insert(SkMsgLink::new(ProgAttachLink::new(
prog_fd, prog_fd,
map_fd, map_fd,
BPF_SK_MSG_VERDICT, BPF_SK_MSG_VERDICT,

@ -84,9 +84,11 @@ impl SkSkb {
io_error, io_error,
} }
})?; })?;
self.data self.data.links.insert(SkSkbLink::new(ProgAttachLink::new(
.links prog_fd,
.insert(SkSkbLink(ProgAttachLink::new(prog_fd, map_fd, attach_type))) map_fd,
attach_type,
)))
} }
/// Detaches the program. /// Detaches the program.

@ -68,7 +68,7 @@ impl SockOps {
io_error, io_error,
} }
})?; })?;
self.data.links.insert(SockOpsLink(ProgAttachLink::new( self.data.links.insert(SockOpsLink::new(ProgAttachLink::new(
prog_fd, prog_fd,
cgroup_fd, cgroup_fd,
BPF_CGROUP_SOCK_OPS, BPF_CGROUP_SOCK_OPS,

@ -165,7 +165,7 @@ impl SchedClassifier {
} }
.map_err(|io_error| TcError::NetlinkError { io_error })?; .map_err(|io_error| TcError::NetlinkError { io_error })?;
self.data.links.insert(SchedClassifierLink(TcLink { self.data.links.insert(SchedClassifierLink::new(TcLink {
if_index: if_index as i32, if_index: if_index as i32,
attach_type, attach_type,
priority, priority,

@ -117,16 +117,18 @@ impl Xdp {
)? as RawFd; )? as RawFd;
self.data self.data
.links .links
.insert(XdpLink(XdpLinkInner::FdLink(FdLink::new(link_fd)))) .insert(XdpLink::new(XdpLinkInner::FdLink(FdLink::new(link_fd))))
} else { } else {
unsafe { netlink_set_xdp_fd(if_index, prog_fd, None, flags.bits) } unsafe { netlink_set_xdp_fd(if_index, prog_fd, None, flags.bits) }
.map_err(|io_error| XdpError::NetlinkError { io_error })?; .map_err(|io_error| XdpError::NetlinkError { io_error })?;
self.data.links.insert(XdpLink(XdpLinkInner::NlLink(NlLink { self.data
if_index, .links
prog_fd, .insert(XdpLink::new(XdpLinkInner::NlLink(NlLink {
flags, if_index,
}))) prog_fd,
flags,
})))
} }
} }
@ -150,9 +152,9 @@ impl Xdp {
/// Ownership of the link will transfer to this program. /// Ownership of the link will transfer to this program.
pub fn attach_to_link(&mut self, link: XdpLink) -> Result<XdpLinkId, ProgramError> { pub fn attach_to_link(&mut self, link: XdpLink) -> Result<XdpLinkId, ProgramError> {
let prog_fd = self.data.fd_or_err()?; let prog_fd = self.data.fd_or_err()?;
match &link.0 { match link.inner() {
XdpLinkInner::FdLink(fd_link) => { XdpLinkInner::FdLink(fd_link) => {
let link_fd = fd_link.fd.unwrap(); let link_fd = fd_link.fd;
bpf_link_update(link_fd, prog_fd, None, 0).map_err(|(_, io_error)| { bpf_link_update(link_fd, prog_fd, None, 0).map_err(|(_, io_error)| {
ProgramError::SyscallError { ProgramError::SyscallError {
call: "bpf_link_update".to_string(), call: "bpf_link_update".to_string(),
@ -163,7 +165,7 @@ impl Xdp {
mem::forget(link); mem::forget(link);
self.data self.data
.links .links
.insert(XdpLink(XdpLinkInner::FdLink(FdLink::new(link_fd)))) .insert(XdpLink::new(XdpLinkInner::FdLink(FdLink::new(link_fd))))
} }
XdpLinkInner::NlLink(nl_link) => { XdpLinkInner::NlLink(nl_link) => {
let if_index = nl_link.if_index; let if_index = nl_link.if_index;
@ -176,11 +178,13 @@ impl Xdp {
} }
// dispose of link and avoid detach on drop // dispose of link and avoid detach on drop
mem::forget(link); mem::forget(link);
self.data.links.insert(XdpLink(XdpLinkInner::NlLink(NlLink { self.data
if_index, .links
prog_fd, .insert(XdpLink::new(XdpLinkInner::NlLink(NlLink {
flags, if_index,
}))) prog_fd,
flags,
})))
} }
} }
} }
@ -246,7 +250,7 @@ impl TryFrom<XdpLink> for FdLink {
type Error = LinkError; type Error = LinkError;
fn try_from(value: XdpLink) -> Result<Self, Self::Error> { fn try_from(value: XdpLink) -> Result<Self, Self::Error> {
if let XdpLinkInner::FdLink(fd) = value.0 { if let XdpLinkInner::FdLink(fd) = value.into_inner() {
Ok(fd) Ok(fd)
} else { } else {
Err(LinkError::InvalidLink) Err(LinkError::InvalidLink)
@ -259,15 +263,14 @@ impl TryFrom<FdLink> for XdpLink {
fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> { fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> {
// unwrap of fd_link.fd will not panic since it's only None when being dropped. // unwrap of fd_link.fd will not panic since it's only None when being dropped.
let info = bpf_link_get_info_by_fd(fd_link.fd.unwrap()).map_err(|io_error| { let info =
LinkError::SyscallError { bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| LinkError::SyscallError {
call: "BPF_OBJ_GET_INFO_BY_FD".to_string(), call: "BPF_OBJ_GET_INFO_BY_FD".to_string(),
code: 0, code: 0,
io_error, io_error,
} })?;
})?;
if info.type_ == (bpf_link_type::BPF_LINK_TYPE_XDP as u32) { if info.type_ == (bpf_link_type::BPF_LINK_TYPE_XDP as u32) {
return Ok(XdpLink(XdpLinkInner::FdLink(fd_link))); return Ok(XdpLink::new(XdpLinkInner::FdLink(fd_link)));
} }
Err(LinkError::InvalidLink) Err(LinkError::InvalidLink)
} }

@ -1,9 +1,13 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use aya_bpf::{bindings::xdp_action, macros::xdp, programs::XdpContext}; use aya_bpf::{
bindings::xdp_action,
macros::{kprobe, xdp},
programs::{ProbeContext, XdpContext},
};
#[xdp(name = "test_unload")] #[xdp(name = "test_unload_xdp")]
pub fn pass(ctx: XdpContext) -> u32 { pub fn pass(ctx: XdpContext) -> u32 {
match unsafe { try_pass(ctx) } { match unsafe { try_pass(ctx) } {
Ok(ret) => ret, Ok(ret) => ret,
@ -15,6 +19,12 @@ unsafe fn try_pass(_ctx: XdpContext) -> Result<u32, u32> {
Ok(xdp_action::XDP_PASS) Ok(xdp_action::XDP_PASS)
} }
#[kprobe]
// truncated name to match bpftool output
pub fn test_unload_kpr(_ctx: ProbeContext) -> u32 {
0
}
#[panic_handler] #[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! { fn panic(_info: &core::panic::PanicInfo) -> ! {
unsafe { core::hint::unreachable_unchecked() } unsafe { core::hint::unreachable_unchecked() }

@ -5,7 +5,7 @@ use aya::{
maps::Array, maps::Array,
programs::{ programs::{
links::{FdLink, PinnedLink}, links::{FdLink, PinnedLink},
TracePoint, Xdp, XdpFlags, KProbe, TracePoint, Xdp, XdpFlags,
}, },
Bpf, Bpf,
}; };
@ -84,28 +84,63 @@ macro_rules! assert_loaded {
} }
#[integration_test] #[integration_test]
fn unload() { fn unload_xdp() {
let bytes = include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/test"); let bytes = include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/test");
let mut bpf = Bpf::load(bytes).unwrap(); let mut bpf = Bpf::load(bytes).unwrap();
let prog: &mut Xdp = bpf.program_mut("test_unload").unwrap().try_into().unwrap(); let prog: &mut Xdp = bpf
.program_mut("test_unload_xdp")
.unwrap()
.try_into()
.unwrap();
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_unload_xdp", true);
let link = prog.attach("lo", XdpFlags::default()).unwrap(); let link = prog.attach("lo", XdpFlags::default()).unwrap();
{ {
let _link_owned = prog.take_link(link); let _link_owned = prog.take_link(link).unwrap();
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("test_unload", true); assert_loaded!("test_unload_xdp", true);
}; };
assert_loaded!("test_unload", false); assert_loaded!("test_unload_xdp", false);
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_unload", true); assert_loaded!("test_unload_xdp", true);
prog.attach("lo", XdpFlags::default()).unwrap(); prog.attach("lo", XdpFlags::default()).unwrap();
assert_loaded!("test_unload", true); assert_loaded!("test_unload_xdp", true);
prog.unload().unwrap();
assert_loaded!("test_unload_xdp", false);
}
#[integration_test]
fn unload_kprobe() {
let bytes = include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/test");
let mut bpf = Bpf::load(bytes).unwrap();
let prog: &mut KProbe = bpf
.program_mut("test_unload_kpr")
.unwrap()
.try_into()
.unwrap();
prog.load().unwrap();
assert_loaded!("test_unload_kpr", true);
let link = prog.attach("try_to_wake_up", 0).unwrap();
{
let _link_owned = prog.take_link(link).unwrap();
prog.unload().unwrap();
assert_loaded!("test_unload_kpr", true);
};
assert_loaded!("test_unload_kpr", false);
prog.load().unwrap();
assert_loaded!("test_unload_kpr", true);
prog.attach("try_to_wake_up", 0).unwrap();
assert_loaded!("test_unload_kpr", true);
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("test_unload", false); assert_loaded!("test_unload_kpr", false);
} }
#[integration_test] #[integration_test]
@ -117,26 +152,30 @@ fn pin_link() {
let bytes = include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/test"); let bytes = include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/test");
let mut bpf = Bpf::load(bytes).unwrap(); let mut bpf = Bpf::load(bytes).unwrap();
let prog: &mut Xdp = bpf.program_mut("test_unload").unwrap().try_into().unwrap(); let prog: &mut Xdp = bpf
.program_mut("test_unload_xdp")
.unwrap()
.try_into()
.unwrap();
prog.load().unwrap(); prog.load().unwrap();
let link_id = prog.attach("lo", XdpFlags::default()).unwrap(); let link_id = prog.attach("lo", XdpFlags::default()).unwrap();
let link = prog.take_link(link_id).unwrap(); let link = prog.take_link(link_id).unwrap();
assert_loaded!("test_unload", true); assert_loaded!("test_unload_xdp", true);
let fd_link: FdLink = link.try_into().unwrap(); let fd_link: FdLink = link.try_into().unwrap();
let pinned = fd_link.pin("/sys/fs/bpf/aya-xdp-test-lo").unwrap(); let pinned = fd_link.pin("/sys/fs/bpf/aya-xdp-test-lo").unwrap();
// because of the pin, the program is still attached // because of the pin, the program is still attached
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("test_unload", true); assert_loaded!("test_unload_xdp", true);
// delete the pin, but the program is still attached // delete the pin, but the program is still attached
let new_link = pinned.unpin().unwrap(); let new_link = pinned.unpin().unwrap();
assert_loaded!("test_unload", true); assert_loaded!("test_unload_xdp", true);
// finally when new_link is dropped we're detached // finally when new_link is dropped we're detached
drop(new_link); drop(new_link);
assert_loaded!("test_unload", false); assert_loaded!("test_unload_xdp", false);
} }
#[integration_test] #[integration_test]

Loading…
Cancel
Save