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