Merge pull request #712 from aya-rs/loaded-links

integration-test: remove bpftool dependency
reviewable/pr720/r1
Tamir Duberstein 1 year ago committed by GitHub
commit 368ddf10c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -42,6 +42,7 @@ use crate::{
is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported, is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported,
is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported,
is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs, is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs,
SyscallError,
}, },
util::{bytes_of, bytes_of_slice, possible_cpus, POSSIBLE_CPUS}, util::{bytes_of, bytes_of_slice, possible_cpus, POSSIBLE_CPUS},
}; };
@ -505,16 +506,19 @@ impl<'a> BpfLoader<'a> {
}; };
if !map.obj.data().is_empty() && map.obj.section_kind() != BpfSectionKind::Bss { if !map.obj.data().is_empty() && map.obj.section_kind() != BpfSectionKind::Bss {
bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0) bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0)
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
})?; })
.map_err(MapError::from)?;
} }
if map.obj.section_kind() == BpfSectionKind::Rodata { if map.obj.section_kind() == BpfSectionKind::Rodata {
bpf_map_freeze(fd).map_err(|(_, io_error)| MapError::SyscallError { bpf_map_freeze(fd)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_map_freeze", call: "bpf_map_freeze",
io_error, io_error,
})?; })
.map_err(MapError::from)?;
} }
maps.insert(name, map); maps.insert(name, map);
} }

@ -5,7 +5,7 @@ use std::{
use crate::{ use crate::{
maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError}, maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError},
sys::{bpf_map_lookup_elem, bpf_map_update_elem}, sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError},
Pod, Pod,
}; };
@ -65,11 +65,10 @@ impl<T: Borrow<MapData>, V: Pod> Array<T, V> {
check_bounds(data, *index)?; check_bounds(data, *index)?;
let fd = data.fd_or_err()?; let fd = data.fd_or_err()?;
let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| { let value =
MapError::SyscallError { bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| SyscallError {
call: "bpf_map_lookup_elem", call: "bpf_map_lookup_elem",
io_error, io_error,
}
})?; })?;
value.ok_or(MapError::KeyNotFound) value.ok_or(MapError::KeyNotFound)
} }
@ -93,7 +92,7 @@ impl<T: BorrowMut<MapData>, V: Pod> Array<T, V> {
check_bounds(data, index)?; check_bounds(data, index)?;
let fd = data.fd_or_err()?; let fd = data.fd_or_err()?;
bpf_map_update_elem(fd, Some(&index), value.borrow(), flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, Some(&index), value.borrow(), flags).map_err(|(_, io_error)| {
MapError::SyscallError { SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
} }

@ -5,7 +5,7 @@ use std::{
use crate::{ use crate::{
maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError, PerCpuValues}, maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError, PerCpuValues},
sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu, SyscallError},
Pod, Pod,
}; };
@ -85,7 +85,7 @@ impl<T: Borrow<MapData>, V: Pod> PerCpuArray<T, V> {
let fd = data.fd_or_err()?; let fd = data.fd_or_err()?;
let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| {
MapError::SyscallError { SyscallError {
call: "bpf_map_lookup_elem", call: "bpf_map_lookup_elem",
io_error, io_error,
} }
@ -113,7 +113,7 @@ impl<T: BorrowMut<MapData>, V: Pod> PerCpuArray<T, V> {
let fd = data.fd_or_err()?; let fd = data.fd_or_err()?;
bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| { bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| {
MapError::SyscallError { SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
} }

@ -8,7 +8,7 @@ use std::{
use crate::{ use crate::{
maps::{check_bounds, check_kv_size, MapData, MapError, MapKeys}, maps::{check_bounds, check_kv_size, MapData, MapError, MapKeys},
programs::ProgramFd, programs::ProgramFd,
sys::{bpf_map_delete_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError},
}; };
/// An array of eBPF program file descriptors used as a jump table. /// An array of eBPF program file descriptors used as a jump table.
@ -80,7 +80,7 @@ impl<T: BorrowMut<MapData>> ProgramArray<T> {
let prog_fd = program.as_raw_fd(); let prog_fd = program.as_raw_fd();
bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| {
MapError::SyscallError { SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
} }
@ -99,9 +99,12 @@ impl<T: BorrowMut<MapData>> ProgramArray<T> {
bpf_map_delete_elem(fd, index) bpf_map_delete_elem(fd, index)
.map(|_| ()) .map(|_| ())
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| {
SyscallError {
call: "bpf_map_delete_elem", call: "bpf_map_delete_elem",
io_error, io_error,
}
.into()
}) })
} }
} }

@ -3,7 +3,7 @@ use std::{borrow::Borrow, marker::PhantomData};
use crate::{ use crate::{
maps::{check_v_size, MapData, MapError}, maps::{check_v_size, MapData, MapError},
sys::{bpf_map_lookup_elem_ptr, bpf_map_push_elem}, sys::{bpf_map_lookup_elem_ptr, bpf_map_push_elem, SyscallError},
Pod, Pod,
}; };
@ -54,7 +54,7 @@ impl<T: Borrow<MapData>, V: Pod> BloomFilter<T, V> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
bpf_map_lookup_elem_ptr::<u32, _>(fd, None, &mut value, flags) bpf_map_lookup_elem_ptr::<u32, _>(fd, None, &mut value, flags)
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| SyscallError {
call: "bpf_map_lookup_elem", call: "bpf_map_lookup_elem",
io_error, io_error,
})? })?
@ -65,11 +65,9 @@ impl<T: Borrow<MapData>, V: Pod> BloomFilter<T, V> {
/// Inserts a value into the map. /// Inserts a value into the map.
pub fn insert(&self, value: impl Borrow<V>, flags: u64) -> Result<(), MapError> { pub fn insert(&self, value: impl Borrow<V>, flags: u64) -> Result<(), MapError> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| { bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError {
MapError::SyscallError {
call: "bpf_map_push_elem", call: "bpf_map_push_elem",
io_error, io_error,
}
})?; })?;
Ok(()) Ok(())
} }
@ -212,7 +210,7 @@ mod tests {
assert_matches!( assert_matches!(
bloom_filter.insert(1, 0), bloom_filter.insert(1, 0),
Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_push_elem" && io_error.raw_os_error() == Some(EFAULT) Err(MapError::SyscallError(SyscallError { call: "bpf_map_push_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT)
); );
} }
@ -250,7 +248,7 @@ mod tests {
assert_matches!( assert_matches!(
bloom_filter.contains(&1, 0), bloom_filter.contains(&1, 0),
Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT) Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT)
); );
} }

@ -5,7 +5,7 @@ use std::{
use crate::{ use crate::{
maps::{check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys}, maps::{check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys},
sys::bpf_map_lookup_elem, sys::{bpf_map_lookup_elem, SyscallError},
Pod, Pod,
}; };
@ -54,11 +54,9 @@ impl<T: Borrow<MapData>, K: Pod, V: Pod> HashMap<T, K, V> {
/// Returns a copy of the value associated with the key. /// Returns a copy of the value associated with the key.
pub fn get(&self, key: &K, flags: u64) -> Result<V, MapError> { pub fn get(&self, key: &K, flags: u64) -> Result<V, MapError> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError {
MapError::SyscallError {
call: "bpf_map_lookup_elem", call: "bpf_map_lookup_elem",
io_error, io_error,
}
})?; })?;
value.ok_or(MapError::KeyNotFound) value.ok_or(MapError::KeyNotFound)
} }
@ -292,7 +290,7 @@ mod tests {
assert_matches!( assert_matches!(
hm.insert(1, 42, 0), hm.insert(1, 42, 0),
Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_update_elem" && io_error.raw_os_error() == Some(EFAULT) Err(MapError::SyscallError(SyscallError { call: "bpf_map_update_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT)
); );
} }
@ -352,7 +350,7 @@ mod tests {
assert_matches!( assert_matches!(
hm.remove(&1), hm.remove(&1),
Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_delete_elem" && io_error.raw_os_error() == Some(EFAULT) Err(MapError::SyscallError(SyscallError { call: "bpf_map_delete_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT)
); );
} }
@ -390,7 +388,7 @@ mod tests {
assert_matches!( assert_matches!(
hm.get(&1, 0), hm.get(&1, 0),
Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT) Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT)
); );
} }
@ -535,7 +533,10 @@ mod tests {
assert_matches!(keys.next(), Some(Ok(20))); assert_matches!(keys.next(), Some(Ok(20)));
assert_matches!( assert_matches!(
keys.next(), keys.next(),
Some(Err(MapError::SyscallError { call, .. })) if call == "bpf_map_get_next_key" Some(Err(MapError::SyscallError(SyscallError {
call: "bpf_map_get_next_key",
io_error: _
})))
); );
assert_matches!(keys.next(), None); assert_matches!(keys.next(), None);
} }
@ -647,7 +648,10 @@ mod tests {
assert_matches!(iter.next(), Some(Ok((20, 200)))); assert_matches!(iter.next(), Some(Ok((20, 200))));
assert_matches!( assert_matches!(
iter.next(), iter.next(),
Some(Err(MapError::SyscallError { call, .. })) if call == "bpf_map_get_next_key" Some(Err(MapError::SyscallError(SyscallError {
call: "bpf_map_get_next_key",
io_error: _
})))
); );
assert_matches!(iter.next(), None); assert_matches!(iter.next(), None);
} }
@ -691,7 +695,10 @@ mod tests {
assert_matches!(iter.next(), Some(Ok((10, 100)))); assert_matches!(iter.next(), Some(Ok((10, 100))));
assert_matches!( assert_matches!(
iter.next(), iter.next(),
Some(Err(MapError::SyscallError { call, .. })) if call == "bpf_map_lookup_elem" Some(Err(MapError::SyscallError(SyscallError {
call: "bpf_map_lookup_elem",
io_error: _
})))
); );
assert_matches!(iter.next(), Some(Ok((30, 300)))); assert_matches!(iter.next(), Some(Ok((30, 300))));
assert_matches!(iter.next(), None); assert_matches!(iter.next(), None);

@ -1,7 +1,7 @@
//! Hash map types. //! Hash map types.
use crate::{ use crate::{
maps::MapError, maps::MapError,
sys::{bpf_map_delete_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError},
Pod, Pod,
}; };
@ -21,11 +21,9 @@ pub(crate) fn insert<K: Pod, V: Pod>(
flags: u64, flags: u64,
) -> Result<(), MapError> { ) -> Result<(), MapError> {
let fd = map.fd_or_err()?; let fd = map.fd_or_err()?;
bpf_map_update_elem(fd, Some(key), value, flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, Some(key), value, flags).map_err(|(_, io_error)| SyscallError {
MapError::SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
}
})?; })?;
Ok(()) Ok(())
@ -35,8 +33,11 @@ pub(crate) fn remove<K: Pod>(map: &MapData, key: &K) -> Result<(), MapError> {
let fd = map.fd_or_err()?; let fd = map.fd_or_err()?;
bpf_map_delete_elem(fd, key) bpf_map_delete_elem(fd, key)
.map(|_| ()) .map(|_| ())
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| {
SyscallError {
call: "bpf_map_delete_elem", call: "bpf_map_delete_elem",
io_error, io_error,
}
.into()
}) })
} }

@ -8,7 +8,7 @@ use crate::{
maps::{ maps::{
check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys, PerCpuValues, check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys, PerCpuValues,
}, },
sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu, SyscallError},
Pod, Pod,
}; };
@ -64,11 +64,10 @@ impl<T: Borrow<MapData>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
/// Returns a slice of values - one for each CPU - associated with the key. /// Returns a slice of values - one for each CPU - associated with the key.
pub fn get(&self, key: &K, flags: u64) -> Result<PerCpuValues<V>, MapError> { pub fn get(&self, key: &K, flags: u64) -> Result<PerCpuValues<V>, MapError> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| { let values =
MapError::SyscallError { bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| SyscallError {
call: "bpf_map_lookup_elem", call: "bpf_map_lookup_elem",
io_error, io_error,
}
})?; })?;
values.ok_or(MapError::KeyNotFound) values.ok_or(MapError::KeyNotFound)
} }
@ -123,7 +122,7 @@ impl<T: BorrowMut<MapData>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
) -> Result<(), MapError> { ) -> Result<(), MapError> {
let fd = self.inner.borrow_mut().fd_or_err()?; let fd = self.inner.borrow_mut().fd_or_err()?;
bpf_map_update_elem_per_cpu(fd, key.borrow(), &values, flags).map_err( bpf_map_update_elem_per_cpu(fd, key.borrow(), &values, flags).map_err(
|(_, io_error)| MapError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
}, },

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
maps::{check_kv_size, IterableMap, MapData, MapError, MapIter, MapKeys}, maps::{check_kv_size, IterableMap, MapData, MapError, MapIter, MapKeys},
sys::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem, SyscallError},
Pod, Pod,
}; };
@ -129,11 +129,9 @@ impl<T: Borrow<MapData>, K: Pod, V: Pod> LpmTrie<T, K, V> {
/// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie. /// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie.
pub fn get(&self, key: &Key<K>, flags: u64) -> Result<V, MapError> { pub fn get(&self, key: &Key<K>, flags: u64) -> Result<V, MapError> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError {
MapError::SyscallError {
call: "bpf_map_lookup_elem", call: "bpf_map_lookup_elem",
io_error, io_error,
}
})?; })?;
value.ok_or(MapError::KeyNotFound) value.ok_or(MapError::KeyNotFound)
} }
@ -161,7 +159,7 @@ impl<T: BorrowMut<MapData>, K: Pod, V: Pod> LpmTrie<T, K, V> {
) -> Result<(), MapError> { ) -> Result<(), MapError> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
bpf_map_update_elem(fd, Some(key), value.borrow(), flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, Some(key), value.borrow(), flags).map_err(|(_, io_error)| {
MapError::SyscallError { SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
} }
@ -177,9 +175,12 @@ impl<T: BorrowMut<MapData>, K: Pod, V: Pod> LpmTrie<T, K, V> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
bpf_map_delete_elem(fd, key) bpf_map_delete_elem(fd, key)
.map(|_| ()) .map(|_| ())
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| {
SyscallError {
call: "bpf_map_delete_elem", call: "bpf_map_delete_elem",
io_error, io_error,
}
.into()
}) })
} }
} }
@ -349,7 +350,7 @@ mod tests {
let key = Key::new(16, u32::from(ipaddr).to_be()); let key = Key::new(16, u32::from(ipaddr).to_be());
assert_matches!( assert_matches!(
trie.insert(&key, 1, 0), trie.insert(&key, 1, 0),
Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_update_elem" && io_error.raw_os_error() == Some(EFAULT) Err(MapError::SyscallError(SyscallError { call: "bpf_map_update_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT)
); );
} }
@ -391,7 +392,7 @@ mod tests {
let key = Key::new(16, u32::from(ipaddr).to_be()); let key = Key::new(16, u32::from(ipaddr).to_be());
assert_matches!( assert_matches!(
trie.remove(&key), trie.remove(&key),
Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_delete_elem" && io_error.raw_os_error() == Some(EFAULT) Err(MapError::SyscallError(SyscallError { call: "bpf_map_delete_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT)
); );
} }
@ -432,7 +433,7 @@ mod tests {
assert_matches!( assert_matches!(
trie.get(&key, 0), trie.get(&key, 0),
Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT) Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT)
); );
} }

@ -58,7 +58,7 @@ use crate::{
pin::PinError, pin::PinError,
sys::{ sys::{
bpf_create_map, bpf_get_object, bpf_map_get_info_by_fd, bpf_map_get_next_key, bpf_create_map, bpf_get_object, bpf_map_get_info_by_fd, bpf_map_get_next_key,
bpf_pin_object, bpf_pin_object, SyscallError,
}, },
util::nr_cpus, util::nr_cpus,
PinningType, Pod, PinningType, Pod,
@ -167,13 +167,8 @@ pub enum MapError {
ProgramNotLoaded, ProgramNotLoaded,
/// Syscall failed /// Syscall failed
#[error("the `{call}` syscall failed")] #[error(transparent)]
SyscallError { SyscallError(#[from] SyscallError),
/// Syscall Name
call: &'static str,
/// Original io::Error
io_error: io::Error,
},
/// Could not pin map by name /// Could not pin map by name
#[error("map `{name:?}` requested pinning by name. pinning failed")] #[error("map `{name:?}` requested pinning by name. pinning failed")]
@ -538,7 +533,7 @@ impl MapData {
} }
let map_path = path.as_ref().join(name); let map_path = path.as_ref().join(name);
let path_string = CString::new(map_path.to_str().unwrap()).unwrap(); let path_string = CString::new(map_path.to_str().unwrap()).unwrap();
let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| MapError::SyscallError { let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
call: "BPF_OBJ_GET", call: "BPF_OBJ_GET",
io_error, io_error,
})? as RawFd; })? as RawFd;
@ -560,15 +555,12 @@ impl MapData {
} }
})?; })?;
let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| MapError::SyscallError { let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
call: "BPF_OBJ_GET", call: "BPF_OBJ_GET",
io_error, io_error,
})? as RawFd; })? as RawFd;
let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError { let info = bpf_map_get_info_by_fd(fd)?;
call: "BPF_MAP_GET_INFO_BY_FD",
io_error,
})?;
Ok(MapData { Ok(MapData {
obj: parse_map_info(info, PinningType::ByName), obj: parse_map_info(info, PinningType::ByName),
@ -584,10 +576,7 @@ impl MapData {
/// This API is intended for cases where you have received a valid BPF FD from some other means. /// This API is intended for cases where you have received a valid BPF FD from some other means.
/// For example, you received an FD over Unix Domain Socket. /// For example, you received an FD over Unix Domain Socket.
pub fn from_fd(fd: RawFd) -> Result<MapData, MapError> { pub fn from_fd(fd: RawFd) -> Result<MapData, MapError> {
let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError { let info = bpf_map_get_info_by_fd(fd)?;
call: "BPF_OBJ_GET",
io_error,
})?;
Ok(MapData { Ok(MapData {
obj: parse_map_info(info, PinningType::None), obj: parse_map_info(info, PinningType::None),
@ -614,8 +603,8 @@ impl MapData {
error: e.to_string(), error: e.to_string(),
} }
})?; })?;
bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError { bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError {
name: "BPF_OBJ_PIN", call: "BPF_OBJ_PIN",
io_error, io_error,
})?; })?;
self.pinned = true; self.pinned = true;
@ -692,21 +681,19 @@ impl<K: Pod> Iterator for MapKeys<'_, K> {
} }
}; };
match bpf_map_get_next_key(fd, self.key.as_ref()) { let key =
Ok(Some(key)) => { bpf_map_get_next_key(fd, self.key.as_ref()).map_err(|(_, io_error)| SyscallError {
self.key = Some(key);
Some(Ok(key))
}
Ok(None) => {
self.key = None;
None
}
Err((_, io_error)) => {
self.err = true;
Some(Err(MapError::SyscallError {
call: "bpf_map_get_next_key", call: "bpf_map_get_next_key",
io_error, io_error,
})) });
match key {
Err(err) => {
self.err = true;
Some(Err(err.into()))
}
Ok(key) => {
self.key = key;
key.map(Ok)
} }
} }
} }

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
maps::{check_kv_size, MapData, MapError}, maps::{check_kv_size, MapData, MapError},
sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem, SyscallError},
Pod, Pod,
}; };
@ -65,7 +65,7 @@ impl<T: BorrowMut<MapData>, V: Pod> Queue<T, V> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err( let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err(
|(_, io_error)| MapError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_map_lookup_and_delete_elem", call: "bpf_map_lookup_and_delete_elem",
io_error, io_error,
}, },
@ -80,11 +80,9 @@ impl<T: BorrowMut<MapData>, V: Pod> Queue<T, V> {
/// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails.
pub fn push(&mut self, value: impl Borrow<V>, flags: u64) -> Result<(), MapError> { pub fn push(&mut self, value: impl Borrow<V>, flags: u64) -> Result<(), MapError> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| { bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError {
MapError::SyscallError {
call: "bpf_map_push_elem", call: "bpf_map_push_elem",
io_error, io_error,
}
})?; })?;
Ok(()) Ok(())
} }

@ -8,7 +8,7 @@ use crate::{
maps::{ maps::{
check_kv_size, hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys, check_kv_size, hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys,
}, },
sys::bpf_map_lookup_elem, sys::{bpf_map_lookup_elem, SyscallError},
Pod, Pod,
}; };
@ -83,11 +83,9 @@ impl<T: Borrow<MapData>, K: Pod> SockHash<T, K> {
/// Returns the fd of the socket stored at the given key. /// Returns the fd of the socket stored at the given key.
pub fn get(&self, key: &K, flags: u64) -> Result<RawFd, MapError> { pub fn get(&self, key: &K, flags: u64) -> Result<RawFd, MapError> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError {
MapError::SyscallError {
call: "bpf_map_lookup_elem", call: "bpf_map_lookup_elem",
io_error, io_error,
}
})?; })?;
value.ok_or(MapError::KeyNotFound) value.ok_or(MapError::KeyNotFound)
} }

@ -7,7 +7,7 @@ use std::{
use crate::{ use crate::{
maps::{check_bounds, check_kv_size, sock::SockMapFd, MapData, MapError, MapKeys}, maps::{check_bounds, check_kv_size, sock::SockMapFd, MapData, MapError, MapKeys},
sys::{bpf_map_delete_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError},
}; };
/// An array of TCP or UDP sockets. /// An array of TCP or UDP sockets.
@ -76,7 +76,7 @@ impl<T: BorrowMut<MapData>> SockMap<T> {
let fd = data.fd_or_err()?; let fd = data.fd_or_err()?;
check_bounds(data, index)?; check_bounds(data, index)?;
bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err( bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err(
|(_, io_error)| MapError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
}, },
@ -91,9 +91,12 @@ impl<T: BorrowMut<MapData>> SockMap<T> {
check_bounds(data, *index)?; check_bounds(data, *index)?;
bpf_map_delete_elem(fd, index) bpf_map_delete_elem(fd, index)
.map(|_| ()) .map(|_| ())
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| {
SyscallError {
call: "bpf_map_delete_elem", call: "bpf_map_delete_elem",
io_error, io_error,
}
.into()
}) })
} }
} }

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
maps::{check_kv_size, MapData, MapError}, maps::{check_kv_size, MapData, MapError},
sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem, SyscallError},
Pod, Pod,
}; };
@ -65,7 +65,7 @@ impl<T: BorrowMut<MapData>, V: Pod> Stack<T, V> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err( let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err(
|(_, io_error)| MapError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_map_lookup_and_delete_elem", call: "bpf_map_lookup_and_delete_elem",
io_error, io_error,
}, },
@ -81,7 +81,7 @@ impl<T: BorrowMut<MapData>, V: Pod> Stack<T, V> {
pub fn push(&mut self, value: impl Borrow<V>, flags: u64) -> Result<(), MapError> { pub fn push(&mut self, value: impl Borrow<V>, flags: u64) -> Result<(), MapError> {
let fd = self.inner.borrow().fd_or_err()?; let fd = self.inner.borrow().fd_or_err()?;
bpf_map_update_elem(fd, None::<&u32>, value.borrow(), flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, None::<&u32>, value.borrow(), flags).map_err(|(_, io_error)| {
MapError::SyscallError { SyscallError {
call: "bpf_map_update_elem", call: "bpf_map_update_elem",
io_error, io_error,
} }

@ -5,7 +5,7 @@ use std::{borrow::Borrow, collections::BTreeMap, fs, io, mem, path::Path, str::F
use crate::{ use crate::{
maps::{IterableMap, MapData, MapError, MapIter, MapKeys}, maps::{IterableMap, MapData, MapError, MapIter, MapKeys},
sys::bpf_map_lookup_elem_ptr, sys::{bpf_map_lookup_elem_ptr, SyscallError},
}; };
/// A hash map of kernel or user space stack traces. /// A hash map of kernel or user space stack traces.
@ -77,11 +77,9 @@ impl<T: Borrow<MapData>> StackTraceMap<T> {
} }
let max_stack_depth = let max_stack_depth =
sysctl::<usize>("kernel/perf_event_max_stack").map_err(|io_error| { sysctl::<usize>("kernel/perf_event_max_stack").map_err(|io_error| SyscallError {
MapError::SyscallError {
call: "sysctl", call: "sysctl",
io_error, io_error,
}
})?; })?;
let size = data.obj.value_size() as usize; let size = data.obj.value_size() as usize;
if size > max_stack_depth * mem::size_of::<u64>() { if size > max_stack_depth * mem::size_of::<u64>() {
@ -106,7 +104,7 @@ impl<T: Borrow<MapData>> StackTraceMap<T> {
let mut frames = vec![0; self.max_stack_depth]; let mut frames = vec![0; self.max_stack_depth];
bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags) bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags)
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| SyscallError {
call: "bpf_map_lookup_elem", call: "bpf_map_lookup_elem",
io_error, io_error,
})? })?

@ -1,5 +1,6 @@
//! Pinning BPF objects to the BPF filesystem. //! Pinning BPF objects to the BPF filesystem.
use std::io;
use crate::sys::SyscallError;
use thiserror::Error; use thiserror::Error;
/// An error ocurred working with a pinned BPF object. /// An error ocurred working with a pinned BPF object.
@ -24,12 +25,6 @@ pub enum PinError {
error: String, error: String,
}, },
/// An error ocurred making a syscall. /// An error ocurred making a syscall.
#[error("{name} failed")] #[error(transparent)]
SyscallError { SyscallError(#[from] SyscallError),
/// The syscall name.
name: &'static str,
/// The [`io::Error`] returned by the syscall.
#[source]
io_error: io::Error,
},
} }

@ -8,7 +8,7 @@ use crate::{
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach}, sys::{bpf_link_create, bpf_prog_attach, SyscallError},
}; };
/// A program used to watch or prevent device interaction from a cgroup. /// A program used to watch or prevent device interaction from a cgroup.
@ -66,7 +66,7 @@ impl CgroupDevice {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, None, 0).map_err( let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },
@ -78,7 +78,7 @@ impl CgroupDevice {
))) )))
} 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 { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }

@ -15,7 +15,7 @@ use crate::{
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach}, sys::{bpf_link_create, bpf_prog_attach, SyscallError},
VerifierLogLevel, VerifierLogLevel,
}; };
@ -101,7 +101,7 @@ impl CgroupSkb {
}; };
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },
@ -113,7 +113,7 @@ impl CgroupSkb {
)))) ))))
} 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 { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }

@ -14,7 +14,7 @@ use crate::{
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach}, sys::{bpf_link_create, bpf_prog_attach, SyscallError},
VerifierLogLevel, VerifierLogLevel,
}; };
@ -76,7 +76,7 @@ impl CgroupSock {
let attach_type = self.data.expected_attach_type.unwrap(); let attach_type = self.data.expected_attach_type.unwrap();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },
@ -88,7 +88,7 @@ impl CgroupSock {
)))) ))))
} 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 { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }

@ -14,7 +14,7 @@ use crate::{
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach}, sys::{bpf_link_create, bpf_prog_attach, SyscallError},
VerifierLogLevel, VerifierLogLevel,
}; };
@ -77,7 +77,7 @@ impl CgroupSockAddr {
let attach_type = self.data.expected_attach_type.unwrap(); let attach_type = self.data.expected_attach_type.unwrap();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },
@ -89,7 +89,7 @@ impl CgroupSockAddr {
))) )))
} 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 { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }

@ -14,7 +14,7 @@ use crate::{
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach}, sys::{bpf_link_create, bpf_prog_attach, SyscallError},
VerifierLogLevel, VerifierLogLevel,
}; };
@ -74,7 +74,7 @@ impl CgroupSockopt {
let attach_type = self.data.expected_attach_type.unwrap(); let attach_type = self.data.expected_attach_type.unwrap();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },
@ -86,7 +86,7 @@ impl CgroupSockopt {
))) )))
} 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 { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }

@ -11,7 +11,7 @@ use crate::{
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach}, sys::{bpf_link_create, bpf_prog_attach, SyscallError},
}; };
/// A program used to watch for sysctl changes. /// A program used to watch for sysctl changes.
@ -68,7 +68,7 @@ impl CgroupSysctl {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL, None, 0).map_err( let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },
@ -80,7 +80,7 @@ impl CgroupSysctl {
))) )))
} 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 { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }

@ -10,7 +10,7 @@ use crate::{
programs::{ programs::{
define_link_wrapper, load_program, FdLink, FdLinkId, ProgramData, ProgramError, ProgramFd, define_link_wrapper, load_program, FdLink, FdLinkId, ProgramData, ProgramError, ProgramFd,
}, },
sys::{self, bpf_link_create}, sys::{self, bpf_link_create, SyscallError},
Btf, Btf,
}; };
@ -91,7 +91,7 @@ impl Extension {
let btf_id = self.data.attach_btf_id.ok_or(ProgramError::NotLoaded)?; let btf_id = self.data.attach_btf_id.ok_or(ProgramError::NotLoaded)?;
// the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS
let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0) let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0)
.map_err(|(_, io_error)| ProgramError::SyscallError { .map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
})? as RawFd; })? as RawFd;
@ -121,7 +121,7 @@ impl Extension {
let prog_fd = self.data.fd_or_err()?; let prog_fd = self.data.fd_or_err()?;
// the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS
let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0) let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0)
.map_err(|(_, io_error)| ProgramError::SyscallError { .map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
})? as RawFd; })? as RawFd;
@ -151,11 +151,7 @@ impl Extension {
/// with the name `func_name` within that BTF object. /// with the name `func_name` within that BTF object.
fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramError> { fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramError> {
// retrieve program information // retrieve program information
let info = let info = sys::bpf_prog_get_info_by_fd(prog_fd)?;
sys::bpf_prog_get_info_by_fd(prog_fd).map_err(|io_error| ProgramError::SyscallError {
call: "bpf_prog_get_info_by_fd",
io_error,
})?;
// btf_id refers to the ID of the program btf that was loaded with bpf(BPF_BTF_LOAD) // btf_id refers to the ID of the program btf that was loaded with bpf(BPF_BTF_LOAD)
if info.btf_id == 0 { if info.btf_id == 0 {
@ -163,8 +159,7 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr
} }
// the bpf fd of the BTF object // the bpf fd of the BTF object
let btf_fd = let btf_fd = sys::bpf_btf_get_fd_by_id(info.btf_id).map_err(|io_error| SyscallError {
sys::bpf_btf_get_fd_by_id(info.btf_id).map_err(|io_error| ProgramError::SyscallError {
call: "bpf_btf_get_fd_by_id", call: "bpf_btf_get_fd_by_id",
io_error, io_error,
})?; })?;
@ -176,18 +171,17 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr
Ok(info) => { Ok(info) => {
if info.btf_size > buf.len() as u32 { if info.btf_size > buf.len() as u32 {
buf.resize(info.btf_size as usize, 0u8); buf.resize(info.btf_size as usize, 0u8);
let btf_info = sys::btf_obj_get_info_by_fd(btf_fd, &buf).map_err(|io_error| { let btf_info =
ProgramError::SyscallError { sys::btf_obj_get_info_by_fd(btf_fd, &buf).map_err(|io_error| SyscallError {
call: "bpf_prog_get_info_by_fd", call: "bpf_prog_get_info_by_fd",
io_error, io_error,
}
})?; })?;
Ok(btf_info) Ok(btf_info)
} else { } else {
Ok(info) Ok(info)
} }
} }
Err(io_error) => Err(ProgramError::SyscallError { Err(io_error) => Err(SyscallError {
call: "bpf_prog_get_info_by_fd", call: "bpf_prog_get_info_by_fd",
io_error, io_error,
}), }),

@ -137,12 +137,7 @@ impl TryFrom<FdLink> for KProbeLink {
type Error = LinkError; type Error = LinkError;
fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> { fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> {
let info = let info = bpf_link_get_info_by_fd(fd_link.fd)?;
bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| LinkError::SyscallError {
call: "BPF_OBJ_GET_INFO_BY_FD",
code: 0,
io_error,
})?;
if info.type_ == (bpf_link_type::BPF_LINK_TYPE_KPROBE_MULTI as u32) { if info.type_ == (bpf_link_type::BPF_LINK_TYPE_KPROBE_MULTI as u32) {
return Ok(KProbeLink::new(PerfLinkInner::FdLink(fd_link))); return Ok(KProbeLink::new(PerfLinkInner::FdLink(fd_link)));
} }

@ -14,7 +14,7 @@ use crate::{
generated::bpf_attach_type, generated::bpf_attach_type,
pin::PinError, pin::PinError,
programs::ProgramError, programs::ProgramError,
sys::{bpf_get_object, bpf_pin_object, bpf_prog_detach}, sys::{bpf_get_object, bpf_pin_object, bpf_prog_detach, SyscallError},
}; };
/// A Link. /// A Link.
@ -152,8 +152,8 @@ impl FdLink {
error: e.to_string(), error: e.to_string(),
} }
})?; })?;
bpf_pin_object(self.fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError { bpf_pin_object(self.fd, &path_string).map_err(|(_, io_error)| SyscallError {
name: "BPF_OBJ_PIN", call: "BPF_OBJ_PIN",
io_error, io_error,
})?; })?;
Ok(PinnedLink::new(PathBuf::from(path.as_ref()), self)) Ok(PinnedLink::new(PathBuf::from(path.as_ref()), self))
@ -208,11 +208,11 @@ impl PinnedLink {
/// Creates a [`crate::programs::links::PinnedLink`] from a valid path on bpffs. /// Creates a [`crate::programs::links::PinnedLink`] from a valid path on bpffs.
pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, LinkError> { pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, LinkError> {
let path_string = CString::new(path.as_ref().to_string_lossy().to_string()).unwrap(); let path_string = CString::new(path.as_ref().to_string_lossy().to_string()).unwrap();
let fd = let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| {
bpf_get_object(&path_string).map_err(|(code, io_error)| LinkError::SyscallError { LinkError::SyscallError(SyscallError {
call: "BPF_OBJ_GET", call: "BPF_OBJ_GET",
code,
io_error, io_error,
})
})? as RawFd; })? as RawFd;
Ok(PinnedLink::new( Ok(PinnedLink::new(
path.as_ref().to_path_buf(), path.as_ref().to_path_buf(),
@ -339,16 +339,8 @@ pub enum LinkError {
#[error("Invalid link")] #[error("Invalid link")]
InvalidLink, InvalidLink,
/// Syscall failed. /// Syscall failed.
#[error("the `{call}` syscall failed with code {code}")] #[error(transparent)]
SyscallError { SyscallError(#[from] SyscallError),
/// Syscall Name.
call: &'static str,
/// Error code.
code: libc::c_long,
#[source]
/// Original io::Error.
io_error: io::Error,
},
} }
#[cfg(test)] #[cfg(test)]

@ -4,7 +4,10 @@ use std::os::fd::{AsRawFd, IntoRawFd as _, RawFd};
use crate::{ use crate::{
generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2}, generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2},
programs::{load_program, query, Link, ProgramData, ProgramError, ProgramInfo}, programs::{load_program, query, Link, ProgramData, ProgramError, ProgramInfo},
sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd}, sys::{
bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd,
SyscallError,
},
}; };
use libc::{close, dup}; use libc::{close, dup};
@ -65,7 +68,7 @@ impl LircMode2 {
let lircdev_fd = lircdev.as_raw_fd(); let lircdev_fd = lircdev.as_raw_fd();
bpf_prog_attach(prog_fd, lircdev_fd, BPF_LIRC_MODE2).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, lircdev_fd, BPF_LIRC_MODE2).map_err(|(_, io_error)| {
ProgramError::SyscallError { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }
@ -96,11 +99,7 @@ impl LircMode2 {
let mut prog_fds = Vec::with_capacity(prog_ids.len()); let mut prog_fds = Vec::with_capacity(prog_ids.len());
for id in prog_ids { for id in prog_ids {
let fd = bpf_prog_get_fd_by_id(id).map_err(|io_error| ProgramError::SyscallError { let fd = bpf_prog_get_fd_by_id(id)?;
call: "bpf_prog_get_fd_by_id",
io_error,
})?;
prog_fds.push(fd); prog_fds.push(fd);
} }
@ -132,13 +131,9 @@ impl LircLink {
/// Get ProgramInfo from this link /// Get ProgramInfo from this link
pub fn info(&self) -> Result<ProgramInfo, ProgramError> { pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
match bpf_prog_get_info_by_fd(self.prog_fd) { bpf_prog_get_info_by_fd(self.prog_fd)
Ok(info) => Ok(ProgramInfo(info)), .map(ProgramInfo)
Err(io_error) => Err(ProgramError::SyscallError { .map_err(Into::into)
call: "bpf_prog_get_info_by_fd",
io_error,
}),
}
} }
} }

@ -64,7 +64,6 @@ pub mod uprobe;
mod utils; mod utils;
pub mod xdp; pub mod xdp;
use crate::util::KernelVersion;
use libc::ENOSPC; use libc::ENOSPC;
use std::{ use std::{
ffi::CString, ffi::CString,
@ -105,15 +104,17 @@ 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_get_next_id, bpf_prog_query, bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd,
retry_with_verifier_logs, BpfLoadProgramAttrs, bpf_prog_query, iter_link_ids, iter_prog_ids, retry_with_verifier_logs,
BpfLoadProgramAttrs, SyscallError,
}, },
util::KernelVersion,
VerifierLogLevel, VerifierLogLevel,
}; };
@ -147,14 +148,8 @@ pub enum ProgramError {
}, },
/// A syscall failed. /// A syscall failed.
#[error("`{call}` failed")] #[error(transparent)]
SyscallError { SyscallError(#[from] SyscallError),
/// The name of the syscall which failed.
call: &'static str,
/// The [`io::Error`] returned by the syscall.
#[source]
io_error: io::Error,
},
/// The network interface does not exist. /// The network interface does not exist.
#[error("unknown network interface {name}")] #[error("unknown network interface {name}")]
@ -456,11 +451,10 @@ impl<T: Link> ProgramData<T> {
None None
}; };
let attach_btf_obj_fd = if info.attach_btf_obj_id > 0 { let attach_btf_obj_fd = if info.attach_btf_obj_id > 0 {
let fd = bpf_btf_get_fd_by_id(info.attach_btf_obj_id).map_err(|io_error| { let fd =
ProgramError::SyscallError { bpf_btf_get_fd_by_id(info.attach_btf_obj_id).map_err(|io_error| SyscallError {
call: "bpf_btf_get_fd_by_id", call: "bpf_btf_get_fd_by_id",
io_error, io_error,
}
})?; })?;
Some(fd as u32) Some(fd as u32)
} else { } else {
@ -489,17 +483,12 @@ impl<T: Link> ProgramData<T> {
) -> Result<ProgramData<T>, ProgramError> { ) -> Result<ProgramData<T>, ProgramError> {
let path_string = let path_string =
CString::new(path.as_ref().as_os_str().to_string_lossy().as_bytes()).unwrap(); CString::new(path.as_ref().as_os_str().to_string_lossy().as_bytes()).unwrap();
let fd = let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
bpf_get_object(&path_string).map_err(|(_, io_error)| ProgramError::SyscallError {
call: "bpf_obj_get", call: "bpf_obj_get",
io_error, io_error,
})? as RawFd; })? as RawFd;
let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| ProgramError::SyscallError { let info = bpf_prog_get_info_by_fd(fd)?;
call: "bpf_prog_get_info_by_fd",
io_error,
})?;
let name = ProgramInfo(info).name_as_str().map(|s| s.to_string()); let name = ProgramInfo(info).name_as_str().map(|s| s.to_string());
ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info, verifier_log_level) ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info, verifier_log_level)
} }
@ -537,8 +526,8 @@ fn pin_program<T: Link, P: AsRef<Path>>(data: &ProgramData<T>, path: P) -> Resul
error: e.to_string(), error: e.to_string(),
} }
})?; })?;
bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError { bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError {
name: "BPF_OBJ_PIN", call: "BPF_OBJ_PIN",
io_error, io_error,
})?; })?;
Ok(()) Ok(())
@ -665,15 +654,17 @@ pub(crate) fn query<T: AsRawFd>(
prog_ids.resize(prog_cnt as usize, 0); prog_ids.resize(prog_cnt as usize, 0);
return Ok(prog_ids); return Ok(prog_ids);
} }
Err((_, io_error)) if retries == 0 && io_error.raw_os_error() == Some(ENOSPC) => { Err((_, io_error)) => {
if retries == 0 && io_error.raw_os_error() == Some(ENOSPC) {
prog_ids.resize(prog_cnt as usize, 0); prog_ids.resize(prog_cnt as usize, 0);
retries += 1; retries += 1;
} } else {
Err((_, io_error)) => { return Err(SyscallError {
return Err(ProgramError::SyscallError {
call: "bpf_prog_query", call: "bpf_prog_query",
io_error, io_error,
}); }
.into());
}
} }
} }
} }
@ -951,82 +942,28 @@ impl ProgramInfo {
/// ///
/// The returned fd must be closed when no longer needed. /// The returned fd must be closed when no longer needed.
pub fn fd(&self) -> Result<RawFd, ProgramError> { pub fn fd(&self) -> Result<RawFd, ProgramError> {
let fd = let Self(info) = self;
bpf_prog_get_fd_by_id(self.0.id).map_err(|io_error| ProgramError::SyscallError { let fd = bpf_prog_get_fd_by_id(info.id)?;
call: "bpf_prog_get_fd_by_id",
io_error,
})?;
Ok(fd.into_raw_fd()) Ok(fd.into_raw_fd())
} }
/// Loads a program from a pinned path in bpffs. /// Loads a program from a pinned path in bpffs.
pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<ProgramInfo, ProgramError> { pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<ProgramInfo, ProgramError> {
let path_string = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let path_string = CString::new(path.as_ref().to_str().unwrap()).unwrap();
let fd = let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
bpf_get_object(&path_string).map_err(|(_, io_error)| ProgramError::SyscallError {
call: "BPF_OBJ_GET", call: "BPF_OBJ_GET",
io_error, io_error,
})? as RawFd; })? as RawFd;
let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| ProgramError::SyscallError { let info = bpf_prog_get_info_by_fd(fd);
call: "bpf_prog_get_info_by_fd",
io_error,
})?;
unsafe { unsafe {
libc::close(fd); libc::close(fd);
} }
let info = info?;
Ok(ProgramInfo(info)) Ok(ProgramInfo(info))
} }
} }
/// ProgramsIter is an Iterator over loaded eBPF programs.
pub struct ProgramsIter {
current: u32,
error: bool,
}
impl Iterator for ProgramsIter {
type Item = Result<ProgramInfo, ProgramError>;
fn next(&mut self) -> Option<Self::Item> {
if self.error {
return None;
}
let current = self.current;
match bpf_prog_get_next_id(current) {
Ok(Some(next)) => {
self.current = next;
Some(
bpf_prog_get_fd_by_id(next)
.map_err(|io_error| ProgramError::SyscallError {
call: "bpf_prog_get_fd_by_id",
io_error,
})
.and_then(|fd| {
bpf_prog_get_info_by_fd(fd.as_raw_fd())
.map_err(|io_error| ProgramError::SyscallError {
call: "bpf_prog_get_info_by_fd",
io_error,
})
.map(ProgramInfo)
}),
)
}
Ok(None) => None,
Err((_, io_error)) => {
// If getting the next program failed, we have to yield None in our next
// iteration to avoid an infinite loop.
self.error = true;
Some(Err(ProgramError::SyscallError {
call: "bpf_prog_get_fd_by_id",
io_error,
}))
}
}
}
}
/// Returns an iterator over all loaded bpf programs. /// Returns an iterator over all loaded bpf programs.
/// ///
/// This differs from [`crate::Bpf::programs`] since it will return all programs /// This differs from [`crate::Bpf::programs`] since it will return all programs
@ -1050,9 +987,31 @@ impl Iterator for ProgramsIter {
/// next program id, get the program fd, or the [`ProgramInfo`] fail. In cases where /// next program id, get the program fd, or the [`ProgramInfo`] fail. In cases where
/// iteration can't be performed, for example the caller does not have the necessary privileges, /// iteration can't be performed, for example the caller does not have the necessary privileges,
/// a single item will be yielded containing the error that occurred. /// a single item will be yielded containing the error that occurred.
pub fn loaded_programs() -> ProgramsIter { pub fn loaded_programs() -> impl Iterator<Item = Result<ProgramInfo, ProgramError>> {
ProgramsIter { iter_prog_ids()
current: 0, .map(|id| {
error: false, let id = id?;
bpf_prog_get_fd_by_id(id)
})
.map(|fd| {
let fd = fd?;
bpf_prog_get_info_by_fd(fd.as_raw_fd())
})
.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))
} }

@ -7,7 +7,7 @@ use crate::{
probe::{detach_debug_fs, ProbeEvent}, probe::{detach_debug_fs, ProbeEvent},
FdLink, Link, ProgramError, FdLink, Link, ProgramError,
}, },
sys::{bpf_link_create, perf_event_ioctl, SysResult}, sys::{bpf_link_create, perf_event_ioctl, SysResult, SyscallError},
FEATURES, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, PERF_EVENT_IOC_SET_BPF, FEATURES, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, PERF_EVENT_IOC_SET_BPF,
}; };
@ -73,7 +73,7 @@ impl Link for PerfLink {
pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result<PerfLinkInner, ProgramError> { pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result<PerfLinkInner, ProgramError> {
if FEATURES.bpf_perf_link() { if FEATURES.bpf_perf_link() {
let link_fd = bpf_link_create(prog_fd, fd.as_raw_fd(), BPF_PERF_EVENT, None, 0).map_err( let link_fd = bpf_link_create(prog_fd, fd.as_raw_fd(), BPF_PERF_EVENT, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },
@ -98,13 +98,13 @@ fn perf_attach_either(
event: Option<ProbeEvent>, event: Option<ProbeEvent>,
) -> Result<PerfLinkInner, ProgramError> { ) -> Result<PerfLinkInner, ProgramError> {
perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_SET_BPF, prog_fd).map_err(|(_, io_error)| { perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_SET_BPF, prog_fd).map_err(|(_, io_error)| {
ProgramError::SyscallError { SyscallError {
call: "PERF_EVENT_IOC_SET_BPF", call: "PERF_EVENT_IOC_SET_BPF",
io_error, io_error,
} }
})?; })?;
perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_ENABLE, 0).map_err(|(_, io_error)| { perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_ENABLE, 0).map_err(|(_, io_error)| {
ProgramError::SyscallError { SyscallError {
call: "PERF_EVENT_IOC_ENABLE", call: "PERF_EVENT_IOC_ENABLE",
io_error, io_error,
} }

@ -19,7 +19,7 @@ use crate::{
perf_attach::{PerfLinkIdInner, PerfLinkInner}, perf_attach::{PerfLinkIdInner, PerfLinkInner},
FdLink, LinkError, ProgramData, ProgramError, FdLink, LinkError, ProgramData, ProgramError,
}, },
sys::{bpf_link_get_info_by_fd, perf_event_open}, sys::{bpf_link_get_info_by_fd, perf_event_open, SyscallError},
}; };
/// The type of perf event /// The type of perf event
@ -165,7 +165,7 @@ impl PerfEvent {
false, false,
0, 0,
) )
.map_err(|(_code, io_error)| ProgramError::SyscallError { .map_err(|(_code, io_error)| SyscallError {
call: "perf_event_open", call: "perf_event_open",
io_error, io_error,
})?; })?;
@ -206,12 +206,7 @@ impl TryFrom<FdLink> for PerfEventLink {
type Error = LinkError; type Error = LinkError;
fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> { fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> {
let info = let info = bpf_link_get_info_by_fd(fd_link.fd)?;
bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| LinkError::SyscallError {
call: "BPF_OBJ_GET_INFO_BY_FD",
code: 0,
io_error,
})?;
if info.type_ == (bpf_link_type::BPF_LINK_TYPE_PERF_EVENT as u32) { if info.type_ == (bpf_link_type::BPF_LINK_TYPE_PERF_EVENT as u32) {
return Ok(PerfEventLink::new(PerfLinkInner::FdLink(fd_link))); return Ok(PerfEventLink::new(PerfLinkInner::FdLink(fd_link)));
} }

@ -15,7 +15,7 @@ use crate::{
trace_point::read_sys_fs_trace_point_id, uprobe::UProbeError, utils::find_tracefs_path, trace_point::read_sys_fs_trace_point_id, uprobe::UProbeError, utils::find_tracefs_path,
Link, ProgramData, ProgramError, Link, ProgramData, ProgramError,
}, },
sys::{perf_event_open_probe, perf_event_open_trace_point}, sys::{perf_event_open_probe, perf_event_open_trace_point, SyscallError},
}; };
static PROBE_NAME_INDEX: AtomicUsize = AtomicUsize::new(0); static PROBE_NAME_INDEX: AtomicUsize = AtomicUsize::new(0);
@ -118,10 +118,11 @@ fn create_as_probe(
}; };
perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid).map_err(|(_code, io_error)| { perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid).map_err(|(_code, io_error)| {
ProgramError::SyscallError { SyscallError {
call: "perf_event_open", call: "perf_event_open",
io_error, io_error,
} }
.into()
}) })
} }
@ -144,11 +145,9 @@ fn create_as_trace_point(
let category = format!("{}s", kind.pmu()); let category = format!("{}s", kind.pmu());
let tpid = read_sys_fs_trace_point_id(tracefs, &category, &event_alias)?; let tpid = read_sys_fs_trace_point_id(tracefs, &category, &event_alias)?;
let fd = perf_event_open_trace_point(tpid, pid).map_err(|(_code, io_error)| { let fd = perf_event_open_trace_point(tpid, pid).map_err(|(_code, io_error)| SyscallError {
ProgramError::SyscallError {
call: "perf_event_open", call: "perf_event_open",
io_error, io_error,
}
})?; })?;
Ok((fd, event_alias)) Ok((fd, event_alias))

@ -3,7 +3,7 @@ use std::os::fd::{AsRawFd, RawFd};
use crate::{ use crate::{
generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP}, generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP},
programs::{define_link_wrapper, load_program, FdLinkId, ProgramData, ProgramError}, programs::{define_link_wrapper, load_program, FdLinkId, ProgramData, ProgramError},
sys::bpf_link_create, sys::{bpf_link_create, SyscallError},
}; };
use super::links::FdLink; use super::links::FdLink;
@ -65,7 +65,7 @@ impl SkLookup {
let netns_fd = netns.as_raw_fd(); let netns_fd = netns.as_raw_fd();
let link_fd = bpf_link_create(prog_fd, netns_fd, BPF_SK_LOOKUP, None, 0).map_err( let link_fd = bpf_link_create(prog_fd, netns_fd, BPF_SK_LOOKUP, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },

@ -9,7 +9,7 @@ use crate::{
define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramError, ProgramError,
}, },
sys::bpf_prog_attach, sys::{bpf_prog_attach, SyscallError},
}; };
/// A program used to intercept messages sent with `sendmsg()`/`sendfile()`. /// A program used to intercept messages sent with `sendmsg()`/`sendfile()`.
@ -83,7 +83,7 @@ impl SkMsg {
let map_fd = map.as_raw_fd(); let map_fd = map.as_raw_fd();
bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| {
ProgramError::SyscallError { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }

@ -12,7 +12,7 @@ use crate::{
define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramError, ProgramError,
}, },
sys::bpf_prog_attach, sys::{bpf_prog_attach, SyscallError},
VerifierLogLevel, VerifierLogLevel,
}; };
@ -79,11 +79,9 @@ impl SkSkb {
SkSkbKind::StreamParser => BPF_SK_SKB_STREAM_PARSER, SkSkbKind::StreamParser => BPF_SK_SKB_STREAM_PARSER,
SkSkbKind::StreamVerdict => BPF_SK_SKB_STREAM_VERDICT, SkSkbKind::StreamVerdict => BPF_SK_SKB_STREAM_VERDICT,
}; };
bpf_prog_attach(prog_fd, map_fd, attach_type).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, map_fd, attach_type).map_err(|(_, io_error)| SyscallError {
ProgramError::SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
}
})?; })?;
self.data.links.insert(SkSkbLink::new(ProgAttachLink::new( self.data.links.insert(SkSkbLink::new(ProgAttachLink::new(
prog_fd, prog_fd,

@ -7,7 +7,7 @@ use crate::{
define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramError, ProgramError,
}, },
sys::bpf_prog_attach, sys::{bpf_prog_attach, SyscallError},
}; };
/// A program used to work with sockets. /// A program used to work with sockets.
@ -63,7 +63,7 @@ impl SockOps {
let cgroup_fd = cgroup.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd();
bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS).map_err(|(_, io_error)| {
ProgramError::SyscallError { SyscallError {
call: "bpf_prog_attach", call: "bpf_prog_attach",
io_error, io_error,
} }

@ -10,7 +10,7 @@ use crate::{
utils::find_tracefs_path, utils::find_tracefs_path,
FdLink, LinkError, ProgramData, ProgramError, FdLink, LinkError, ProgramData, ProgramError,
}, },
sys::{bpf_link_get_info_by_fd, perf_event_open_trace_point}, sys::{bpf_link_get_info_by_fd, perf_event_open_trace_point, SyscallError},
}; };
/// The type returned when attaching a [`TracePoint`] fails. /// The type returned when attaching a [`TracePoint`] fails.
@ -80,11 +80,10 @@ impl TracePoint {
pub fn attach(&mut self, category: &str, name: &str) -> Result<TracePointLinkId, ProgramError> { pub fn attach(&mut self, category: &str, name: &str) -> Result<TracePointLinkId, ProgramError> {
let tracefs = find_tracefs_path()?; let tracefs = find_tracefs_path()?;
let id = read_sys_fs_trace_point_id(tracefs, category, name)?; let id = read_sys_fs_trace_point_id(tracefs, category, name)?;
let fd = perf_event_open_trace_point(id, None).map_err(|(_code, io_error)| { let fd =
ProgramError::SyscallError { perf_event_open_trace_point(id, None).map_err(|(_code, io_error)| SyscallError {
call: "perf_event_open_trace_point", call: "perf_event_open_trace_point",
io_error, io_error,
}
})?; })?;
let link = perf_attach(self.data.fd_or_err()?, fd)?; let link = perf_attach(self.data.fd_or_err()?, fd)?;
@ -132,12 +131,7 @@ impl TryFrom<FdLink> for TracePointLink {
type Error = LinkError; type Error = LinkError;
fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> { fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> {
let info = let info = bpf_link_get_info_by_fd(fd_link.fd)?;
bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| LinkError::SyscallError {
call: "BPF_OBJ_GET_INFO_BY_FD",
code: 0,
io_error,
})?;
if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) {
return Ok(TracePointLink::new(PerfLinkInner::FdLink(fd_link))); return Ok(TracePointLink::new(PerfLinkInner::FdLink(fd_link)));
} }

@ -177,12 +177,7 @@ impl TryFrom<FdLink> for UProbeLink {
type Error = LinkError; type Error = LinkError;
fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> { fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> {
let info = let info = bpf_link_get_info_by_fd(fd_link.fd)?;
bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| LinkError::SyscallError {
call: "BPF_OBJ_GET_INFO_BY_FD",
code: 0,
io_error,
})?;
if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) {
return Ok(UProbeLink::new(PerfLinkInner::FdLink(fd_link))); return Ok(UProbeLink::new(PerfLinkInner::FdLink(fd_link)));
} }

@ -3,7 +3,7 @@ use std::{ffi::CStr, io, os::fd::RawFd, path::Path};
use crate::{ use crate::{
programs::{FdLink, Link, ProgramData, ProgramError}, programs::{FdLink, Link, ProgramData, ProgramError},
sys::bpf_raw_tracepoint_open, sys::{bpf_raw_tracepoint_open, SyscallError},
}; };
/// Attaches the program to a raw tracepoint. /// Attaches the program to a raw tracepoint.
@ -13,11 +13,10 @@ pub(crate) fn attach_raw_tracepoint<T: Link + From<FdLink>>(
) -> Result<T::Id, ProgramError> { ) -> Result<T::Id, ProgramError> {
let prog_fd = program_data.fd_or_err()?; let prog_fd = program_data.fd_or_err()?;
let pfd = bpf_raw_tracepoint_open(tp_name, prog_fd).map_err(|(_code, io_error)| { let pfd =
ProgramError::SyscallError { bpf_raw_tracepoint_open(tp_name, prog_fd).map_err(|(_code, io_error)| SyscallError {
call: "bpf_raw_tracepoint_open", call: "bpf_raw_tracepoint_open",
io_error, io_error,
}
})? as RawFd; })? as RawFd;
program_data.links.insert(FdLink::new(pfd).into()) program_data.links.insert(FdLink::new(pfd).into())

@ -1,6 +1,6 @@
//! eXpress Data Path (XDP) programs. //! eXpress Data Path (XDP) programs.
use crate::util::KernelVersion; use crate::{sys::SyscallError, util::KernelVersion};
use bitflags; use bitflags;
use libc::if_nametoindex; use libc::if_nametoindex;
use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::fd::RawFd}; use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::fd::RawFd};
@ -127,7 +127,7 @@ impl Xdp {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) { if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) {
let link_fd = bpf_link_create(prog_fd, if_index, BPF_XDP, None, flags.bits()).map_err( let link_fd = bpf_link_create(prog_fd, if_index, BPF_XDP, None, flags.bits()).map_err(
|(_, io_error)| ProgramError::SyscallError { |(_, io_error)| SyscallError {
call: "bpf_link_create", call: "bpf_link_create",
io_error, io_error,
}, },
@ -173,7 +173,7 @@ impl Xdp {
XdpLinkInner::FdLink(fd_link) => { XdpLinkInner::FdLink(fd_link) => {
let link_fd = fd_link.fd; 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 { SyscallError {
call: "bpf_link_update", call: "bpf_link_update",
io_error, io_error,
} }
@ -279,12 +279,7 @@ 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 = let info = bpf_link_get_info_by_fd(fd_link.fd)?;
bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| LinkError::SyscallError {
call: "BPF_OBJ_GET_INFO_BY_FD",
code: 0,
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::new(XdpLinkInner::FdLink(fd_link))); return Ok(XdpLink::new(XdpLinkInner::FdLink(fd_link)));
} }

@ -1,7 +1,7 @@
use std::{ use std::{
cmp::{self, min}, cmp::{self, min},
ffi::{CStr, CString}, ffi::{CStr, CString},
io, io, iter,
mem::{self, MaybeUninit}, mem::{self, MaybeUninit},
os::fd::{AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, os::fd::{AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd},
slice, slice,
@ -28,7 +28,7 @@ use crate::{
}, },
copy_instructions, copy_instructions,
}, },
sys::{syscall, SysResult, Syscall}, sys::{syscall, SysResult, Syscall, SyscallError},
Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN, Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN,
}; };
@ -90,7 +90,7 @@ pub(crate) fn bpf_create_map(
.copy_from_slice(unsafe { slice::from_raw_parts(name.as_ptr(), name_len) }); .copy_from_slice(unsafe { slice::from_raw_parts(name.as_ptr(), name_len) });
} }
sys_bpf(bpf_cmd::BPF_MAP_CREATE, &attr) sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr)
} }
pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult<c_long> { pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult<c_long> {
@ -98,14 +98,14 @@ pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult<c_long> {
let u = unsafe { &mut attr.__bindgen_anon_4 }; let u = unsafe { &mut attr.__bindgen_anon_4 };
u.bpf_fd = fd as u32; u.bpf_fd = fd as u32;
u.pathname = path.as_ptr() as u64; u.pathname = path.as_ptr() as u64;
sys_bpf(bpf_cmd::BPF_OBJ_PIN, &attr) sys_bpf(bpf_cmd::BPF_OBJ_PIN, &mut attr)
} }
pub(crate) fn bpf_get_object(path: &CStr) -> SysResult<c_long> { pub(crate) fn bpf_get_object(path: &CStr) -> SysResult<c_long> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let u = unsafe { &mut attr.__bindgen_anon_4 }; let u = unsafe { &mut attr.__bindgen_anon_4 };
u.pathname = path.as_ptr() as u64; u.pathname = path.as_ptr() as u64;
sys_bpf(bpf_cmd::BPF_OBJ_GET, &attr) sys_bpf(bpf_cmd::BPF_OBJ_GET, &mut attr)
} }
pub(crate) struct BpfLoadProgramAttrs<'a> { pub(crate) struct BpfLoadProgramAttrs<'a> {
@ -188,7 +188,7 @@ pub(crate) fn bpf_load_program(
if let Some(v) = aya_attr.attach_btf_id { if let Some(v) = aya_attr.attach_btf_id {
u.attach_btf_id = v; u.attach_btf_id = v;
} }
sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr)
} }
fn lookup<K: Pod, V: Pod>( fn lookup<K: Pod, V: Pod>(
@ -208,7 +208,7 @@ fn lookup<K: Pod, V: Pod>(
u.__bindgen_anon_1.value = &mut value as *mut _ as u64; u.__bindgen_anon_1.value = &mut value as *mut _ as u64;
u.flags = flags; u.flags = flags;
match sys_bpf(cmd, &attr) { match sys_bpf(cmd, &mut attr) {
Ok(_) => Ok(Some(unsafe { value.assume_init() })), Ok(_) => Ok(Some(unsafe { value.assume_init() })),
Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None),
Err(e) => Err(e), Err(e) => Err(e),
@ -260,7 +260,7 @@ pub(crate) fn bpf_map_lookup_elem_ptr<K: Pod, V>(
u.__bindgen_anon_1.value = value as u64; u.__bindgen_anon_1.value = value as u64;
u.flags = flags; u.flags = flags;
match sys_bpf(bpf_cmd::BPF_MAP_LOOKUP_ELEM, &attr) { match sys_bpf(bpf_cmd::BPF_MAP_LOOKUP_ELEM, &mut attr) {
Ok(_) => Ok(Some(())), Ok(_) => Ok(Some(())),
Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None),
Err(e) => Err(e), Err(e) => Err(e),
@ -283,7 +283,7 @@ pub(crate) fn bpf_map_update_elem<K: Pod, V: Pod>(
u.__bindgen_anon_1.value = value as *const _ as u64; u.__bindgen_anon_1.value = value as *const _ as u64;
u.flags = flags; u.flags = flags;
sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &attr) sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr)
} }
pub(crate) fn bpf_map_push_elem<V: Pod>(fd: RawFd, value: &V, flags: u64) -> SysResult<c_long> { pub(crate) fn bpf_map_push_elem<V: Pod>(fd: RawFd, value: &V, flags: u64) -> SysResult<c_long> {
@ -294,7 +294,7 @@ pub(crate) fn bpf_map_push_elem<V: Pod>(fd: RawFd, value: &V, flags: u64) -> Sys
u.__bindgen_anon_1.value = value as *const _ as u64; u.__bindgen_anon_1.value = value as *const _ as u64;
u.flags = flags; u.flags = flags;
sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &attr) sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr)
} }
pub(crate) fn bpf_map_update_elem_ptr<K, V>( pub(crate) fn bpf_map_update_elem_ptr<K, V>(
@ -311,7 +311,7 @@ pub(crate) fn bpf_map_update_elem_ptr<K, V>(
u.__bindgen_anon_1.value = value as u64; u.__bindgen_anon_1.value = value as u64;
u.flags = flags; u.flags = flags;
sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &attr) sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr)
} }
pub(crate) fn bpf_map_update_elem_per_cpu<K: Pod, V: Pod>( pub(crate) fn bpf_map_update_elem_per_cpu<K: Pod, V: Pod>(
@ -331,7 +331,7 @@ pub(crate) fn bpf_map_delete_elem<K: Pod>(fd: RawFd, key: &K) -> SysResult<c_lon
u.map_fd = fd as u32; u.map_fd = fd as u32;
u.key = key as *const _ as u64; u.key = key as *const _ as u64;
sys_bpf(bpf_cmd::BPF_MAP_DELETE_ELEM, &attr) sys_bpf(bpf_cmd::BPF_MAP_DELETE_ELEM, &mut attr)
} }
pub(crate) fn bpf_map_get_next_key<K: Pod>( pub(crate) fn bpf_map_get_next_key<K: Pod>(
@ -348,7 +348,7 @@ pub(crate) fn bpf_map_get_next_key<K: Pod>(
} }
u.__bindgen_anon_1.next_key = &mut next_key as *mut _ as u64; u.__bindgen_anon_1.next_key = &mut next_key as *mut _ as u64;
match sys_bpf(bpf_cmd::BPF_MAP_GET_NEXT_KEY, &attr) { match sys_bpf(bpf_cmd::BPF_MAP_GET_NEXT_KEY, &mut attr) {
Ok(_) => Ok(Some(unsafe { next_key.assume_init() })), Ok(_) => Ok(Some(unsafe { next_key.assume_init() })),
Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None),
Err(e) => Err(e), Err(e) => Err(e),
@ -360,7 +360,7 @@ pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult<c_long> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let u = unsafe { &mut attr.__bindgen_anon_2 }; let u = unsafe { &mut attr.__bindgen_anon_2 };
u.map_fd = fd as u32; u.map_fd = fd as u32;
sys_bpf(bpf_cmd::BPF_MAP_FREEZE, &attr) sys_bpf(bpf_cmd::BPF_MAP_FREEZE, &mut attr)
} }
// since kernel 5.7 // since kernel 5.7
@ -381,7 +381,7 @@ pub(crate) fn bpf_link_create(
attr.link_create.__bindgen_anon_3.target_btf_id = btf_id; attr.link_create.__bindgen_anon_3.target_btf_id = btf_id;
} }
sys_bpf(bpf_cmd::BPF_LINK_CREATE, &attr) sys_bpf(bpf_cmd::BPF_LINK_CREATE, &mut attr)
} }
// since kernel 5.7 // since kernel 5.7
@ -402,7 +402,7 @@ pub(crate) fn bpf_link_update(
attr.link_update.flags = flags; attr.link_update.flags = flags;
} }
sys_bpf(bpf_cmd::BPF_LINK_UPDATE, &attr) sys_bpf(bpf_cmd::BPF_LINK_UPDATE, &mut attr)
} }
pub(crate) fn bpf_prog_attach( pub(crate) fn bpf_prog_attach(
@ -416,7 +416,7 @@ pub(crate) fn bpf_prog_attach(
attr.__bindgen_anon_5.target_fd = target_fd as u32; attr.__bindgen_anon_5.target_fd = target_fd as u32;
attr.__bindgen_anon_5.attach_type = attach_type as u32; attr.__bindgen_anon_5.attach_type = attach_type as u32;
sys_bpf(bpf_cmd::BPF_PROG_ATTACH, &attr) sys_bpf(bpf_cmd::BPF_PROG_ATTACH, &mut attr)
} }
pub(crate) fn bpf_prog_detach( pub(crate) fn bpf_prog_detach(
@ -430,7 +430,7 @@ pub(crate) fn bpf_prog_detach(
attr.__bindgen_anon_5.target_fd = map_fd as u32; attr.__bindgen_anon_5.target_fd = map_fd as u32;
attr.__bindgen_anon_5.attach_type = attach_type as u32; attr.__bindgen_anon_5.attach_type = attach_type as u32;
sys_bpf(bpf_cmd::BPF_PROG_DETACH, &attr) sys_bpf(bpf_cmd::BPF_PROG_DETACH, &mut attr)
} }
pub(crate) fn bpf_prog_query( pub(crate) fn bpf_prog_query(
@ -449,7 +449,7 @@ pub(crate) fn bpf_prog_query(
attr.query.prog_cnt = prog_ids.len() as u32; attr.query.prog_cnt = prog_ids.len() as u32;
attr.query.prog_ids = prog_ids.as_mut_ptr() as u64; attr.query.prog_ids = prog_ids.as_mut_ptr() as u64;
let ret = sys_bpf(bpf_cmd::BPF_PROG_QUERY, &attr); let ret = sys_bpf(bpf_cmd::BPF_PROG_QUERY, &mut attr);
*prog_cnt = unsafe { attr.query.prog_cnt }; *prog_cnt = unsafe { attr.query.prog_cnt };
@ -460,57 +460,71 @@ pub(crate) fn bpf_prog_query(
ret ret
} }
pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result<OwnedFd, io::Error> { pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result<OwnedFd, SyscallError> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
attr.__bindgen_anon_6.__bindgen_anon_1.prog_id = prog_id; attr.__bindgen_anon_6.__bindgen_anon_1.prog_id = prog_id;
// SAFETY: BPF_PROG_GET_FD_BY_ID returns a new file descriptor. // SAFETY: BPF_PROG_GET_FD_BY_ID returns a new file descriptor.
unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &attr).map_err(|(_, e)| e) } unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| {
assert_eq!(code, -1);
SyscallError {
call: "bpf_prog_get_fd_by_id",
io_error,
}
})
} }
pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: RawFd) -> Result<bpf_prog_info, io::Error> { fn bpf_obj_get_info_by_fd<T>(fd: BorrowedFd<'_>) -> Result<T, SyscallError> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
// info gets entirely populated by the kernel // info gets entirely populated by the kernel
let info = MaybeUninit::zeroed(); let info = MaybeUninit::zeroed();
attr.info.bpf_fd = prog_fd as u32; attr.info.bpf_fd = fd.as_raw_fd() as u32;
attr.info.info = &info as *const _ as u64; attr.info.info = &info as *const _ as u64;
attr.info.info_len = mem::size_of::<bpf_prog_info>() as u32; attr.info.info_len = mem::size_of_val(&info) as u32;
match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) { match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) {
Ok(_) => Ok(unsafe { info.assume_init() }), Ok(code) => {
Err((_, err)) => Err(err), assert_eq!(code, 0);
Ok(unsafe { info.assume_init() })
}
Err((code, io_error)) => {
assert_eq!(code, -1);
Err(SyscallError {
call: "bpf_obj_get_info_by_fd",
io_error,
})
}
} }
} }
pub(crate) fn bpf_map_get_info_by_fd(prog_fd: RawFd) -> Result<bpf_map_info, io::Error> { pub(crate) fn bpf_prog_get_info_by_fd(fd: RawFd) -> Result<bpf_prog_info, SyscallError> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let fd = unsafe { BorrowedFd::borrow_raw(fd) };
// info gets entirely populated by the kernel bpf_obj_get_info_by_fd::<bpf_prog_info>(fd)
let info = MaybeUninit::zeroed();
attr.info.bpf_fd = prog_fd as u32;
attr.info.info = info.as_ptr() as *const _ as u64;
attr.info.info_len = mem::size_of::<bpf_map_info>() as u32;
match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) {
Ok(_) => Ok(unsafe { info.assume_init() }),
Err((_, err)) => Err(err),
} }
pub(crate) fn bpf_map_get_info_by_fd(fd: RawFd) -> Result<bpf_map_info, SyscallError> {
let fd = unsafe { BorrowedFd::borrow_raw(fd) };
bpf_obj_get_info_by_fd::<bpf_map_info>(fd)
} }
pub(crate) fn bpf_link_get_info_by_fd(link_fd: RawFd) -> Result<bpf_link_info, io::Error> { pub(crate) fn bpf_link_get_fd_by_id(link_id: u32) -> Result<OwnedFd, SyscallError> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
// info gets entirely populated by the kernel
let info = unsafe { MaybeUninit::zeroed().assume_init() };
attr.info.bpf_fd = link_fd as u32; attr.__bindgen_anon_6.__bindgen_anon_1.link_id = link_id;
attr.info.info = &info as *const _ as u64; // SAFETY: BPF_LINK_GET_FD_BY_ID returns a new file descriptor.
attr.info.info_len = mem::size_of::<bpf_link_info>() as u32; unsafe { fd_sys_bpf(bpf_cmd::BPF_LINK_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| {
assert_eq!(code, -1);
match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) { SyscallError {
Ok(_) => Ok(info), call: "bpf_link_get_fd_by_id",
Err((_, err)) => Err(err), io_error,
} }
})
}
pub(crate) fn bpf_link_get_info_by_fd(fd: RawFd) -> Result<bpf_link_info, SyscallError> {
let fd = unsafe { BorrowedFd::borrow_raw(fd) };
bpf_obj_get_info_by_fd::<bpf_link_info>(fd)
} }
pub(crate) fn btf_obj_get_info_by_fd( pub(crate) fn btf_obj_get_info_by_fd(
@ -526,7 +540,7 @@ pub(crate) fn btf_obj_get_info_by_fd(
attr.info.info = &info as *const bpf_btf_info as u64; attr.info.info = &info as *const bpf_btf_info as u64;
attr.info.info_len = mem::size_of::<bpf_btf_info>() as u32; attr.info.info_len = mem::size_of::<bpf_btf_info>() as u32;
match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) { match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) {
Ok(_) => Ok(info), Ok(_) => Ok(info),
Err((_, err)) => Err(err), Err((_, err)) => Err(err),
} }
@ -541,7 +555,7 @@ pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> Sy
}; };
attr.raw_tracepoint.prog_fd = prog_fd as u32; attr.raw_tracepoint.prog_fd = prog_fd as u32;
sys_bpf(bpf_cmd::BPF_RAW_TRACEPOINT_OPEN, &attr) sys_bpf(bpf_cmd::BPF_RAW_TRACEPOINT_OPEN, &mut attr)
} }
pub(crate) fn bpf_load_btf( pub(crate) fn bpf_load_btf(
@ -559,11 +573,11 @@ pub(crate) fn bpf_load_btf(
u.btf_log_size = log_buf.len() as u32; u.btf_log_size = log_buf.len() as u32;
} }
// SAFETY: `BPF_BTF_LOAD` returns a newly created fd. // SAFETY: `BPF_BTF_LOAD` returns a newly created fd.
unsafe { fd_sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr) } unsafe { fd_sys_bpf(bpf_cmd::BPF_BTF_LOAD, &mut attr) }
} }
// SAFETY: only use for bpf_cmd that return a new file descriptor on success. // SAFETY: only use for bpf_cmd that return a new file descriptor on success.
unsafe fn fd_sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult<OwnedFd> { unsafe fn fd_sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult<OwnedFd> {
let fd = sys_bpf(cmd, attr)?; let fd = sys_bpf(cmd, attr)?;
let fd = fd.try_into().map_err(|_| { let fd = fd.try_into().map_err(|_| {
( (
@ -581,7 +595,7 @@ pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result<RawFd, io::Error> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
attr.__bindgen_anon_6.__bindgen_anon_1.btf_id = id; attr.__bindgen_anon_6.__bindgen_anon_1.btf_id = id;
match sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &attr) { match sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &mut attr) {
Ok(v) => Ok(v as RawFd), Ok(v) => Ok(v as RawFd),
Err((_, err)) => Err(err), Err((_, err)) => Err(err),
} }
@ -612,7 +626,7 @@ pub(crate) fn is_prog_name_supported() -> bool {
u.insns = insns.as_ptr() as u64; u.insns = insns.as_ptr() as u64;
u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32;
match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) {
Ok(v) => { Ok(v) => {
let fd = v as RawFd; let fd = v as RawFd;
unsafe { close(fd) }; unsafe { close(fd) };
@ -643,7 +657,7 @@ pub(crate) fn is_probe_read_kernel_supported() -> bool {
u.insns = insns.as_ptr() as u64; u.insns = insns.as_ptr() as u64;
u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32;
match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) {
Ok(v) => { Ok(v) => {
let fd = v as RawFd; let fd = v as RawFd;
unsafe { close(fd) }; unsafe { close(fd) };
@ -670,7 +684,7 @@ pub(crate) fn is_perf_link_supported() -> bool {
u.insns = insns.as_ptr() as u64; u.insns = insns.as_ptr() as u64;
u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32;
if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) {
if let Err((_, e)) = if let Err((_, e)) =
// Uses an invalid target FD so we get EBADF if supported. // Uses an invalid target FD so we get EBADF if supported.
bpf_link_create(fd as i32, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0) bpf_link_create(fd as i32, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0)
@ -726,7 +740,7 @@ pub(crate) fn is_bpf_global_data_supported() -> bool {
u.insns = insns.as_ptr() as u64; u.insns = insns.as_ptr() as u64;
u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32;
if let Ok(v) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { if let Ok(v) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) {
let fd = v as RawFd; let fd = v as RawFd;
unsafe { close(fd) }; unsafe { close(fd) };
@ -755,7 +769,7 @@ pub(crate) fn is_bpf_cookie_supported() -> bool {
u.insns = insns.as_ptr() as u64; u.insns = insns.as_ptr() as u64;
u.prog_type = bpf_prog_type::BPF_PROG_TYPE_KPROBE as u32; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_KPROBE as u32;
match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) {
Ok(v) => { Ok(v) => {
let fd = v as RawFd; let fd = v as RawFd;
unsafe { close(fd) }; unsafe { close(fd) };
@ -905,19 +919,61 @@ pub(crate) fn is_btf_type_tag_supported() -> bool {
bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok()
} }
pub fn sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult<c_long> { fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult<c_long> {
syscall(Syscall::Bpf { cmd, attr }) syscall(Syscall::Bpf { cmd, attr })
} }
pub(crate) fn bpf_prog_get_next_id(id: u32) -> Result<Option<u32>, (c_long, io::Error)> { 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, &attr) { match sys_bpf(cmd, &mut attr) {
Ok(_) => Ok(Some(unsafe { attr.__bindgen_anon_6.next_id })), Ok(code) => {
Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), assert_eq!(code, 0);
Err(e) => Err(e), Ok(Some(unsafe { attr.__bindgen_anon_6.next_id }))
}
Err((code, io_error)) => {
assert_eq!(code, -1);
if io_error.raw_os_error() == Some(ENOENT) {
Ok(None)
} else {
Err(SyscallError {
call: name,
io_error,
})
}
}
}
} }
fn iter_obj_ids(
cmd: bpf_cmd,
name: &'static str,
) -> impl Iterator<Item = Result<u32, SyscallError>> {
let mut current_id = Some(0);
iter::from_fn(move || {
let next_id = {
let current_id = current_id?;
bpf_obj_get_next_id(current_id, cmd, name).transpose()
};
current_id = next_id.as_ref().and_then(|next_id| match next_id {
Ok(next_id) => Some(*next_id),
Err(SyscallError { .. }) => None,
});
next_id
})
}
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>(

@ -5,12 +5,12 @@ mod perf_event;
#[cfg(test)] #[cfg(test)]
mod fake; mod fake;
use libc::{c_int, c_long, pid_t, SYS_bpf, SYS_perf_event_open};
use std::{ use std::{
io, mem, io, mem,
os::fd::{AsRawFd as _, BorrowedFd}, os::fd::{AsRawFd as _, BorrowedFd},
}; };
use thiserror::Error;
use libc::{c_int, c_long, pid_t, SYS_bpf, SYS_perf_event_open};
pub(crate) use bpf::*; pub(crate) use bpf::*;
#[cfg(test)] #[cfg(test)]
@ -27,7 +27,7 @@ pub(crate) type SysResult<T> = Result<T, (c_long, io::Error)>;
pub(crate) enum Syscall<'a> { pub(crate) enum Syscall<'a> {
Bpf { Bpf {
cmd: bpf_cmd, cmd: bpf_cmd,
attr: &'a bpf_attr, attr: &'a mut bpf_attr,
}, },
PerfEventOpen { PerfEventOpen {
attr: perf_event_attr, attr: perf_event_attr,
@ -43,6 +43,16 @@ pub(crate) enum Syscall<'a> {
}, },
} }
#[derive(Debug, Error)]
#[error("`{call}` failed")]
pub struct SyscallError {
/// The name of the syscall which failed.
pub(crate) call: &'static str,
/// The [`io::Error`] returned by the syscall.
#[source]
pub(crate) io_error: io::Error,
}
impl std::fmt::Debug for Syscall<'_> { impl std::fmt::Debug for Syscall<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {

@ -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() {

@ -996,9 +996,7 @@ pub aya::maps::MapError::PinError
pub aya::maps::MapError::PinError::error: aya::pin::PinError pub aya::maps::MapError::PinError::error: aya::pin::PinError
pub aya::maps::MapError::PinError::name: core::option::Option<alloc::string::String> pub aya::maps::MapError::PinError::name: core::option::Option<alloc::string::String>
pub aya::maps::MapError::ProgramNotLoaded pub aya::maps::MapError::ProgramNotLoaded
pub aya::maps::MapError::SyscallError pub aya::maps::MapError::SyscallError(crate::sys::SyscallError)
pub aya::maps::MapError::SyscallError::call: &'static str
pub aya::maps::MapError::SyscallError::io_error: std::io::error::Error
pub aya::maps::MapError::Unsupported pub aya::maps::MapError::Unsupported
pub aya::maps::MapError::Unsupported::map_type: u32 pub aya::maps::MapError::Unsupported::map_type: u32
impl core::convert::From<aya::maps::MapError> for aya::BpfError impl core::convert::From<aya::maps::MapError> for aya::BpfError
@ -1764,9 +1762,7 @@ pub aya::pin::PinError::InvalidPinPath
pub aya::pin::PinError::InvalidPinPath::error: alloc::string::String pub aya::pin::PinError::InvalidPinPath::error: alloc::string::String
pub aya::pin::PinError::NoFd pub aya::pin::PinError::NoFd
pub aya::pin::PinError::NoFd::name: alloc::string::String pub aya::pin::PinError::NoFd::name: alloc::string::String
pub aya::pin::PinError::SyscallError pub aya::pin::PinError::SyscallError(crate::sys::SyscallError)
pub aya::pin::PinError::SyscallError::io_error: std::io::error::Error
pub aya::pin::PinError::SyscallError::name: &'static str
impl core::error::Error for aya::pin::PinError impl core::error::Error for aya::pin::PinError
pub fn aya::pin::PinError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> pub fn aya::pin::PinError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)>
impl core::fmt::Display for aya::pin::PinError impl core::fmt::Display for aya::pin::PinError
@ -3008,10 +3004,7 @@ pub fn aya::programs::kprobe::KProbeLinkId::from(t: T) -> T
pub mod aya::programs::links pub mod aya::programs::links
pub enum aya::programs::links::LinkError pub enum aya::programs::links::LinkError
pub aya::programs::links::LinkError::InvalidLink pub aya::programs::links::LinkError::InvalidLink
pub aya::programs::links::LinkError::SyscallError pub aya::programs::links::LinkError::SyscallError(crate::sys::SyscallError)
pub aya::programs::links::LinkError::SyscallError::call: &'static str
pub aya::programs::links::LinkError::SyscallError::code: libc::unix::linux_like::linux::gnu::b64::x86_64::not_x32::c_long
pub aya::programs::links::LinkError::SyscallError::io_error: std::io::error::Error
impl core::error::Error for aya::programs::links::LinkError impl core::error::Error for aya::programs::links::LinkError
pub fn aya::programs::links::LinkError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> pub fn aya::programs::links::LinkError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)>
impl core::fmt::Display for aya::programs::links::LinkError impl core::fmt::Display for aya::programs::links::LinkError
@ -5174,9 +5167,7 @@ pub aya::programs::ProgramError::MapError(aya::maps::MapError)
pub aya::programs::ProgramError::NotAttached pub aya::programs::ProgramError::NotAttached
pub aya::programs::ProgramError::NotLoaded pub aya::programs::ProgramError::NotLoaded
pub aya::programs::ProgramError::SocketFilterError(aya::programs::SocketFilterError) pub aya::programs::ProgramError::SocketFilterError(aya::programs::SocketFilterError)
pub aya::programs::ProgramError::SyscallError pub aya::programs::ProgramError::SyscallError(crate::sys::SyscallError)
pub aya::programs::ProgramError::SyscallError::call: &'static str
pub aya::programs::ProgramError::SyscallError::io_error: std::io::error::Error
pub aya::programs::ProgramError::TcError(aya::programs::tc::TcError) pub aya::programs::ProgramError::TcError(aya::programs::tc::TcError)
pub aya::programs::ProgramError::TracePointError(aya::programs::trace_point::TracePointError) pub aya::programs::ProgramError::TracePointError(aya::programs::trace_point::TracePointError)
pub aya::programs::ProgramError::UProbeError(aya::programs::uprobe::UProbeError) pub aya::programs::ProgramError::UProbeError(aya::programs::uprobe::UProbeError)
@ -6237,35 +6228,6 @@ impl<T> core::borrow::BorrowMut<T> for aya::programs::ProgramInfo where T: core:
pub fn aya::programs::ProgramInfo::borrow_mut(&mut self) -> &mut T pub fn aya::programs::ProgramInfo::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::ProgramInfo impl<T> core::convert::From<T> for aya::programs::ProgramInfo
pub fn aya::programs::ProgramInfo::from(t: T) -> T pub fn aya::programs::ProgramInfo::from(t: T) -> T
pub struct aya::programs::ProgramsIter
impl core::iter::traits::iterator::Iterator for aya::programs::ProgramsIter
pub type aya::programs::ProgramsIter::Item = core::result::Result<aya::programs::ProgramInfo, aya::programs::ProgramError>
pub fn aya::programs::ProgramsIter::next(&mut self) -> core::option::Option<Self::Item>
impl core::marker::Send for aya::programs::ProgramsIter
impl core::marker::Sync for aya::programs::ProgramsIter
impl core::marker::Unpin for aya::programs::ProgramsIter
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::ProgramsIter
impl core::panic::unwind_safe::UnwindSafe for aya::programs::ProgramsIter
impl<I> core::iter::traits::collect::IntoIterator for aya::programs::ProgramsIter where I: core::iter::traits::iterator::Iterator
pub type aya::programs::ProgramsIter::IntoIter = I
pub type aya::programs::ProgramsIter::Item = <I as core::iter::traits::iterator::Iterator>::Item
pub fn aya::programs::ProgramsIter::into_iter(self) -> I
impl<T, U> core::convert::Into<U> for aya::programs::ProgramsIter where U: core::convert::From<T>
pub fn aya::programs::ProgramsIter::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::ProgramsIter where U: core::convert::Into<T>
pub type aya::programs::ProgramsIter::Error = core::convert::Infallible
pub fn aya::programs::ProgramsIter::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::ProgramsIter where U: core::convert::TryFrom<T>
pub type aya::programs::ProgramsIter::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::ProgramsIter::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::ProgramsIter where T: 'static + core::marker::Sized
pub fn aya::programs::ProgramsIter::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::ProgramsIter where T: core::marker::Sized
pub fn aya::programs::ProgramsIter::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::ProgramsIter where T: core::marker::Sized
pub fn aya::programs::ProgramsIter::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::ProgramsIter
pub fn aya::programs::ProgramsIter::from(t: T) -> T
pub struct aya::programs::RawTracePoint pub struct aya::programs::RawTracePoint
impl aya::programs::RawTracePoint impl aya::programs::RawTracePoint
pub fn aya::programs::RawTracePoint::attach(&mut self, tp_name: &str) -> core::result::Result<RawTracePointLinkId, aya::programs::ProgramError> pub fn aya::programs::RawTracePoint::attach(&mut self, tp_name: &str) -> core::result::Result<RawTracePointLinkId, aya::programs::ProgramError>
@ -6928,7 +6890,7 @@ impl aya::programs::links::Link for aya::programs::xdp::XdpLink
pub type aya::programs::xdp::XdpLink::Id = aya::programs::xdp::XdpLinkId pub type aya::programs::xdp::XdpLink::Id = aya::programs::xdp::XdpLinkId
pub fn aya::programs::xdp::XdpLink::detach(self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::xdp::XdpLink::detach(self) -> core::result::Result<(), aya::programs::ProgramError>
pub fn aya::programs::xdp::XdpLink::id(&self) -> Self::Id pub fn aya::programs::xdp::XdpLink::id(&self) -> Self::Id
pub fn aya::programs::loaded_programs() -> aya::programs::ProgramsIter pub fn aya::programs::loaded_programs() -> impl core::iter::traits::iterator::Iterator<Item = core::result::Result<aya::programs::ProgramInfo, aya::programs::ProgramError>>
pub mod aya::util pub mod aya::util
pub struct aya::util::KernelVersion pub struct aya::util::KernelVersion
impl aya::util::KernelVersion impl aya::util::KernelVersion
@ -7259,4 +7221,4 @@ impl aya::Pod for u8
impl<K: aya::Pod> aya::Pod for aya::maps::lpm_trie::Key<K> impl<K: aya::Pod> aya::Pod for aya::maps::lpm_trie::Key<K>
impl<T: aya::Pod, const N: usize> aya::Pod for [T; N] impl<T: aya::Pod, const N: usize> aya::Pod for [T; N]
pub fn aya::features() -> &'static aya_obj::obj::Features pub fn aya::features() -> &'static aya_obj::obj::Features
pub fn aya::loaded_programs() -> aya::programs::ProgramsIter pub fn aya::loaded_programs() -> impl core::iter::traits::iterator::Iterator<Item = core::result::Result<aya::programs::ProgramInfo, aya::programs::ProgramError>>

Loading…
Cancel
Save