use std::{ffi::CStr, os::raw, ptr, time::Duration};
use bpf_rs_macros::Display;
#[cfg(feature = "serde")]
use bpf_rs_macros::SerializeFromDisplay;
use crate::{BpfHelper, Error, StaticName};
use libbpf_sys::{libbpf_probe_bpf_helper, libbpf_probe_bpf_prog_type};
use num_enum::{IntoPrimitive, TryFromPrimitive};
#[non_exhaustive]
#[repr(u32)]
#[derive(Debug, Display, TryFromPrimitive, IntoPrimitive, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(SerializeFromDisplay))]
pub enum ProgramType {
Unspec = 0,
SocketFilter,
Kprobe,
SchedCls,
SchedAct,
Tracepoint,
Xdp,
PerfEvent,
CgroupSkb,
CgroupSock,
LwtIn,
LwtOut,
LwtXmit,
SockOps,
SkSkb,
CgroupDevice,
SkMsg,
RawTracepoint,
CgroupSockAddr,
LwtSeg6local,
LircMode2,
SkReuseport,
FlowDissector,
CgroupSysctl,
RawTracepointWritable,
CgroupSockopt,
Tracing,
StructOps,
Ext,
Lsm,
SkLookup,
Syscall,
}
impl ProgramType {
pub fn probe(&self) -> Result<bool, Error> {
match unsafe { libbpf_probe_bpf_prog_type((*self).into(), ptr::null()) } {
negative if negative < 0 => Err(Error::Code(negative)),
0 => Ok(false),
1 => Ok(true),
positive if positive > 1 => Err(Error::Unknown(positive)),
_ => unreachable!(),
}
}
pub fn probe_helper(&self, helper: BpfHelper) -> Result<bool, Error> {
match unsafe { libbpf_probe_bpf_helper((*self).into(), helper.into(), ptr::null()) } {
negative if negative < 0 => Err(Error::Code(negative)),
0 => Ok(false),
1 => Ok(true),
positive if positive > 1 => Err(Error::Unknown(positive)),
_ => unreachable!(),
}
}
pub fn iter() -> impl Iterator<Item = ProgramType> {
ProgramTypeIter(1)
}
}
impl StaticName for ProgramType {
fn name(&self) -> &'static str {
match *self {
ProgramType::Unspec => "unspec",
ProgramType::SocketFilter => "socket_filter",
ProgramType::Kprobe => "kprobe",
ProgramType::SchedCls => "sched_cls",
ProgramType::SchedAct => "sched_act",
ProgramType::Tracepoint => "tracepoint",
ProgramType::Xdp => "xdp",
ProgramType::PerfEvent => "perf_event",
ProgramType::CgroupSkb => "cgroup_skb",
ProgramType::CgroupSock => "cgroup_sock",
ProgramType::LwtIn => "lwt_in",
ProgramType::LwtOut => "lwt_out",
ProgramType::LwtXmit => "lwt_xmit",
ProgramType::SockOps => "sock_ops",
ProgramType::SkSkb => "sk_skb",
ProgramType::CgroupDevice => "cgroup_device",
ProgramType::SkMsg => "sk_msg",
ProgramType::RawTracepoint => "raw_tracepoint",
ProgramType::CgroupSockAddr => "cgroup_sock_addr",
ProgramType::LwtSeg6local => "lwt_seg6local",
ProgramType::LircMode2 => "lirc_mode2",
ProgramType::SkReuseport => "sk_reuseport",
ProgramType::FlowDissector => "flow_dissector",
ProgramType::CgroupSysctl => "cgroup_sysctl",
ProgramType::RawTracepointWritable => "raw_tracepoint_writable",
ProgramType::CgroupSockopt => "cgroup_sockopt",
ProgramType::Tracing => "tracing",
ProgramType::StructOps => "struct_ops",
ProgramType::Ext => "ext",
ProgramType::Lsm => "lsm",
ProgramType::SkLookup => "sk_lookup",
ProgramType::Syscall => "syscall",
}
}
}
struct ProgramTypeIter(u32);
impl Iterator for ProgramTypeIter {
type Item = ProgramType;
fn next(&mut self) -> Option<Self::Item> {
let next = self.0;
if next > ProgramType::Syscall.into() {
None
} else {
self.0 += 1;
ProgramType::try_from_primitive(next).ok()
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct ProgramInfo {
pub name: String,
pub ty: ProgramType,
pub tag: [u8; 8],
pub id: u32,
pub jited_prog_len: u32,
pub xlated_prog_len: u32,
pub jited_prog_insns: u64,
pub xlated_prog_insns: u64,
pub load_time: Duration,
pub created_by_uid: u32,
pub nr_map_ids: u32,
pub map_ids: u64,
pub ifindex: u32,
pub gpl_compatible: bool,
pub netns_dev: u64,
pub netns_ino: u64,
pub nr_jited_ksyms: u32,
pub nr_jited_func_lens: u32,
pub jited_ksyms: u64,
pub jited_func_lens: u64,
pub btf_id: u32,
pub func_info_rec_size: u32,
pub func_info: u64,
pub nr_func_info: u32,
pub nr_line_info: u32,
pub line_info: u64,
pub jited_line_info: u64,
pub nr_jited_line_info: u32,
pub line_info_rec_size: u32,
pub jited_line_info_rec_size: u32,
pub nr_prog_tags: u32,
pub prog_tags: u64,
pub run_time_ns: u64,
pub run_cnt: u64,
}
#[non_exhaustive]
pub enum ProgramLicense {
GPL,
}
impl ProgramLicense {
pub fn as_str_with_nul(&self) -> &'static str {
match *self {
ProgramLicense::GPL => "GPL\0",
}
}
pub fn as_ptr(&self) -> *const raw::c_char {
CStr::from_bytes_with_nul(self.as_str_with_nul().as_bytes())
.unwrap()
.as_ptr()
}
}