From e66f9540c9196ecce16431542366771b6505124f Mon Sep 17 00:00:00 2001 From: Catalin Horghidan Date: Sat, 17 Feb 2024 21:14:21 +0200 Subject: [PATCH 1/3] aya-log: allow re-attach and read previously created logs This feature is useful if someone wants to view the log contents of a program that is already running. For e.g. a pinned program or an XDP program attached to a net interface. --- aya-log/src/lib.rs | 65 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index e24acfb4..3dd5b171 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -60,10 +60,12 @@ use std::{ const MAP_NAME: &str = "AYA_LOGS"; use aya::{ + loaded_programs, maps::{ perf::{AsyncPerfEventArray, Events, PerfBufferError}, - MapError, + Map, MapData, MapError, MapInfo, }, + programs::ProgramError, util::online_cpus, Ebpf, Pod, }; @@ -112,12 +114,54 @@ impl EbpfLogger { bpf: &mut Ebpf, logger: T, ) -> Result { - let logger = Arc::new(logger); - let mut logs: AsyncPerfEventArray<_> = bpf - .take_map(MAP_NAME) - .ok_or(Error::MapNotFound)? - .try_into()?; + let map = bpf.take_map(MAP_NAME).ok_or(Error::MapNotFound)?; + Self::read_logs_async(map, logger)?; + Ok(EbpfLogger {}) + } + + /// Attaches to an existing `aya-log-ebpf` log created by a running ebpf + /// program identified by `program_id`. The log records will be written + /// to the default logger. See [log::logger]. + /// It can be used to review the log for a pinned program after the user + /// application exits. + pub fn init_from_id(program_id: u32) -> Result { + Self::init_from_id_with_logger(program_id, log::logger()) + } + /// Attaches to an existing `aya-log-ebpf` log created by a running ebpf + /// program identified by `program_id`. The log records will be written + /// to the user provided logger. + /// It can be used to review the log for a pinned program after the user + /// application exits. + pub fn init_from_id_with_logger( + program_id: u32, + logger: T, + ) -> Result { + let program_info = loaded_programs() + .filter_map(|info| info.ok()) + .find(|info| info.id() == program_id) + .ok_or(Error::ProgramNotFound)?; + let map = program_info + .map_ids() + .map_err(Error::ProgramError)? + .iter() + .filter_map(|id| MapInfo::from_id(*id).ok()) + .find(|map_info| match map_info.name_as_str() { + Some(name) => name == MAP_NAME, + None => false, + }) + .ok_or(Error::MapNotFound)?; + let map = MapData::from_id(map.id()).map_err(Error::MapError)?; + + Self::read_logs_async(Map::PerfEventArray(map), logger)?; + + Ok(EbpfLogger {}) + } + + fn read_logs_async(map: Map, logger: T) -> Result<(), Error> { + let mut logs: AsyncPerfEventArray<_> = map.try_into()?; + + let logger = Arc::new(logger); for cpu_id in online_cpus().map_err(Error::InvalidOnlineCpu)? { let mut buf = logs.open(cpu_id, None)?; @@ -134,8 +178,7 @@ impl EbpfLogger { } }); } - - Ok(EbpfLogger {}) + Ok(()) } } @@ -374,6 +417,12 @@ pub enum Error { #[error("invalid /sys/devices/system/cpu/online format")] InvalidOnlineCpu(#[source] io::Error), + + #[error("program not found")] + ProgramNotFound, + + #[error(transparent)] + ProgramError(#[from] ProgramError), } fn log_buf(mut buf: &[u8], logger: &dyn Log) -> Result<(), ()> { From 60abea54cebe1104ee80c52b314180973bedb15b Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Wed, 24 Apr 2024 13:24:16 +1000 Subject: [PATCH 2/3] chore(aya-log): bless API --- xtask/public-api/aya-log.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xtask/public-api/aya-log.txt b/xtask/public-api/aya-log.txt index 843f436b..8c04980e 100644 --- a/xtask/public-api/aya-log.txt +++ b/xtask/public-api/aya-log.txt @@ -4,10 +4,14 @@ pub aya_log::Error::InvalidOnlineCpu(std::io::error::Error) pub aya_log::Error::MapError(aya::maps::MapError) pub aya_log::Error::MapNotFound pub aya_log::Error::PerfBufferError(aya::maps::perf::perf_buffer::PerfBufferError) +pub aya_log::Error::ProgramError(aya::programs::ProgramError) +pub aya_log::Error::ProgramNotFound impl core::convert::From for aya_log::Error pub fn aya_log::Error::from(source: aya::maps::MapError) -> Self impl core::convert::From for aya_log::Error pub fn aya_log::Error::from(source: aya::maps::perf::perf_buffer::PerfBufferError) -> Self +impl core::convert::From for aya_log::Error +pub fn aya_log::Error::from(source: aya::programs::ProgramError) -> Self impl core::error::Error for aya_log::Error pub fn aya_log::Error::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> impl core::fmt::Debug for aya_log::Error @@ -66,6 +70,8 @@ pub fn aya_log::DefaultFormatter::from(t: T) -> T pub struct aya_log::EbpfLogger impl aya_log::EbpfLogger pub fn aya_log::EbpfLogger::init(bpf: &mut aya::bpf::Ebpf) -> core::result::Result +pub fn aya_log::EbpfLogger::init_from_id(program_id: u32) -> core::result::Result +pub fn aya_log::EbpfLogger::init_from_id_with_logger(program_id: u32, logger: T) -> core::result::Result pub fn aya_log::EbpfLogger::init_with_logger(bpf: &mut aya::bpf::Ebpf, logger: T) -> core::result::Result impl core::marker::Freeze for aya_log::EbpfLogger impl core::marker::Send for aya_log::EbpfLogger From 8830c0bc20c6e3dbbddf63533d4623fcd45dd9af Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Wed, 24 Apr 2024 13:34:48 +1000 Subject: [PATCH 3/3] docs(aya-log): reword rustdocs a bit --- aya-log/src/lib.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index 3dd5b171..8c89c115 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -119,20 +119,18 @@ impl EbpfLogger { Ok(EbpfLogger {}) } - /// Attaches to an existing `aya-log-ebpf` log created by a running ebpf - /// program identified by `program_id`. The log records will be written - /// to the default logger. See [log::logger]. - /// It can be used to review the log for a pinned program after the user - /// application exits. + /// Attaches to an existing `aya-log-ebpf` instance. + /// + /// Attaches to the logs produced by `program_id`. Can be used to read logs generated by a + /// pinned program. The log records will be written to the default logger. See [log::logger]. pub fn init_from_id(program_id: u32) -> Result { Self::init_from_id_with_logger(program_id, log::logger()) } - /// Attaches to an existing `aya-log-ebpf` log created by a running ebpf - /// program identified by `program_id`. The log records will be written - /// to the user provided logger. - /// It can be used to review the log for a pinned program after the user - /// application exits. + /// Attaches to an existing `aya-log-ebpf` instance and logs with the given logger. + /// + /// Attaches to the logs produced by `program_id`. Can be used to read logs generated by a + /// pinned program. The log records will be written to the given logger. pub fn init_from_id_with_logger( program_id: u32, logger: T,