Operations 12 min read

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.

Tencent Architect
Tencent Architect
Tencent Architect
Mastering eBPF: Install, Write Hello World, and Explore Advanced Examples

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:

<code>sudo yum install bcc kernel-headers-$(uname -r)</code>

If the above fails, use:

<code>sudo yum install bcc-tools</code>

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

<code>#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\n", dfd);
    bpf_trace_printk("Hello, World!:%s\n", filename);
    return 0;
}</code>

hello.py

<code>#!/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()</code>

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.c

implements 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:

<code>#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x
enum bpf_func_id {
    __BPF_FUNC_MAPPER(__BPF_ENUM_FN)
    __BPF_FUNC_MAX_ID,
};</code>

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

:

<code>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,
};</code>

During loading,

kernel/bpf/verifier.c

calls

fixup_bpf_calls

to replace the

func_id

immediate value with the actual function pointer offset:

<code>fn = env->ops->get_func_proto(insn->imm, env->prog);
insn->imm = fn->func - __bpf_call_base;</code>

When the kernel runs the eBPF program, the dispatcher executes the resolved function:

<code>BPF_R0 = (__bpf_call_base + insn->imm)(BPF_R1, BPF_R2, BPF_R3, BPF_R4, BPF_R5);</code>

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.

performance monitoringLinuxeBPFKernel TracingBCC
Tencent Architect
Written by

Tencent Architect

We share technical insights on storage, computing, and access, and explore industry-leading product technologies together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.