Alessandro Decina 3 سال پیش
والد
کامیت
11e21e83be

+ 3 - 2
aya/src/bpf.rs

@@ -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}")]

+ 8 - 11
aya/src/lib.rs

@@ -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]

+ 12 - 12
aya/src/maps/array/array.rs

@@ -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)?;

+ 4 - 4
aya/src/maps/hash_map/hash_map.rs

@@ -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")]

+ 25 - 20
aya/src/maps/mod.rs

@@ -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,

+ 4 - 4
aya/src/maps/sock/sock_map.rs

@@ -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>> {

+ 1 - 0
aya/src/obj/btf/btf.rs

@@ -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}")]

+ 31 - 27
aya/src/programs/cgroup_skb.rs

@@ -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,
 }

+ 13 - 14
aya/src/programs/kprobe.rs

@@ -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}`")]

+ 43 - 24
aya/src/programs/mod.rs

@@ -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>>,

+ 4 - 0
aya/src/programs/probe.rs

@@ -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,
 }
 

+ 42 - 6
aya/src/programs/sk_msg.rs

@@ -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,

+ 22 - 6
aya/src/programs/sk_skb.rs

@@ -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,

+ 31 - 1
aya/src/programs/sock_ops.rs

@@ -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();

+ 45 - 2
aya/src/programs/socket_filter.rs

@@ -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(

+ 37 - 0
aya/src/programs/trace_point.rs

@@ -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)| {

+ 5 - 0
aya/src/programs/uprobe.rs

@@ -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,

+ 19 - 14
aya/src/programs/xdp.rs

@@ -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()?;
 

+ 13 - 10
aya/src/util.rs

@@ -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`.