diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 0947c8fd..20eac41f 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -110,7 +110,7 @@ use crate::{ pin::PinError, sys::{ bpf_btf_get_fd_by_id, bpf_get_object, bpf_load_program, bpf_pin_object, - bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_get_next_id, bpf_prog_query, + bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_query, iter_prog_ids, retry_with_verifier_logs, BpfLoadProgramAttrs, SyscallError, }, util::KernelVersion, @@ -971,56 +971,6 @@ impl ProgramInfo { } } -/// ProgramsIter is an Iterator over loaded eBPF programs. -pub struct ProgramsIter { - current: u32, - error: bool, -} - -impl Iterator for ProgramsIter { - type Item = Result; - - fn next(&mut self) -> Option { - 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| 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| SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - }) - .map(ProgramInfo) - }) - .map_err(Into::into), - ) - } - 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(SyscallError { - call: "bpf_prog_get_fd_by_id", - io_error, - } - .into())) - } - } - } -} - /// Returns an iterator over all loaded bpf programs. /// /// This differs from [`crate::Bpf::programs`] since it will return all programs @@ -1044,9 +994,21 @@ impl Iterator for ProgramsIter { /// 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, /// a single item will be yielded containing the error that occurred. -pub fn loaded_programs() -> ProgramsIter { - ProgramsIter { - current: 0, - error: false, - } +pub fn loaded_programs() -> impl Iterator> { + iter_prog_ids() + .map(|id| { + let id = id?; + bpf_prog_get_fd_by_id(id).map_err(|io_error| SyscallError { + call: "bpf_prog_get_fd_by_id", + io_error, + }) + }) + .map(|fd| { + let fd = fd?; + bpf_prog_get_info_by_fd(fd.as_raw_fd()).map_err(|io_error| SyscallError { + call: "bpf_prog_get_info_by_fd", + io_error, + }) + }) + .map(|result| result.map(ProgramInfo).map_err(Into::into)) } diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index ab8de01c..e4a4becc 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -1,7 +1,7 @@ use std::{ cmp::{self, min}, ffi::{CStr, CString}, - io, + io, iter, mem::{self, MaybeUninit}, os::fd::{AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, slice, @@ -28,7 +28,7 @@ use crate::{ }, copy_instructions, }, - sys::{syscall, SysResult, Syscall}, + sys::{syscall, SysResult, Syscall, SyscallError}, Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN, }; @@ -994,17 +994,44 @@ fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } -pub(crate) fn bpf_prog_get_next_id(id: u32) -> Result, (c_long, io::Error)> { +fn bpf_prog_get_next_id(id: u32) -> Result, SyscallError> { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_6 }; u.__bindgen_anon_1.start_id = id; match sys_bpf(bpf_cmd::BPF_PROG_GET_NEXT_ID, &mut attr) { - Ok(_) => Ok(Some(unsafe { attr.__bindgen_anon_6.next_id })), - Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), - Err(e) => Err(e), + Ok(code) => { + assert_eq!(code, 0); + 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: "bpf_prog_get_next_id", + io_error, + }) + } + } } } +pub(crate) fn iter_prog_ids() -> impl Iterator> { + let mut current_id = Some(0); + iter::from_fn(move || { + let next_id = { + let current_id = current_id?; + bpf_prog_get_next_id(current_id).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 retry_with_verifier_logs( max_retries: usize, f: impl Fn(&mut [u8]) -> SysResult, diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index da13c4a7..a545bd61 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -6228,35 +6228,6 @@ impl core::borrow::BorrowMut for aya::programs::ProgramInfo where T: core: pub fn aya::programs::ProgramInfo::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::programs::ProgramInfo 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 -pub fn aya::programs::ProgramsIter::next(&mut self) -> core::option::Option -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 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 = ::Item -pub fn aya::programs::ProgramsIter::into_iter(self) -> I -impl core::convert::Into for aya::programs::ProgramsIter where U: core::convert::From -pub fn aya::programs::ProgramsIter::into(self) -> U -impl core::convert::TryFrom for aya::programs::ProgramsIter where U: core::convert::Into -pub type aya::programs::ProgramsIter::Error = core::convert::Infallible -pub fn aya::programs::ProgramsIter::try_from(value: U) -> core::result::Result>::Error> -impl core::convert::TryInto for aya::programs::ProgramsIter where U: core::convert::TryFrom -pub type aya::programs::ProgramsIter::Error = >::Error -pub fn aya::programs::ProgramsIter::try_into(self) -> core::result::Result>::Error> -impl 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 core::borrow::Borrow for aya::programs::ProgramsIter where T: core::marker::Sized -pub fn aya::programs::ProgramsIter::borrow(&self) -> &T -impl core::borrow::BorrowMut for aya::programs::ProgramsIter where T: core::marker::Sized -pub fn aya::programs::ProgramsIter::borrow_mut(&mut self) -> &mut T -impl core::convert::From for aya::programs::ProgramsIter -pub fn aya::programs::ProgramsIter::from(t: T) -> T pub struct aya::programs::RawTracePoint impl aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::attach(&mut self, tp_name: &str) -> core::result::Result @@ -6919,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 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::loaded_programs() -> aya::programs::ProgramsIter +pub fn aya::programs::loaded_programs() -> impl core::iter::traits::iterator::Iterator> pub mod aya::util pub struct aya::util::KernelVersion impl aya::util::KernelVersion @@ -7250,4 +7221,4 @@ impl aya::Pod for u8 impl aya::Pod for aya::maps::lpm_trie::Key impl aya::Pod for [T; N] 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>