Full code for the example in this chapter is available
here.
What are the probes in eBPF?
The probe BPF programs attach to kernel (kprobes) or user-side (uprobes)
functions and are able to access the function parameters of those functions.
You can find more information about probes in the
kernel documentation, including the difference between kprobes
and kretprobes.
Example project
To illustrate kprobes with Aya, let's write a program which
attaches a eBPF handler to the tcp_connect function and allows
printing the source and destination IP addresses from the socket parameter.
Design
For this demo program, we are going to rely on aya-log to print IP addresses
from the BPF program and not going to have any custom BPF maps (besides those
created by aya-log).
eBPF code
From the tcp_connect signature, we see that struct sock *sk is the only
function parameter. We will access it from the ProbeContext ctx handle.
We call bpf_probe_read_kernel helper to copy the
struct sock_common __sk_common portion of the socket structure. (For uprobe
programs, we would need to call bpf_probe_read_user instead.)
We match the skc_family field, and for AF_INET (IPv4) and AF_INET6
(IPv6) values, extract and print the src and destination addresses using
aya-log info! macro.
useaya::{include_bytes_aligned,programs::KProbe,Ebpf};useaya_log::EbpfLogger;useclap::Parser;uselog::{info,warn};usetokio::signal;#[derive(Debug, Parser)]structOpt{}#[tokio::main]asyncfnmain()-> Result<(),anyhow::Error>{let_opt=Opt::parse();env_logger::init();// This will include your eBPF object file as raw bytes at compile-time and load it at// runtime. This approach is recommended for most real-world use cases. If you would// like to specify the eBPF program at runtime rather than at compile-time, you can// reach for `Ebpf::load_file` instead.#[cfg(debug_assertions)]letmutbpf=Ebpf::load(include_bytes_aligned!("../../target/bpfel-unknown-none/debug/kprobetcp"))?;#[cfg(not(debug_assertions))]letmutbpf=Ebpf::load(include_bytes_aligned!("../../target/bpfel-unknown-none/release/kprobetcp"))?;ifletErr(e)=EbpfLogger::init(&mutbpf){// This can happen if you remove all log statements from your eBPF program.warn!("failed to initialize eBPF logger: {e}");}letprogram: &mutKProbe=bpf.program_mut("kprobetcp").unwrap().try_into()?;program.load()?;program.attach("tcp_connect",0)?;info!("Waiting for Ctrl-C...");signal::ctrl_c().await?;info!("Exiting...");Ok(())}
Running the program
$ RUST_LOG=info cargo xtask run --release
[2022-12-28T20:50:00Z INFO kprobetcp] Waiting for Ctrl-C...[2022-12-28T20:50:05Z INFO kprobetcp] AF_INET6 src addr: 2001:4998:efeb:282::249, dest addr: 2606:2800:220:1:248:1893:25c8:1946[2022-12-28T20:50:11Z INFO kprobetcp] AF_INET src address: 10.53.149.148, dest address: 10.87.116.72[2022-12-28T20:50:30Z INFO kprobetcp] AF_INET src address: 10.53.149.148, dest address: 98.138.219.201