add methods to help the loaded_programs() API

Add helper methods to get useful information from the ProgramInfo
object which is returned by the `loaded_programs()` API.  Specifically
this code mirrors the bpftool program in terms of useful fields.

The methods here are not exhaustive and may expand in the future.

Signed-off-by: Andrew Stoycos <astoycos@redhat.com>
reviewable/pr637/r13
Andrew Stoycos 2 years ago
parent 58fa703a33
commit 4b892e1a4b
No known key found for this signature in database
GPG Key ID: 66735B92BB71C096

@ -71,6 +71,7 @@ use std::{
io,
os::unix::io::{AsRawFd, RawFd},
path::{Path, PathBuf},
time::{Duration, SystemTime},
};
use thiserror::Error;
@ -108,6 +109,7 @@ use crate::{
maps::MapError,
obj::{self, btf::BtfError, Function},
pin::PinError,
programs::utils::{boot_time, get_fdinfo},
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,
@ -937,16 +939,88 @@ impl ProgramInfo {
unsafe { std::slice::from_raw_parts(self.0.name.as_ptr() as *const _, length) }
}
/// The name of the program as a &str. If the name was not valid unicode, None is returned
/// The name of the program as a &str. If the name was not valid unicode, None is returned.
pub fn name_as_str(&self) -> Option<&str> {
std::str::from_utf8(self.name()).ok()
}
/// The program id for this program. Each program has a unique id.
/// The id for this program. Each program has a unique id.
pub fn id(&self) -> u32 {
self.0.id
}
/// The program tag is a SHA sum of the program's instructions which be used as an alternative to
/// [`Self::id()`]". A program's id can vary every time it's loaded or unloaded, but the tag
/// will remain the same.
pub fn tag(&self) -> u64 {
u64::from_be_bytes(self.0.tag)
}
/// The program type as defined by the linux kernel enum
/// [`bpf_prog_type`](https://elixir.bootlin.com/linux/v6.4.4/source/include/uapi/linux/bpf.h#L948).
pub fn program_type(&self) -> u32 {
self.0.type_
}
/// Returns true if the program is defined with a GPL-compatible license.
pub fn gpl_compatible(&self) -> bool {
self.0.gpl_compatible() != 0
}
/// Returns the ids of the maps maps used by the program.
pub fn map_ids(&self) -> Result<Vec<u32>, ProgramError> {
let fd = self.fd()?;
let map_ids = vec![0u32; self.0.nr_map_ids as usize];
bpf_prog_get_info_by_fd(fd, &map_ids).map_err(|io_error| ProgramError::SyscallError {
call: "bpf_prog_get_info_by_fd",
io_error,
})?;
unsafe { libc::close(fd) };
Ok(map_ids)
}
/// The btf id for the program.
pub fn btf_id(&self) -> u32 {
self.0.btf_id
}
/// The size in bytes of the program's translated eBPF bytecode.
pub fn bytes_xlated(&self) -> u32 {
self.0.xlated_prog_len
}
/// The size in bytes of the program's JIT-compiled machine code.
pub fn bytes_jited(&self) -> u32 {
self.0.jited_prog_len
}
/// How much memory in bytes has been allocated and locked for the program.
pub fn bytes_memlock(&self) -> Result<u32, ProgramError> {
let fd = self.fd()?;
let mem = get_fdinfo(fd, "memlock");
unsafe { libc::close(fd) };
mem
}
/// The number of verified instructions in the program.
pub fn verified_insns(&self) -> u32 {
self.0.verified_insns
}
/// The time the program was loaded.
///
/// The load time is specified by the kernel as nanoseconds since system boot,
/// this function converts that u64 value to a [`std::time::SystemTime`]
/// for easy consumption.
pub fn loaded_at(&self) -> SystemTime {
boot_time() + Duration::from_nanos(self.0.load_time)
}
/// Returns the fd associated with the program.
///
/// The returned fd must be closed when no longer needed.

@ -1,5 +1,13 @@
//! Common functions shared between multiple eBPF program types.
use std::{ffi::CStr, io, os::unix::io::RawFd, path::Path};
use std::{
ffi::CStr,
fs::File,
io,
io::{BufRead, BufReader},
os::unix::io::RawFd,
path::Path,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use crate::{
programs::{FdLink, Link, ProgramData, ProgramError},
@ -23,7 +31,7 @@ pub(crate) fn attach_raw_tracepoint<T: Link + From<FdLink>>(
program_data.links.insert(FdLink::new(pfd).into())
}
/// Find tracefs filesystem path
/// Find tracefs filesystem path.
pub(crate) fn find_tracefs_path() -> Result<&'static Path, ProgramError> {
lazy_static::lazy_static! {
static ref TRACE_FS: Option<&'static Path> = {
@ -51,3 +59,44 @@ pub(crate) fn find_tracefs_path() -> Result<&'static Path, ProgramError> {
.as_deref()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "tracefs not found").into())
}
/// Get the real (wall-clock) boot time.
pub(crate) fn boot_time() -> SystemTime {
let mut time = unsafe { std::mem::zeroed::<libc::timespec>() };
let ret = unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut time) };
assert_eq!(ret, 0, "failed to get system bootime");
let libc::timespec { tv_sec, tv_nsec } = time;
let dur_since_boot = Duration::new(tv_sec as u64, tv_nsec as u32);
let ret = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut time) };
assert_eq!(ret, 0, "failed to get system realtime");
let libc::timespec { tv_sec, tv_nsec } = time;
let dur_since_epoch = Duration::new(tv_sec as u64, tv_nsec as u32);
UNIX_EPOCH + (dur_since_epoch - dur_since_boot)
}
/// Get the specified information from a file descriptor's fdinfo.
pub(crate) fn get_fdinfo(fd: RawFd, key: &str) -> Result<u32, ProgramError> {
let info = File::open(format!("/proc/self/fdinfo/{}", fd))?;
let reader = BufReader::new(info);
for line in reader.lines() {
match line {
Ok(l) => {
if !l.contains(key) {
continue;
}
let (_key, val) = l.rsplit_once('\t').unwrap();
return Ok(val.parse().unwrap());
}
Err(e) => return Err(ProgramError::IOError(e)),
}
}
Ok(0)
}

Loading…
Cancel
Save