Mastering eBPF: Install, Write Hello World, and Explore Advanced Examples
This article guides you through installing BCC, creating simple and complex eBPF programs with C and Python, explains eBPF architecture, source‑code organization, and demonstrates real‑world tracing examples for kernel diagnostics and performance monitoring.
Introduction
eBPF is increasingly used for daily problem diagnosis and has become mature. It can locate kernel issues and optimize network performance, especially in scenarios where server restarts are not allowed. eBPF programs are write‑once and can be executed directly, offering high efficiency.
1. How to Write eBPF
1.1 BCC Tool Installation
Install the BCC tools on a Linux system with the following commands: sudo yum install bcc kernel-headers-$(uname -r) If the above fails, use: sudo yum install bcc-tools After installation, verify with bcc -v. For detailed instructions see the official install guide .
1.2 Hello World Program
eBPF programs consist of two parts: a kernel‑space C file and a user‑space Python loader.
Example files hello.c and hello.py:
hello.c
#include <uapi/linux/ptrace.h>
int hello_world(struct pt_regs *regs, int dfd, const char __user *filename, int flags, umode_t mode) {
bpf_trace_printk("Hello, World!:%d
", dfd);
bpf_trace_printk("Hello, World!:%s
", filename);
return 0;
}hello.py
#!/usr/bin/env python3
from bcc import BPF
# Load the eBPF C program
b = BPF(src_file="hello.c")
# Attach the program to the do_sys_open kprobe
b.attach_kprobe(event="do_sys_open", fn_name="hello_world")
# Print output from the kernel program
b.trace_print()Run the program with python3 hello.py to see the output.
1.3 Example Development
After installing BCC, the directory /usr/share/bcc/tools contains ready‑made eBPF tools that can be examined and modified.
Example 1: syncsnoop – Traces the sync system call using a kprobe. The left pane shows the C code loaded into the kernel, and the right pane shows the Python driver.
Example 2: vfscount – Demonstrates a Python loader that creates a hash table to count calls to VFS functions. The kernel part uses a tracepoint to record the data.
Example 3: hardirqs – Uses a tracepoint to monitor hardware interrupts, storing results in a hash table.
2. eBPF Limitations
3. eBPF Architecture
eBPF consists of a user‑space component and a kernel‑space component.
The user‑space part loads BPF bytecode into the kernel and reads statistics or event details returned from the kernel.
The kernel‑space bytecode runs inside the kernel, handling specific events and optionally sending results back to user space via maps or perf‑event mechanisms.
Interaction between user and kernel space is achieved through map structures, enabling bidirectional communication.
Typical workflow:
Compile the BPF program to bytecode using LLVM or GCC.
Load the bytecode into the kernel with a loader program.
The kernel verifier checks safety before execution.
Running BPF programs can return data via maps (for aggregated statistics) or perf‑events (for real‑time events).
4. eBPF Source Code
4.1 Directory Organization
User‑space loading
ELF parsing source: tkernel4/samples/bpf/ Libbpf provides helper functions such as bpf_load_program and ultimately invokes the __NR_bpf system call.
Kernel‑space
Source directory:
tkernel4/kernel/bpf/ syscall.cimplements the bpf() system call for loading and verification. core.c selects the runtime (interpreter or JIT). verifier.c contains bpf_check() for safety validation.
4.2 Source Code Analysis
The user‑space side includes eBPF tool functions and libraries, while the kernel side provides the eBPF runtime, kprobe mechanism, ftrace, and tracepoints.
Function IDs ( func_id) are defined in include/uapi/linux/bpf.h using the BPF_FUNC_* macros:
#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x
enum bpf_func_id {
__BPF_FUNC_MAPPER(__BPF_ENUM_FN)
__BPF_FUNC_MAX_ID,
};These IDs map to kernel implementations, e.g., BPF_FUNC_msg_redirect_hash. The kernel’s net/core/filter.c registers a verifier ops structure that resolves a func_id to a bpf_func_proto:
const struct bpf_verifier_ops sk_msg_verifier_ops = {
.get_func_proto = sk_msg_func_proto,
.is_valid_access = sk_msg_is_valid_access,
.convert_ctx_access = sk_msg_convert_ctx_access,
.gen_prologue = bpf_noop_prologue,
};During loading, kernel/bpf/verifier.c calls fixup_bpf_calls to replace the func_id immediate value with the actual function pointer offset:
fn = env->ops->get_func_proto(insn->imm, env->prog);
insn->imm = fn->func - __bpf_call_base;When the kernel runs the eBPF program, the dispatcher executes the resolved function:
BPF_R0 = (__bpf_call_base + insn->imm)(BPF_R1, BPF_R2, BPF_R3, BPF_R4, BPF_R5);This article shares eBPF tool installation methods, analyzes the composition of user‑space tool core files, and explains the kernel’s support mechanisms for eBPF.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent Architect
We share technical insights on storage, computing, and access, and explore industry-leading product technologies together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
