Blog
Thoughts on engineering, design, and building great products.
XDP: Xử Lý Gói Ở Điểm Sớm Nhất, Viết Một Firewall
XDP gắn chương trình eBPF vào driver mạng, chạy trên mỗi gói tới trước cả khi nhân cấp phát sk_buff — điểm sớm nhất có thể đụng vào một gói. Nó trả về một verdict: PASS, DROP, TX, REDIRECT. Bài này dựng một XDP firewall nhỏ drop ICMP trên một interface thật, gắn vào card mạng của node bằng bptool, rồi xem ping rớt từ 0% lên 100% loss trong khi SSH vẫn sống — và thấy nó nằm trước datapath tc của Cilium trên cùng interface ra sao.
libbpf và CO-RE: Tự Viết Một Công Cụ eBPF
bpftrace hợp cho câu hỏi nhanh. Khi cần một công cụ thật — đóng gói, phân phối, chạy lâu dài — ta viết chương trình eBPF bằng C với libbpf và CO-RE. Bài này dựng execsnoop từ đầu: chương trình nhân đẩy sự kiện exec qua ring buffer, bpftool sinh skeleton, một loader C dùng libbpf nạp và đọc sự kiện. Build đủ chuỗi clang → skeleton → link libbpf, rồi chạy thấy từng lần exec trên cụm hiện ra với pid, ppid, tên file — kèm một cái bẫy buffer thật.
uprobe, USDT và Soi Pod Từ Host
Tới giờ ta gắn vào nhân. eBPF còn với được vào userspace: uprobe gắn vào hàm của một chương trình hay thư viện thường, USDT gắn vào điểm tracepoint mà ứng dụng cài sẵn. Bài này trace hàm getaddrinfo trong libc để thấy chương trình nào đang phân giải tên miền gì, rồi dùng đúng kỹ thuật đó soi một pod thật trên cụm từ phía host — thấy nó gọi syscall gì mà không cần đụng vào pod. Đây là lý do eBPF thành nền quan sát cho Kubernetes.
bpftrace: Maps, Đếm và Histogram
In từng dòng ngập màn hình khi sự kiện dày. Sức mạnh thật của bpftrace là gộp dữ liệu ngay trong nhân: đếm theo khóa, lập biểu đồ phân phối, rồi chỉ trả về bản tóm tắt nhỏ. Bài này dùng map @ của bpftrace để đếm syscall theo tiến trình, rồi dựng một histogram độ trễ vfs_read thật bằng cặp kprobe/kretprobe — thấy phân phối với cột ASCII, gồm cả cái đuôi chậm mà số trung bình sẽ giấu mất.
bpftrace: Viết Tracing Trong Một Dòng
Part I tự viết chương trình eBPF bằng C, clang, bpftool — nhiều bước cho một câu hỏi đơn giản như 'tiến trình nào đang mở file nào'. bpftrace là đường tắt: một dòng lệnh trả lời ngay, không C không clang. Nhưng bên dưới vẫn là eBPF — bài này chứng minh điều đó (bpftool thấy chương trình bpftrace nạp vào rồi biến mất), rồi đi qua cú pháp probe/filter/action, kho 122 nghìn probe gắn được, và các biến dựng sẵn, qua các one-liner chạy thật trên cụm.
BTF và CO-RE: Một Lần Biên Dịch, Chạy Mọi Kernel
Cấu trúc dữ liệu bên trong nhân như task_struct có layout khác nhau giữa các phiên bản kernel — field nằm ở offset nào tùy bản. Vậy làm sao một chương trình eBPF biên dịch sẵn đọc đúng field trên mọi kernel? Câu trả lời là BTF và CO-RE. Bài cuối Part I sinh vmlinux.h từ BTF của nhân, viết một chương trình đọc ppid bằng cách lần qua task->real_parent->tgid, biên dịch một lần và chạy — libbpf tự tìm offset đúng theo BTF của kernel đang chạy. Đây cũng là nền cho Part III tự viết công cụ thật.
Program Type và Hook: Gắn Vào Đâu, Thấy Được Gì
Một chương trình eBPF không chạy lơ lửng — nó gắn vào một hook trong nhân, và loại hook đó quyết định ba thứ: chương trình chạy lúc nào, nhận context gì, và được gọi helper nào. Bài này liệt kê các program type nhân hỗ trợ, rồi gắn một tracepoint vào syscall openat để thấy nó chạy thật trên mỗi lần mở file — tương phản với XDP nhận gói tin ở bài trước, để thấy vì sao cùng là eBPF mà mỗi loại thấy một thế giới khác nhau.