Tìm Hiểu Cơ Bản Về eBPF Trong Linux Kernel

eBPF: Cơ Chế Lập Trình Nội Kernel Động

eBPF (Extended Berkeley Packet Filter) là công nghệ cho phép chạy mã tùy chỉnh trong không gian nhân Linux mà không cần thay đổi mã nguồn nhân hay nạp module. Khởi nguồn từ BPF truyền thống (cBPF) ra đời năm 1992 cho bộ lọc gói tin, eBPF đã phát triển thành nền tảng đa dụng xử lý theo dõi hiệu năng, bảo mật và mạng.

Đặc điểm kỹ thuật nổi bật

  • Đảm bảo tính ổn định: Giới hạn vòng lặp và đường dẫn thực thi, đảm bảo kết thúc trong thời gian xác định
  • Tối ưu hiệu năng: Sử dụng JIT (Just-In-Time) để biên dịch thành mã máy bản địa
  • Cơ chế xác thực nghiêm ngặt: Trình xác thực kiểm tra toàn bộ mã trước khi nạp vào nhân
  • Khả năng cập nhật nóng: Thay thế chương trình mà không cần khởi động lại hệ thống

Khác biệt quan trọng so với module nhân:

  • eBPF chỉ truy cập được hàm hỗ trợ được định nghĩa trước, trong khi module nhân có toàn quyền truy cập
  • Chương trình eBPF phải qua xác thực để ngăn sự cố gây treo hệ thống
  • Map eBPF cung cấp cơ chế chia sẻ dữ liệu hiệu quả giữa không gian người dùng và nhân

Nguyên lý hoạt động

eBPF vận hành dựa trên mô hình sự kiện thông qua các điểm móc (hook points) trong nhân:

  1. Điểm móc tĩnh: Socket mạng, tracepoint, đánh dấu người dùng (USDT)
  2. Điểm móc động: kprobe (theo dõi hàm nhân), uprobe (theo dõi ứng dụng người dùng)
  3. Sự kiện hiệu năng: Perf_events cho thu thập mẫu

Quy trình thực thi điển hình:

  1. Viết mã eBPF bằng C hoặc assembly (thường dùng C)
  2. Biên dịch thành bytecode qua LLVM
  3. Nạp vào nhân qua syscall sys_bpf()
  4. Nhân xác thực và JIT bytecode thành mã máy
  5. Gắn chương trình vào điểm móc tương ứng
  6. Kích hoạt khi sự kiện diễn ra, trao đổi dữ liệu qua map hoặc perf_events

Triển khai thực tế: Theo dõi sự kiện mở file

Sử dụng BCC (BPF Compiler Collection) để tạo công cụ theo dõi hàm vfs_open:

// kernel_probe.c
int greet_kernel(void *ctx) {
    char message[] = "File duoc mo tu kernel!";
    bpf_trace_printk(message, sizeof(message));
    return 0;
}

Chương trình người dùng bằng Python:

#!/usr/bin/env python3
from bcc import BPF

# Tải và biên dịch mã eBPF
bpf_program = BPF(src_file="kernel_probe.c")

# Gắn vào điểm theo dõi vfs_open
bpf_program.attach_kprobe(event="vfs_open", fn_name="greet_kernel")

# Đọc luồng debug
print("Theo dõi su kien mo file...")
try:
    bpf_program.trace_print()
except KeyboardInterrupt:
    exit()

Khi thực thi với quyền root, đầu ra hiển thị:

      chrome-12345 [002] ...1 123456.789012: bpf_trace_printk: File duoc mo tu kernel!
        bash-67890 [001] ...1 123456.790123: bpf_trace_printk: File duoc mo tu kernel!

Cấu trúc đầu ra bao gồm: tên tiến trình, PID, CPU core, dấu thời gian và thông báo theo dõi. Cơ chế này có chi phí thấp hơn đáng kể so với công cụ truyền thống như strace nhờ xử lý trực tiếp trong nhân.

Thẻ: eBPF BCC linux-kernel kprobe JIT

Đăng vào ngày 23 tháng 6 lúc 09:18