More docs

pull/1/head
Alessandro Decina 3 years ago
parent 6c7df27bd0
commit 11e21e83be

@ -213,7 +213,7 @@ impl Bpf {
/// Returns a reference to the map with the given name.
///
/// The returned type is mostly opaque. In order to do anything useful with it you need to
/// convert it to a [concrete map type](crate::maps).
/// convert it to a [typed map](crate::maps).
///
/// For more details and examples on maps and their usage, see the [maps module
/// documentation][crate::maps].
@ -238,7 +238,7 @@ impl Bpf {
/// Returns a mutable reference to the map with the given name.
///
/// The returned type is mostly opaque. In order to do anything useful with it you need to
/// convert it to a [concrete map type](crate::maps).
/// convert it to a [typed map](crate::maps).
///
/// For more details and examples on maps and their usage, see the [maps module
/// documentation][crate::maps].
@ -361,6 +361,7 @@ impl Bpf {
}
}
/// The error type returned by [`Bpf::load_file`] and [`Bpf::load`].
#[derive(Debug, Error)]
pub enum BpfError {
#[error("error loading {path}")]

@ -10,28 +10,25 @@
//! crate to execute syscalls. With BTF support and when linked with musl, it offers a true
//! [compile once, run everywhere
//! solution](https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html),
//! where one self-contained binary can be deployed on many linux distributions
//! where a single self-contained binary can be deployed on many linux distributions
//! and kernel versions.
//!
//! Some of the major features provided include:
//!
//! * Support for the BPF Type Format (BTF), which is transparently enabled when
//! * Support for the **BPF Type Format** (BTF), which is transparently enabled when
//! supported by the target kernel. This allows eBPF programs compiled against
//! one kernel version to run on different kernel versions without the need to
//! recompile.
//! * Support for global data maps, which allows eBPF programs to make use of global data and
//! variables. This is especially useful when the eBPF code itself is written in Rust, and makes
//! use of byte literals and other initializers that get place in global data sections.
//! * Support for function calls, so eBPF programs can call other functions and are not
//! forced to inline everything.
//! * Async support with both [tokio](https://docs.rs/tokio) and [async-std](https://docs.rs/async-std).
//! * Support for function call relocation and global data maps, which
//! allows eBPF programs to make **function calls** and use **global variables
//! and initializers**.
//! * **Async support** with both [tokio] and [async-std].
//! * Easy to deploy and fast to build: aya doesn't require a kernel build or
//! compiled headers, and not even a C toolchain; a release build completes in a matter
//! of seconds.
//!
//! # Minimum kernel version
//!
//! Aya currently supports kernels version 5.4 (latest LTS) and newer.
//! [tokio]: https://docs.rs/tokio
//! [async-std]: https://docs.rs/async-std
#![deny(clippy::all)]
#[macro_use]

@ -16,6 +16,18 @@ use crate::{
///
/// The size of the array is defined on the eBPF side using the `bpf_map_def::max_entries` field.
/// All the entries are zero-initialized when the map is created.
///
/// # Example
/// ```no_run
/// # let bpf = aya::Bpf::load(&[], None)?;
/// use aya::maps::Array;
/// use std::convert::TryFrom;
///
/// let mut array = Array::try_from(bpf.map_mut("ARRAY")?)?;
/// array.set(1, 42, 0)?;
/// assert_eq!(array.get(&1, 0)?, 42);
/// # Ok::<(), aya::BpfError>(())
/// ```
pub struct Array<T: Deref<Target = Map>, V: Pod> {
inner: T,
_v: PhantomData<V>,
@ -98,18 +110,6 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Array<T, V> {
///
/// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
/// if `bpf_map_update_elem` fails.
///
/// # Example
/// ```no_run
/// # let bpf = aya::Bpf::load(&[], None)?;
/// use aya::maps::Array;
/// use std::convert::TryFrom;
///
/// let mut array = Array::try_from(bpf.map_mut("ARRAY")?)?;
/// array.set(1, 42, 0)?;
/// assert_eq!(array.get(&1, 0)?, 42);
/// # Ok::<(), aya::BpfError>(())
/// ```
pub fn set(&mut self, index: u32, value: V, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?;
self.check_bounds(index)?;

@ -13,8 +13,6 @@ use crate::{
/// A hash map that can be shared between eBPF programs and user space.
///
/// It is required that both keys and values implement the [`Pod`] trait.
///
/// # Example
///
/// ```no_run
@ -24,8 +22,10 @@ use crate::{
///
/// let mut redirect_ports = HashMap::try_from(bpf.map_mut("REDIRECT_PORTS")?)?;
///
/// redirect_ports.insert(80, 8080, 0 /* flags */);
/// redirect_ports.insert(443, 8443, 0 /* flags */);
/// // redirect port 80 to 8080
/// redirect_ports.insert(80, 8080, 0);
/// // redirect port 443 to 8443
/// redirect_ports.insert(443, 8443, 0);
/// # Ok::<(), aya::BpfError>(())
/// ```
#[doc(alias = "BPF_MAP_TYPE_HASH")]

@ -1,34 +1,37 @@
//! Data structures used to exchange data with eBPF programs.
//! Data structures used to setup and share data with eBPF programs.
//!
//! The eBPF platform provides data structures - maps in eBPF speak - that can be used by eBPF
//! programs and user-space to exchange data. When you call
//! [`Bpf::load_file`](crate::Bpf::load_file) or [`Bpf::load`](crate::Bpf::load), all the maps
//! defined in the eBPF code get initialized and can then be accessed using
//! [`Bpf::map`](crate::Bpf::map) and [`Bpf::map_mut`](crate::Bpf::map_mut).
//! The eBPF platform provides data structures - maps in eBPF speak - that are
//! used to setup and share data with eBPF programs. When you call
//! [`Bpf::load_file`](crate::Bpf::load_file) or
//! [`Bpf::load`](crate::Bpf::load), all the maps defined in the eBPF code get
//! initialized and can then be accessed using [`Bpf::map`](crate::Bpf::map) and
//! [`Bpf::map_mut`](crate::Bpf::map_mut).
//!
//! # Concrete map types
//! # Typed maps
//!
//! The eBPF platform provides many map types each supporting different operations.
//! The eBPF API includes many map types each supporting different operations.
//! [`Bpf::map`](crate::Bpf::map) and [`Bpf::map_mut`](crate::Bpf::map_mut) always return the
//! opaque [`MapRef`] and [`MapRefMut`] types respectively. Those two types can be converted to
//! *concrete map types* using the [`TryFrom`](std::convert::TryFrom) trait. For example:
//! *typed maps* using the [`TryFrom`](std::convert::TryFrom) trait. For example:
//!
//! ```no_run
//! # let bpf = aya::Bpf::load(&[], None)?;
//! use aya::maps::HashMap;
//! use std::convert::TryFrom;
//! # let mut bpf = aya::Bpf::load(&[], None)?;
//! use std::convert::{TryFrom, TryInto};
//! use aya::maps::SockMap;
//! use aya::programs::SkMsg;
//!
//! const CONFIG_KEY_NUM_RETRIES: u8 = 1;
//!
//! // HashMap::try_from() converts MapRefMut to HashMap. It will fail if CONFIG is not an eBPF
//! // hash map.
//! let mut hm = HashMap::try_from(bpf.map_mut("CONFIG")?)?;
//! hm.insert(CONFIG_KEY_NUM_RETRIES, 3, 0 /* flags */);
//! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?;
//! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet")?.try_into()?;
//! prog.load()?;
//! prog.attach(&intercept_egress)?;
//! # Ok::<(), aya::BpfError>(())
//! ```
//!
//! The code above uses `HashMap`, but all the concrete map types implement the
//! `TryFrom` trait.
//! # Maps and `Pod` values
//!
//! Many map operations copy data from kernel space to user space and vice
//! versa. Because of that, all map values must be plain old data and therefore
//! implement the [Pod] trait.
use std::{
convert::TryFrom, ffi::CString, io, marker::PhantomData, mem, ops::Deref, os::unix::io::RawFd,
ptr,
@ -118,6 +121,8 @@ pub enum MapError {
}
/// A generic handle to a BPF map.
///
/// You should never need to use this unless you're implementing a new map type.
#[derive(Debug)]
pub struct Map {
pub(crate) obj: obj::Map,

@ -28,12 +28,12 @@ use crate::{
/// # let mut bpf = aya::Bpf::load(&[], None)?;
/// use std::convert::{TryFrom, TryInto};
/// use aya::maps::SockMap;
/// use aya::programs::SkMsg;
/// use aya::programs::SkSkb;
///
/// let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?;
/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet")?.try_into()?;
/// let intercept_ingress = SockMap::try_from(bpf.map_mut("INTERCEPT_INGRESS")?)?;
/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet")?.try_into()?;
/// prog.load()?;
/// prog.attach(&intercept_egress)?;
/// prog.attach(&intercept_ingress)?;
/// # Ok::<(), aya::BpfError>(())
/// ```
pub struct SockMap<T: Deref<Target = Map>> {

@ -18,6 +18,7 @@ use crate::{
pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32;
pub(crate) const MAX_SPEC_LEN: usize = 64;
/// The error type returned when `BTF` operations fail.
#[derive(Error, Debug)]
pub enum BtfError {
#[error("error parsing {path}")]

@ -14,9 +14,36 @@ use super::FdLink;
/// A program used to inspect or filter network activity for a given cgroup.
///
/// [`CgroupSkb`] programs can be used to inspect or filter network activity
/// generated on all the sockets belonging to a given [cgroup].
/// generated on all the sockets belonging to a given [cgroup]. They can be
/// attached to both _ingress_ and _egress_.
///
/// [cgroup]: https://man7.org/linux/man-pages/man7/cgroups.7.html
///
/// # Example
///
/// ```no_run
/// # #[derive(thiserror::Error, Debug)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[], None)?;
/// use std::fs::File;
/// use std::convert::TryInto;
/// use aya::programs::{CgroupSkb, CgroupSkbAttachType};
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let egress: &mut CgroupSkb = bpf.program_mut("egress_filter")?.try_into()?;
/// egress.load()?;
/// egress.attach(file, CgroupSkbAttachType::Egress)?;
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug)]
pub struct CgroupSkb {
pub(crate) data: ProgramData,
@ -47,32 +74,6 @@ impl CgroupSkb {
}
/// Attaches the program to the given cgroup.
///
/// # Example
///
/// ```no_run
/// # #[derive(thiserror::Error, Debug)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[], None)?;
/// use std::fs::File;
/// use std::convert::TryInto;
/// use aya::programs::{CgroupSkb, CgroupSkbAttachType};
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let egress: &mut CgroupSkb = bpf.program_mut("egress_filter")?.try_into()?;
/// egress.load()?;
/// egress.attach(file, CgroupSkbAttachType::Egress)?;
/// # Ok::<(), Error>(())
/// ```
pub fn attach<T: AsRawFd>(
&mut self,
cgroup: T,
@ -110,8 +111,11 @@ impl CgroupSkb {
}
}
/// Defines where to attach a [`CgroupSkb`] program.
#[derive(Copy, Clone, Debug)]
pub enum CgroupSkbAttachType {
/// Attach to ingress.
Ingress,
/// Attach to egress.
Egress,
}

@ -19,6 +19,18 @@ use crate::{
///
/// - `kprobe`: get attached to the *start* of the target functions
/// - `kretprobe`: get attached to the *return address* of the target functions
///
/// # Example
///
/// ```no_run
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::KProbe};
/// use std::convert::TryInto;
///
/// let program: &mut KProbe = bpf.program_mut("intercept_wakeups")?.try_into()?;
/// program.attach("try_to_wake_up", 0, None)?;
/// # Ok::<(), aya::BpfError>(())
/// ```
#[derive(Debug)]
pub struct KProbe {
pub(crate) data: ProgramData,
@ -54,20 +66,6 @@ impl KProbe {
/// If the program is a `kprobe`, it is attached to the *start* address of the target function.
/// Conversely if the program is a `kretprobe`, it is attached to the return address of the
/// target function.
///
///
/// # Example
///
/// ```no_run
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::KProbe};
/// use std::convert::TryInto;
///
/// let program: &mut KProbe = bpf.program_mut("intercept_wakeups")?.try_into()?;
/// program.attach("try_to_wake_up", 0, None)?;
/// # Ok::<(), aya::BpfError>(())
/// ```
///
pub fn attach(
&mut self,
fn_name: &str,
@ -78,6 +76,7 @@ impl KProbe {
}
}
/// The type returned when attaching a [`KProbe`] fails.
#[derive(Debug, Error)]
pub enum KProbeError {
#[error("`{filename}`")]

@ -1,14 +1,17 @@
//! eBPF program types.
//!
//! eBPF programs are loaded inside the kernel and attached to one or more hook points. Whenever
//! the kernel or an application reaches those hook points, the programs are executed.
//! eBPF programs are loaded inside the kernel and attached to one or more hook
//! points. Whenever the hook points are reached, the programs are executed.
//!
//! # Loading programs
//! # Loading and attaching programs
//!
//! When you call [`Bpf::load_file`] or [`Bpf::load`], all the programs present in the code are
//! parsed and can be retrieved using the [`Bpf::program`] and [`Bpf::program_mut`] methods. In
//! order to load a program, you need to get a handle to it and call the `load()` method, for
//! example:
//! When you call [`Bpf::load_file`] or [`Bpf::load`], all the programs included
//! in the object code are parsed and relocated. Programs are not loaded
//! automatically though, since often you will need to do some application
//! specific setup before you can actually load them.
//!
//! In order to load and attach a program, you need to retrieve it using [`Bpf::program_mut`],
//! then call the `load()` and `attach()` methods, for example:
//!
//! ```no_run
//! use aya::{Bpf, programs::KProbe};
@ -18,32 +21,21 @@
//! // intercept_wakeups is the name of the program we want to load
//! let program: &mut KProbe = bpf.program_mut("intercept_wakeups")?.try_into()?;
//! program.load()?;
//! // intercept_wakeups will be called every time try_to_wake_up() is called
//! // inside the kernel
//! program.attach("try_to_wake_up", 0, None)?;
//! # Ok::<(), aya::BpfError>(())
//! ```
//!
//! # Attaching programs
//!
//! After being loaded, programs must be attached to their target hook points to be executed. The
//! eBPF platform supports many different program types, with each type providing different
//! attachment options. For example when attaching a [`KProbe`], you must provide the name of the
//! kernel function you want instrument; when loading an [`Xdp`] program, you need to specify the
//! network card name you want to hook into, and so forth.
//!
//! Currently aya supports [`KProbe`], [`UProbe`], [`SocketFilter`], [`TracePoint`] and [`Xdp`]
//! programs. To see how to attach them, see the documentation of the respective `attach()` method.
//!
//! # Interacting with programs
//!
//! eBPF programs are event-driven and execute when the hook points they are attached to are hit.
//! To communicate with user-space, programs use data structures provided by the eBPF platform,
//! which can be found in the [maps] module.
//! The signature of the `attach()` method varies depending on what kind of
//! program you're trying to attach.
//!
//! [`Bpf::load_file`]: crate::Bpf::load_file
//! [`Bpf::load`]: crate::Bpf::load
//! [`Bpf::programs`]: crate::Bpf::programs
//! [`Bpf::program`]: crate::Bpf::program
//! [`Bpf::program_mut`]: crate::Bpf::program_mut
//! [maps]: crate::maps
//! [`maps`]: crate::maps
mod cgroup_skb;
mod kprobe;
mod perf_attach;
@ -80,61 +72,83 @@ use crate::{
obj::{self, Function},
sys::{bpf_load_program, bpf_prog_detach},
};
/// Error type returned when working with programs.
#[derive(Debug, Error)]
pub enum ProgramError {
/// The program could not be found in the object code.
#[error("program `{name}` not found")]
NotFound { name: String },
/// The program is already loaded.
#[error("the program is already loaded")]
AlreadyLoaded,
/// The program is not loaded.
#[error("the program is not loaded")]
NotLoaded,
/// The program is already detached.
#[error("the program was already detached")]
AlreadyDetached,
/// The program is not attached.
#[error("the program is not attached")]
NotAttached,
/// Loading the program failed.
#[error("the BPF_PROG_LOAD syscall failed. Verifier output: {verifier_log}")]
LoadError {
/// The [`io::Error`] returned by the `BPF_PROG_LOAD` syscall.
#[source]
io_error: io::Error,
/// The error log produced by the kernel verifier.
verifier_log: String,
},
/// A syscall failed.
#[error("`{call}` failed")]
SyscallError {
/// The name of the syscall which failed.
call: String,
/// The [`io::Error`] returned by the syscall.
#[source]
io_error: io::Error,
},
/// The network interface does not exist.
#[error("unknown network interface {name}")]
UnknownInterface { name: String },
/// The program is not of the expected type.
#[error("unexpected program type")]
UnexpectedProgramType,
/// A map error occurred while loading or attaching a program.
#[error(transparent)]
MapError(#[from] MapError),
/// An error occurred while working with a [`KProbe`].
#[error(transparent)]
KProbeError(#[from] KProbeError),
/// An error occurred while working with an [`UProbe`].
#[error(transparent)]
UProbeError(#[from] UProbeError),
/// An error occurred while working with a [`TracePoint`].
#[error(transparent)]
TracePointError(#[from] TracePointError),
/// An error occurred while working with a [`SocketFilter`].
#[error(transparent)]
SocketFilterError(#[from] SocketFilterError),
/// An error occurred while working with an [`Xdp`] program.
#[error(transparent)]
XdpError(#[from] XdpError),
/// An error occurred while working with a TC program.
#[error(transparent)]
TcError(#[from] TcError),
}
@ -353,10 +367,15 @@ fn load_program(prog_type: bpf_prog_type, data: &mut ProgramData) -> Result<(),
Ok(())
}
/// Detach an attached program.
pub trait Link: std::fmt::Debug {
fn detach(&mut self) -> Result<(), ProgramError>;
}
/// The return type of `program.attach(...)`.
///
/// [`LinkRef`] implements the [`Link`] trait and can be used to detach a
/// program.
#[derive(Debug)]
pub struct LinkRef {
inner: Rc<RefCell<dyn Link>>,

@ -10,9 +10,13 @@ use crate::{
#[derive(Debug, Copy, Clone)]
pub enum ProbeKind {
/// Kernel probe
KProbe,
/// Kernel return probe
KRetProbe,
/// User space probe
UProbe,
/// User space return probe
URetProbe,
}

@ -5,14 +5,50 @@ use crate::{
sys::bpf_prog_attach,
};
/// A socket buffer program.
/// A program used to intercept messages sent with `sendmsg()`/`sendfile()`.
///
/// Socket buffer programs are attached to [sockmaps], and can be used to
/// redirect or drop packets. See the [`SockMap` documentation] for more info
/// and examples.
/// [`SkMsg`] programs are attached to [socket maps], and can be used inspect,
/// filter and redirect messages sent on sockets. See also [`SockMap`] and
/// [`SockHash`].
///
/// [sockmaps]: crate::maps::SockMap
/// [`SockMap` documentation]: crate::maps::SockMap
/// # Example
///
/// ```no_run
/// ##[derive(Debug, thiserror::Error)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[], None)?;
/// use std::convert::{TryFrom, TryInto};
/// use std::io::Write;
/// use std::net::TcpStream;
/// use std::os::unix::io::AsRawFd;
/// use aya::maps::SockHash;
/// use aya::programs::SkMsg;
///
/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?;
/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet")?.try_into()?;
/// prog.load()?;
/// prog.attach(&intercept_egress)?;
///
/// let mut client = TcpStream::connect("127.0.0.1:1234")?;
/// intercept_egress.insert(1234, client.as_raw_fd(), 0)?;
///
/// // the write will be intercepted
/// client.write_all(b"foo")?;
/// # Ok::<(), Error>(())
/// ```
///
/// [socket maps]: crate::maps::sock
/// [`SockMap`]: crate::maps::SockMap
/// [`SockHash`]: crate::maps::SockHash
#[derive(Debug)]
pub struct SkMsg {
pub(crate) data: ProgramData,

@ -8,21 +8,37 @@ use crate::{
sys::bpf_prog_attach,
};
/// The kind of [`SkSkb`] program.
#[derive(Copy, Clone, Debug)]
pub enum SkSkbKind {
StreamParser,
StreamVerdict,
}
/// A socket buffer program.
/// A program used to intercept ingress socket buffers.
///
/// Socket buffer programs are attached to [socket maps], and can be used to
/// inspect, redirect or filter packet. See [SockMap] and [SockHash] for more
/// info and examples.
/// [`SkSkb`] programs are attached to [socket maps], and can be used to
/// inspect, redirect or filter incoming packet. See also [`SockMap`] and
/// [`SockHash`].
///
/// # Example
///
/// ```no_run
/// # let mut bpf = aya::Bpf::load(&[], None)?;
/// use std::convert::{TryFrom, TryInto};
/// use aya::maps::SockMap;
/// use aya::programs::SkSkb;
///
/// let intercept_ingress = SockMap::try_from(bpf.map_mut("INTERCEPT_INGRESS")?)?;
/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet")?.try_into()?;
/// prog.load()?;
/// prog.attach(&intercept_ingress)?;
/// # Ok::<(), aya::BpfError>(())
/// ```
///
/// [socket maps]: crate::maps::sock
/// [SockMap]: crate::maps::SockMap
/// [SockHash]: crate::maps::SockHash
/// [`SockMap`]: crate::maps::SockMap
/// [`SockHash`]: crate::maps::SockHash
#[derive(Debug)]
pub struct SkSkb {
pub(crate) data: ProgramData,

@ -6,6 +6,36 @@ use crate::{
sys::bpf_prog_attach,
};
/// A program used to work with sockets.
///
/// [`SockOps`] programs can access or set socket options, connection
/// parameters, watch connection state changes and more. They are attached to
/// cgroups.
///
/// # Example
///
/// ```no_run
/// # #[derive(thiserror::Error, Debug)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[], None)?;
/// use std::fs::File;
/// use std::convert::TryInto;
/// use aya::programs::SockOps;
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let prog: &mut SockOps = bpf.program_mut("intercept_active_sockets")?.try_into()?;
/// prog.load()?;
/// prog.attach(file)?;
/// # Ok::<(), Error>(())
#[derive(Debug)]
pub struct SockOps {
pub(crate) data: ProgramData,
@ -24,7 +54,7 @@ impl SockOps {
self.data.name.to_string()
}
/// Attaches the program to the given sockmap.
/// Attaches the program to the given cgroup.
pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<LinkRef, ProgramError> {
let prog_fd = self.data.fd_or_err()?;
let cgroup_fd = cgroup.as_raw_fd();

@ -1,5 +1,8 @@
use libc::{setsockopt, SOL_SOCKET};
use std::{io, mem, os::unix::prelude::RawFd};
use std::{
io, mem,
os::unix::prelude::{AsRawFd, RawFd},
};
use thiserror::Error;
use crate::{
@ -7,8 +10,10 @@ use crate::{
programs::{load_program, Link, LinkRef, ProgramData, ProgramError},
};
/// The type returned when attaching a [`SocketFilter`] fails.
#[derive(Debug, Error)]
pub enum SocketFilterError {
/// Setting the `SO_ATTACH_BPF` socket option failed.
#[error("setsockopt SO_ATTACH_BPF failed")]
SoAttachBpfError {
#[source]
@ -16,18 +21,56 @@ pub enum SocketFilterError {
},
}
/// A program used to inspect and filter incoming packets on a socket.
///
/// [`SocketFilter`] programs are attached on sockets and can be used to inspect
/// and filter incoming packets.
///
///
/// # Example
///
/// ```no_run
/// ##[derive(Debug, thiserror::Error)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[], None)?;
/// use std::convert::{TryFrom, TryInto};
/// use std::io::Write;
/// use std::net::TcpStream;
/// use std::os::unix::io::AsRawFd;
/// use aya::programs::SocketFilter;
///
/// let mut client = TcpStream::connect("127.0.0.1:1234")?;
/// let prog: &mut SocketFilter = bpf.program_mut("filter_packets")?.try_into()?;
/// prog.load()?;
/// prog.attach(client.as_raw_fd())?;
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug)]
pub struct SocketFilter {
pub(crate) data: ProgramData,
}
impl SocketFilter {
/// Loads the program inside the kernel.
///
/// See also [`Program::load`](crate::programs::Program::load).
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SOCKET_FILTER, &mut self.data)
}
pub fn attach(&mut self, socket: RawFd) -> Result<LinkRef, ProgramError> {
/// Attaches the filter on the given socket.
pub fn attach<T: AsRawFd>(&mut self, socket: T) -> Result<LinkRef, ProgramError> {
let prog_fd = self.data.fd_or_err()?;
let socket = socket.as_raw_fd();
let ret = unsafe {
setsockopt(

@ -5,6 +5,7 @@ use crate::{generated::bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT, sys::perf_event_
use super::{load_program, perf_attach, LinkRef, ProgramData, ProgramError};
/// The type returned when attaching a [`TracePoint`] fails.
#[derive(Debug, Error)]
pub enum TracePointError {
#[error("`{filename}`")]
@ -15,16 +16,52 @@ pub enum TracePointError {
},
}
/// A program that can be attached at a pre-defined kernel trace point.
///
/// The kernel provides a set of pre-defined trace points that eBPF programs can
/// be attached to. See `/sys/kernel/debug/tracing/events` for a list of which
/// events can be traced.
///
/// # Example
///
/// ```no_run
/// ##[derive(Debug, thiserror::Error)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[], None)?;
/// use std::convert::{TryFrom, TryInto};
/// use aya::programs::TracePoint;
///
/// let prog: &mut TracePoint = bpf.program_mut("trace_context_switch")?.try_into()?;
/// prog.load()?;
/// prog.attach("sched", "sched_switch")?;
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug)]
pub struct TracePoint {
pub(crate) data: ProgramData,
}
impl TracePoint {
/// Loads the program inside the kernel.
///
/// See also [`Program::load`](crate::programs::Program::load).
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_TRACEPOINT, &mut self.data)
}
/// Attaches to a given trace point.
///
/// For a list of the available event categories and names, see
/// `/sys/kernel/debug/tracing/events`.
pub fn attach(&mut self, category: &str, name: &str) -> Result<LinkRef, ProgramError> {
let id = read_sys_fs_trace_point_id(category, name)?;
let fd = perf_event_open_trace_point(id).map_err(|(_code, io_error)| {

@ -127,17 +127,21 @@ impl UProbe {
}
}
/// The type returned when attaching an [`UProbe`] fails.
#[derive(Debug, Error)]
pub enum UProbeError {
/// There was an error parsing `/etc/ld.so.cache`.
#[error("error reading `{}` file", LD_SO_CACHE_FILE)]
InvalidLdSoCache {
#[source]
io_error: Arc<io::Error>,
},
/// The target program could not be found.
#[error("could not resolve uprobe target `{path}`")]
InvalidTarget { path: PathBuf },
/// There was an error resolving the target symbol.
#[error("error resolving symbol")]
SymbolError {
symbol: String,
@ -145,6 +149,7 @@ pub enum UProbeError {
error: Box<dyn Error + Send + Sync>,
},
/// There was an error accessing `filename`.
#[error("`{filename}`")]
FileError {
filename: String,

@ -12,6 +12,7 @@ use crate::{
sys::{bpf_link_create, kernel_version, netlink_set_xdp_fd},
};
/// The type returned when attaching an [`Xdp`] program fails on kernels `< 5.9`.
#[derive(Debug, Error)]
pub enum XdpError {
#[error("netlink error while attaching XDP program")]
@ -22,12 +23,18 @@ pub enum XdpError {
}
bitflags! {
/// Flags passed to [`Xdp::attach()`].
#[derive(Default)]
pub struct XdpFlags: u32 {
/// Skb mode.
const SKB_MODE = XDP_FLAGS_SKB_MODE;
/// Driver mode.
const DRV_MODE = XDP_FLAGS_DRV_MODE;
/// Hardware mode.
const HW_MODE = XDP_FLAGS_HW_MODE;
/// Replace a previously attached XDP program.
const REPLACE = XDP_FLAGS_REPLACE;
/// Only attach if there isn't another XDP program already attached.
const UPDATE_IF_NOEXIST = XDP_FLAGS_UPDATE_IF_NOEXIST;
}
}
@ -38,6 +45,18 @@ bitflags! {
/// processing, where they can apply custom packet processing logic. When supported by the
/// underlying network driver, XDP programs can execute directly on network cards, greatly
/// reducing CPU load.
///
/// # Example
///
/// ```no_run
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::{Xdp, XdpFlags}};
/// use std::convert::TryInto;
///
/// let program: &mut Xdp = bpf.program_mut("intercept_packets")?.try_into()?;
/// program.attach("eth0", XdpFlags::default())?;
/// # Ok::<(), aya::BpfError>(())
/// ```
#[derive(Debug)]
pub struct Xdp {
pub(crate) data: ProgramData,
@ -56,8 +75,6 @@ impl Xdp {
self.data.name.to_string()
}
/// Attaches the program.
///
/// Attaches the program to the given `interface`.
///
/// # Errors
@ -69,18 +86,6 @@ impl Xdp {
/// kernels `>= 5.9.0`, and instead
/// [`XdpError::NetlinkError`] is returned for older
/// kernels.
///
/// # Example
///
/// ```no_run
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::{Xdp, XdpFlags}};
/// use std::convert::TryInto;
///
/// let program: &mut Xdp = bpf.program_mut("intercept_packets")?.try_into()?;
/// program.attach("eth0", XdpFlags::default())?;
/// # Ok::<(), aya::BpfError>(())
/// ```
pub fn attach(&mut self, interface: &str, flags: XdpFlags) -> Result<LinkRef, ProgramError> {
let prog_fd = self.data.fd_or_err()?;

@ -1,16 +1,14 @@
//! Utility functions.
use std::{
collections::BTreeMap,
fs::{self, File},
ffi::CString,
os::raw::c_char,
fs::{self, File},
io::{self, BufReader},
os::raw::c_char,
str::FromStr,
};
use crate::{
generated::{TC_H_MAJ_MASK, TC_H_MIN_MASK},
};
use crate::generated::{TC_H_MAJ_MASK, TC_H_MIN_MASK};
use libc::if_nametoindex;
@ -19,7 +17,7 @@ use io::BufRead;
const ONLINE_CPUS: &str = "/sys/devices/system/cpu/online";
pub(crate) const POSSIBLE_CPUS: &str = "/sys/devices/system/cpu/possible";
/// Returns the numeric IDs of the available CPUs.
/// Returns the numeric IDs of the CPUs currently online.
pub fn online_cpus() -> Result<Vec<u32>, io::Error> {
let data = fs::read_to_string(ONLINE_CPUS)?;
parse_cpu_ranges(data.trim()).map_err(|_| {
@ -30,6 +28,9 @@ pub fn online_cpus() -> Result<Vec<u32>, io::Error> {
})
}
/// Get the number of possible cpus.
///
/// See `/sys/devices/system/cpu/possible`.
pub fn nr_cpus() -> Result<usize, io::Error> {
Ok(possible_cpus()?.len())
}
@ -38,6 +39,9 @@ pub(crate) fn tc_handler_make(major: u32, minor: u32) -> u32 {
(major & TC_H_MAJ_MASK) | (minor & TC_H_MIN_MASK)
}
/// Get the list of possible cpus.
///
/// See `/sys/devices/system/cpu/possible`.
pub(crate) fn possible_cpus() -> Result<Vec<u32>, io::Error> {
let data = fs::read_to_string(POSSIBLE_CPUS)?;
parse_cpu_ranges(data.trim()).map_err(|_| {
@ -75,20 +79,19 @@ pub unsafe fn ifindex_from_ifname(if_name: &str) -> Result<u32, io::Error> {
let c_if_name: *const c_char = c_str_if_name.as_ptr() as *const c_char;
// unsafe libc wrapper
let if_index = if_nametoindex(c_if_name);
if if_index == 0 {
if if_index == 0 {
return Err(io::Error::last_os_error());
}
Ok(if_index)
}
/// htons and ntohs util functions
pub fn htons(u: u16) -> u16 {
u.to_be()
u.to_be()
}
pub fn ntohs(u: u16) -> u16 {
u16::from_be(u)
u16::from_be(u)
}
/// Loads kernel symbols from `/proc/kallsyms`.

Loading…
Cancel
Save