Add links iterator

This is not yet exposed in documentation, but is complete enough for use
in tests, removing the dependency on bpftool.

Updates #645.
reviewable/pr712/r19
Tamir Duberstein 1 year ago
parent 7bb9b7f5a5
commit 30faa5f68f

@ -104,14 +104,15 @@ pub use uprobe::{UProbe, UProbeError};
pub use xdp::{Xdp, XdpError, XdpFlags}; pub use xdp::{Xdp, XdpError, XdpFlags};
use crate::{ use crate::{
generated::{bpf_attach_type, bpf_prog_info, bpf_prog_type}, generated::{bpf_attach_type, bpf_link_info, bpf_prog_info, bpf_prog_type},
maps::MapError, maps::MapError,
obj::{self, btf::BtfError, Function, VerifierLog}, obj::{self, btf::BtfError, Function, VerifierLog},
pin::PinError, pin::PinError,
sys::{ sys::{
bpf_btf_get_fd_by_id, bpf_get_object, bpf_load_program, bpf_pin_object, bpf_btf_get_fd_by_id, bpf_get_object, bpf_link_get_fd_by_id, bpf_link_get_info_by_fd,
bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_query, iter_prog_ids, bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd,
retry_with_verifier_logs, BpfLoadProgramAttrs, SyscallError, bpf_prog_query, iter_link_ids, iter_prog_ids, retry_with_verifier_logs,
BpfLoadProgramAttrs, SyscallError,
}, },
util::KernelVersion, util::KernelVersion,
VerifierLogLevel, VerifierLogLevel,
@ -998,3 +999,19 @@ pub fn loaded_programs() -> impl Iterator<Item = Result<ProgramInfo, ProgramErro
}) })
.map(|result| result.map(ProgramInfo).map_err(Into::into)) .map(|result| result.map(ProgramInfo).map_err(Into::into))
} }
// TODO(https://github.com/aya-rs/aya/issues/645): this API is currently used in tests. Stabilize
// and remove doc(hidden).
#[doc(hidden)]
pub fn loaded_links() -> impl Iterator<Item = Result<bpf_link_info, ProgramError>> {
iter_link_ids()
.map(|id| {
let id = id?;
bpf_link_get_fd_by_id(id)
})
.map(|fd| {
let fd = fd?;
bpf_link_get_info_by_fd(fd.as_raw_fd())
})
.map(|result| result.map_err(Into::into))
}

@ -508,6 +508,20 @@ pub(crate) fn bpf_map_get_info_by_fd(fd: RawFd) -> Result<bpf_map_info, SyscallE
bpf_obj_get_info_by_fd::<bpf_map_info>(fd) bpf_obj_get_info_by_fd::<bpf_map_info>(fd)
} }
pub(crate) fn bpf_link_get_fd_by_id(link_id: u32) -> Result<OwnedFd, SyscallError> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
attr.__bindgen_anon_6.__bindgen_anon_1.link_id = link_id;
// SAFETY: BPF_LINK_GET_FD_BY_ID returns a new file descriptor.
unsafe { fd_sys_bpf(bpf_cmd::BPF_LINK_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| {
assert_eq!(code, -1);
SyscallError {
call: "bpf_link_get_fd_by_id",
io_error,
}
})
}
pub(crate) fn bpf_link_get_info_by_fd(fd: RawFd) -> Result<bpf_link_info, SyscallError> { pub(crate) fn bpf_link_get_info_by_fd(fd: RawFd) -> Result<bpf_link_info, SyscallError> {
let fd = unsafe { BorrowedFd::borrow_raw(fd) }; let fd = unsafe { BorrowedFd::borrow_raw(fd) };
bpf_obj_get_info_by_fd::<bpf_link_info>(fd) bpf_obj_get_info_by_fd::<bpf_link_info>(fd)
@ -909,11 +923,15 @@ fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult<c_long> {
syscall(Syscall::Bpf { cmd, attr }) syscall(Syscall::Bpf { cmd, attr })
} }
fn bpf_prog_get_next_id(id: u32) -> Result<Option<u32>, SyscallError> { fn bpf_obj_get_next_id(
id: u32,
cmd: bpf_cmd,
name: &'static str,
) -> Result<Option<u32>, SyscallError> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let u = unsafe { &mut attr.__bindgen_anon_6 }; let u = unsafe { &mut attr.__bindgen_anon_6 };
u.__bindgen_anon_1.start_id = id; u.__bindgen_anon_1.start_id = id;
match sys_bpf(bpf_cmd::BPF_PROG_GET_NEXT_ID, &mut attr) { match sys_bpf(cmd, &mut attr) {
Ok(code) => { Ok(code) => {
assert_eq!(code, 0); assert_eq!(code, 0);
Ok(Some(unsafe { attr.__bindgen_anon_6.next_id })) Ok(Some(unsafe { attr.__bindgen_anon_6.next_id }))
@ -924,7 +942,7 @@ fn bpf_prog_get_next_id(id: u32) -> Result<Option<u32>, SyscallError> {
Ok(None) Ok(None)
} else { } else {
Err(SyscallError { Err(SyscallError {
call: "bpf_prog_get_next_id", call: name,
io_error, io_error,
}) })
} }
@ -932,12 +950,15 @@ fn bpf_prog_get_next_id(id: u32) -> Result<Option<u32>, SyscallError> {
} }
} }
pub(crate) fn iter_prog_ids() -> impl Iterator<Item = Result<u32, SyscallError>> { fn iter_obj_ids(
cmd: bpf_cmd,
name: &'static str,
) -> impl Iterator<Item = Result<u32, SyscallError>> {
let mut current_id = Some(0); let mut current_id = Some(0);
iter::from_fn(move || { iter::from_fn(move || {
let next_id = { let next_id = {
let current_id = current_id?; let current_id = current_id?;
bpf_prog_get_next_id(current_id).transpose() bpf_obj_get_next_id(current_id, cmd, name).transpose()
}; };
current_id = next_id.as_ref().and_then(|next_id| match next_id { current_id = next_id.as_ref().and_then(|next_id| match next_id {
Ok(next_id) => Some(*next_id), Ok(next_id) => Some(*next_id),
@ -947,6 +968,14 @@ pub(crate) fn iter_prog_ids() -> impl Iterator<Item = Result<u32, SyscallError>>
}) })
} }
pub(crate) fn iter_prog_ids() -> impl Iterator<Item = Result<u32, SyscallError>> {
iter_obj_ids(bpf_cmd::BPF_PROG_GET_NEXT_ID, "bpf_prog_get_next_id")
}
pub(crate) fn iter_link_ids() -> impl Iterator<Item = Result<u32, SyscallError>> {
iter_obj_ids(bpf_cmd::BPF_LINK_GET_NEXT_ID, "bpf_link_get_next_id")
}
pub(crate) fn retry_with_verifier_logs<T>( pub(crate) fn retry_with_verifier_logs<T>(
max_retries: usize, max_retries: usize,
f: impl Fn(&mut [u8]) -> SysResult<T>, f: impl Fn(&mut [u8]) -> SysResult<T>,

@ -11,7 +11,6 @@ To run locally all you need is:
1. Rust nightly 1. Rust nightly
1. `cargo install bpf-linker` 1. `cargo install bpf-linker`
1. `bpftool` [^1]
### Other OSs ### Other OSs
@ -52,5 +51,3 @@ Tests should follow these guidelines:
- You may add a new module, or use an existing one. - You may add a new module, or use an existing one.
- Test functions should not return `anyhow::Result<()>` since this produces errors without stack - Test functions should not return `anyhow::Result<()>` since this produces errors without stack
traces. Prefer to `panic!` instead. traces. Prefer to `panic!` instead.
[^1]: TODO(https://github.com/aya-rs/aya/issues/645): Remove this dependency.

@ -1,17 +1,17 @@
use std::{convert::TryInto as _, process::Command, thread, time}; use std::{convert::TryInto as _, thread, time};
use aya::{ use aya::{
maps::Array, maps::Array,
programs::{ programs::{
links::{FdLink, PinnedLink}, links::{FdLink, PinnedLink},
loaded_programs, KProbe, TracePoint, UProbe, Xdp, XdpFlags, loaded_links, loaded_programs, KProbe, TracePoint, UProbe, Xdp, XdpFlags,
}, },
util::KernelVersion, util::KernelVersion,
Bpf, Bpf,
}; };
const MAX_RETRIES: u32 = 100; const MAX_RETRIES: usize = 100;
const RETRY_DURATION_MS: u64 = 10; const RETRY_DURATION: time::Duration = time::Duration::from_millis(10);
#[test] #[test]
fn long_name() { fn long_name() {
@ -50,61 +50,67 @@ fn multiple_btf_maps() {
assert_eq!(val_2, 42); assert_eq!(val_2, 42);
} }
fn is_linked(prog_id: &u32) -> bool { fn poll_loaded_program_id(name: &str) -> impl Iterator<Item = Option<u32>> + '_ {
let output = Command::new("bpftool").args(["link"]).output(); std::iter::once(true)
let output = output.expect("Failed to run 'bpftool link'"); .chain(std::iter::repeat(false))
let stdout = String::from_utf8(output.stdout).unwrap(); .map(|first| {
stdout.contains(&prog_id.to_string()) if !first {
thread::sleep(RETRY_DURATION);
} }
macro_rules! assert_loaded_and_linked {
($name:literal, $loaded:expr) => {
for i in 0..(MAX_RETRIES + 1) {
// Ignore race failures which can happen when the tests delete a // Ignore race failures which can happen when the tests delete a
// program in the middle of a `loaded_programs()` call. // program in the middle of a `loaded_programs()` call.
let id = loaded_programs() loaded_programs()
.filter_map(|prog| prog.ok()) .filter_map(|prog| prog.ok())
.find(|prog| prog.name() == $name.as_bytes()) .find_map(|prog| (prog.name() == name.as_bytes()).then(|| prog.id()))
.map(|prog| Some(prog.id())); })
let mut linked = false; }
if let Some(prog_id) = id {
linked = is_linked(&prog_id.unwrap()); #[track_caller]
if linked == $loaded { fn assert_loaded_and_linked(name: &str) {
break; let (attempts_used, prog_id) = poll_loaded_program_id(name)
} .take(MAX_RETRIES)
} .enumerate()
.find_map(|(i, id)| id.map(|id| (i, id)))
if i == MAX_RETRIES { .unwrap_or_else(|| panic!("{name} not loaded after {MAX_RETRIES}"));
panic!( let poll_loaded_link_id = std::iter::once(true)
"Expected (loaded/linked: {}) but found (id: {}, linked: {}", .chain(std::iter::repeat(false))
$loaded, .map(|first| {
id.is_some(), if !first {
linked thread::sleep(RETRY_DURATION);
);
}
thread::sleep(time::Duration::from_millis(RETRY_DURATION_MS));
}
};
} }
macro_rules! assert_loaded {
($name:literal, $loaded:expr) => {
for i in 0..(MAX_RETRIES + 1) {
// Ignore race failures which can happen when the tests delete a // Ignore race failures which can happen when the tests delete a
// program in the middle of a `loaded_programs()` call. // program in the middle of a `loaded_programs()` call.
let state = loaded_programs() loaded_links()
.filter_map(|prog| prog.ok()) .filter_map(|link| link.ok())
.any(|prog| prog.name() == $name.as_bytes()); .find_map(|link| (link.prog_id == prog_id).then_some(link.id))
});
if state == $loaded { assert!(
break; poll_loaded_link_id
} .take(MAX_RETRIES)
if i == MAX_RETRIES { .skip(attempts_used)
panic!("Expected loaded: {} but was loaded: {}", $loaded, state); .any(|id| id.is_some()),
"{name} not linked after {MAX_RETRIES}"
);
} }
thread::sleep(time::Duration::from_millis(RETRY_DURATION_MS));
#[track_caller]
fn assert_loaded(name: &str) {
assert!(
poll_loaded_program_id(name)
.take(MAX_RETRIES)
.any(|id| id.is_some()),
"{name} not loaded after {MAX_RETRIES}"
)
} }
};
#[track_caller]
fn assert_unloaded(name: &str) {
assert!(
poll_loaded_program_id(name)
.take(MAX_RETRIES)
.any(|id| id.is_none()),
"{name} still loaded after {MAX_RETRIES}"
)
} }
#[test] #[test]
@ -112,24 +118,24 @@ fn unload_xdp() {
let mut bpf = Bpf::load(crate::TEST).unwrap(); let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); let prog: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap();
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("pass", true); assert_loaded("pass");
let link = prog.attach("lo", XdpFlags::default()).unwrap(); let link = prog.attach("lo", XdpFlags::default()).unwrap();
{ {
let _link_owned = prog.take_link(link).unwrap(); let _link_owned = prog.take_link(link).unwrap();
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded_and_linked!("pass", true); assert_loaded_and_linked("pass");
}; };
assert_loaded!("pass", false); assert_unloaded("pass");
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("pass", true); assert_loaded("pass");
prog.attach("lo", XdpFlags::default()).unwrap(); prog.attach("lo", XdpFlags::default()).unwrap();
assert_loaded!("pass", true); assert_loaded("pass");
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("pass", false); assert_unloaded("pass");
} }
#[test] #[test]
@ -137,24 +143,24 @@ fn unload_kprobe() {
let mut bpf = Bpf::load(crate::TEST).unwrap(); let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut KProbe = bpf.program_mut("test_kprobe").unwrap().try_into().unwrap(); let prog: &mut KProbe = bpf.program_mut("test_kprobe").unwrap().try_into().unwrap();
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_kprobe", true); assert_loaded("test_kprobe");
let link = prog.attach("try_to_wake_up", 0).unwrap(); let link = prog.attach("try_to_wake_up", 0).unwrap();
{ {
let _link_owned = prog.take_link(link).unwrap(); let _link_owned = prog.take_link(link).unwrap();
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded_and_linked!("test_kprobe", true); assert_loaded_and_linked("test_kprobe");
}; };
assert_loaded!("test_kprobe", false); assert_unloaded("test_kprobe");
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_kprobe", true); assert_loaded("test_kprobe");
prog.attach("try_to_wake_up", 0).unwrap(); prog.attach("try_to_wake_up", 0).unwrap();
assert_loaded!("test_kprobe", true); assert_loaded("test_kprobe");
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("test_kprobe", false); assert_unloaded("test_kprobe");
} }
#[test] #[test]
@ -167,25 +173,25 @@ fn basic_tracepoint() {
.unwrap(); .unwrap();
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_tracepoint", true); assert_loaded("test_tracepoint");
let link = prog.attach("syscalls", "sys_enter_kill").unwrap(); let link = prog.attach("syscalls", "sys_enter_kill").unwrap();
{ {
let _link_owned = prog.take_link(link).unwrap(); let _link_owned = prog.take_link(link).unwrap();
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded_and_linked!("test_tracepoint", true); assert_loaded_and_linked("test_tracepoint");
}; };
assert_loaded!("test_tracepoint", false); assert_unloaded("test_tracepoint");
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_tracepoint", true); assert_loaded("test_tracepoint");
prog.attach("syscalls", "sys_enter_kill").unwrap(); prog.attach("syscalls", "sys_enter_kill").unwrap();
assert_loaded!("test_tracepoint", true); assert_loaded("test_tracepoint");
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("test_tracepoint", false); assert_unloaded("test_tracepoint");
} }
#[test] #[test]
@ -194,25 +200,25 @@ fn basic_uprobe() {
let prog: &mut UProbe = bpf.program_mut("test_uprobe").unwrap().try_into().unwrap(); let prog: &mut UProbe = bpf.program_mut("test_uprobe").unwrap().try_into().unwrap();
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_uprobe", true); assert_loaded("test_uprobe");
let link = prog.attach(Some("sleep"), 0, "libc", None).unwrap(); let link = prog.attach(Some("sleep"), 0, "libc", None).unwrap();
{ {
let _link_owned = prog.take_link(link).unwrap(); let _link_owned = prog.take_link(link).unwrap();
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded_and_linked!("test_uprobe", true); assert_loaded_and_linked("test_uprobe");
}; };
assert_loaded!("test_uprobe", false); assert_unloaded("test_uprobe");
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_uprobe", true); assert_loaded("test_uprobe");
prog.attach(Some("sleep"), 0, "libc", None).unwrap(); prog.attach(Some("sleep"), 0, "libc", None).unwrap();
assert_loaded!("test_uprobe", true); assert_loaded("test_uprobe");
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("test_uprobe", false); assert_unloaded("test_uprobe");
} }
#[test] #[test]
@ -228,22 +234,22 @@ fn pin_link() {
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!("pass", true); assert_loaded("pass");
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!("pass", true); assert_loaded("pass");
// 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!("pass", true); assert_loaded("pass");
// 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!("pass", false); assert_unloaded("pass");
} }
#[test] #[test]
@ -263,7 +269,7 @@ fn pin_lifecycle() {
} }
// should still be loaded since prog was pinned // should still be loaded since prog was pinned
assert_loaded!("pass", true); assert_loaded("pass");
// 2. Load program from bpffs but don't attach it // 2. Load program from bpffs but don't attach it
{ {
@ -271,7 +277,7 @@ fn pin_lifecycle() {
} }
// should still be loaded since prog was pinned // should still be loaded since prog was pinned
assert_loaded!("pass", true); assert_loaded("pass");
// 3. Load program from bpffs and attach // 3. Load program from bpffs and attach
{ {
@ -286,7 +292,7 @@ fn pin_lifecycle() {
} }
// should still be loaded since link was pinned // should still be loaded since link was pinned
assert_loaded_and_linked!("pass", true); assert_loaded_and_linked("pass");
// 4. Load a new version of the program, unpin link, and atomically replace old program // 4. Load a new version of the program, unpin link, and atomically replace old program
{ {
@ -299,11 +305,11 @@ fn pin_lifecycle() {
.unpin() .unpin()
.unwrap(); .unwrap();
prog.attach_to_link(link.try_into().unwrap()).unwrap(); prog.attach_to_link(link.try_into().unwrap()).unwrap();
assert_loaded!("pass", true); assert_loaded("pass");
} }
// program should be unloaded // program should be unloaded
assert_loaded!("pass", false); assert_unloaded("pass");
} }
#[test] #[test]
@ -321,7 +327,7 @@ fn pin_lifecycle_tracepoint() {
} }
// should still be loaded since prog was pinned // should still be loaded since prog was pinned
assert_loaded!("test_tracepoint", true); assert_loaded("test_tracepoint");
// 2. Load program from bpffs but don't attach it // 2. Load program from bpffs but don't attach it
{ {
@ -329,7 +335,7 @@ fn pin_lifecycle_tracepoint() {
} }
// should still be loaded since prog was pinned // should still be loaded since prog was pinned
assert_loaded!("test_tracepoint", true); assert_loaded("test_tracepoint");
// 3. Load program from bpffs and attach // 3. Load program from bpffs and attach
{ {
@ -346,7 +352,7 @@ fn pin_lifecycle_tracepoint() {
} }
// should still be loaded since link was pinned // should still be loaded since link was pinned
assert_loaded_and_linked!("test_tracepoint", true); assert_loaded_and_linked("test_tracepoint");
// 4. unpin link, and make sure everything is unloaded // 4. unpin link, and make sure everything is unloaded
{ {
@ -357,7 +363,7 @@ fn pin_lifecycle_tracepoint() {
} }
// program should be unloaded // program should be unloaded
assert_loaded!("test_tracepoint", false); assert_unloaded("test_tracepoint");
} }
#[test] #[test]
@ -371,7 +377,7 @@ fn pin_lifecycle_kprobe() {
} }
// should still be loaded since prog was pinned // should still be loaded since prog was pinned
assert_loaded!("test_kprobe", true); assert_loaded("test_kprobe");
// 2. Load program from bpffs but don't attach it // 2. Load program from bpffs but don't attach it
{ {
@ -383,7 +389,7 @@ fn pin_lifecycle_kprobe() {
} }
// should still be loaded since prog was pinned // should still be loaded since prog was pinned
assert_loaded!("test_kprobe", true); assert_loaded("test_kprobe");
// 3. Load program from bpffs and attach // 3. Load program from bpffs and attach
{ {
@ -404,7 +410,7 @@ fn pin_lifecycle_kprobe() {
} }
// should still be loaded since link was pinned // should still be loaded since link was pinned
assert_loaded_and_linked!("test_kprobe", true); assert_loaded_and_linked("test_kprobe");
// 4. unpin link, and make sure everything is unloaded // 4. unpin link, and make sure everything is unloaded
{ {
@ -415,7 +421,7 @@ fn pin_lifecycle_kprobe() {
} }
// program should be unloaded // program should be unloaded
assert_loaded!("test_kprobe", false); assert_unloaded("test_kprobe");
} }
#[test] #[test]
@ -429,7 +435,7 @@ fn pin_lifecycle_uprobe() {
} }
// should still be loaded since prog was pinned // should still be loaded since prog was pinned
assert_loaded!("test_uprobe", true); assert_loaded("test_uprobe");
// 2. Load program from bpffs but don't attach it // 2. Load program from bpffs but don't attach it
{ {
@ -441,7 +447,7 @@ fn pin_lifecycle_uprobe() {
} }
// should still be loaded since prog was pinned // should still be loaded since prog was pinned
assert_loaded!("test_uprobe", true); assert_loaded("test_uprobe");
// 3. Load program from bpffs and attach // 3. Load program from bpffs and attach
{ {
@ -462,7 +468,7 @@ fn pin_lifecycle_uprobe() {
} }
// should still be loaded since link was pinned // should still be loaded since link was pinned
assert_loaded_and_linked!("test_uprobe", true); assert_loaded_and_linked("test_uprobe");
// 4. unpin link, and make sure everything is unloaded // 4. unpin link, and make sure everything is unloaded
{ {
@ -473,5 +479,5 @@ fn pin_lifecycle_uprobe() {
} }
// program should be unloaded // program should be unloaded
assert_loaded!("test_uprobe", false); assert_unloaded("test_uprobe");
} }

@ -190,8 +190,6 @@ EOF
echo "Enabling testing repositories" echo "Enabling testing repositories"
exec_vm sudo dnf config-manager --set-enabled updates-testing exec_vm sudo dnf config-manager --set-enabled updates-testing
exec_vm sudo dnf config-manager --set-enabled updates-testing-modular exec_vm sudo dnf config-manager --set-enabled updates-testing-modular
echo "Installing dependencies"
exec_vm sudo dnf install -qy bpftool
} }
scp_vm() { scp_vm() {

Loading…
Cancel
Save