Cấu hình môi trường và chuẩn bị công cụ cho giám sát mạng
Bước đầu tiên là đảm bảo môi trường trên Raspberry Pi CM5 đã có sẵn các công cụ cần thiết để biên dịch và chạy các chương trình eBPF liên quan đến mạng.
Chúng ta cần cài đặt bpfcc-tools (BPF Compiler Collection) hoặc bpftrace để có thể viết và chạy các script giám sát mà không cần biên dịch phức tạp. Đồng thời, kiểm tra xem kernel đã hỗ trợ XDP hay chưa.
Thực thi lệnh sau để cài đặt các gói công cụ trên Debian/Ubuntu (hệ điều hành mặc định cho CM5):
sudo apt-get update && sudo apt-get install -y bpfcc-tools bpftrace linux-headers-rpi linux-modules-rpi
Kết quả mong đợi: Hệ thống tải và cài đặt thành công các công cụ, không báo lỗi. Bạn có thể kiểm tra bằng lệnh bpftrace --version.
Kiểm tra hỗ trợ XDP trên giao diện mạng
Trước khi viết code, cần xác minh xem driver mạng trên CM5 (thường là eth0 hoặc enx...) có hỗ trợ XDP hay không. XDP yêu cầu driver phải có hook ndo_bpf.
Sử dụng lệnh ip để kiểm tra khả năng hỗ trợ XDP của card mạng:
ip -s link show eth0 | grep -i xdp
Kết quả mong đợi: Nếu thấy dòng XDP: 0 hoặc tương tự, nghĩa là driver hỗ trợ XDP. Nếu không thấy gì, driver đó không hỗ trợ, và bạn cần kiểm tra lại kernel hoặc driver.
Giám sát hiệu năng mạng với BPF Tracepoint ở tầng Transport
Mục tiêu của phần này là theo dõi các gói tin mạng khi chúng đi qua tầng Transport (TCP/UDP) để đo lường latency và throughput. Chúng ta sẽ sử dụng tracepoint thay vì kprobe vì tracepoint an toàn hơn, ổn định hơn và không bị xóa khi kernel update.
Chúng ta sẽ viết một script bpftrace để hook vào điểm tracepoint:tcp:tcp_sendmsg và tracepoint:tcp:tcp_recvmsg.
Viết script bpftrace để theo dõi TCP Send/Recv
Script này sẽ đếm số lượng gói tin và tổng số byte được gửi/nhận, sau đó in ra kết quả mỗi 1 giây.
Đường dẫn file: /root/tcp_monitor.bt
Nội dung file hoàn chỉnh:
@/root/tcp_monitor.bt
tracepoint:tcp:tcp_sendmsg {
$bytes = 0;
if (pid == 1234) { // Thay 1234 bằng PID ứng dụng bạn muốn monitor, hoặc xóa dòng này để monitor toàn bộ
$bytes = (long)args->sk_wmem_alloc;
}
@sent_bytes = sum($bytes);
@sent_pkts = count();
}
tracepoint:tcp:tcp_recvmsg {
$bytes = 0;
if (pid == 1234) {
$bytes = (long)args->sk_wmem_alloc;
}
@recv_bytes = sum($bytes);
@recv_pkts = count();
}
interval:s:1 {
printf("TCP Stats (last 1s):\n");
printf(" Sent: %d pkts, %d bytes\n", @sent_pkts, @sent_bytes);
printf(" Recv: %d pkts, %d bytes\n", @recv_pkts, @recv_bytes);
delete(@sent_bytes); delete(@sent_pkts);
delete(@recv_bytes); delete(@recv_pkts);
}
Chạy script với quyền root để kích hoạt giám sát:
sudo bpftrace /root/tcp_monitor.bt
Kết quả mong đợi: Màn hình hiển thị số liệu thống kê về gói tin và byte gửi/nhận được cập nhật mỗi giây. Bạn có thể tạo traffic bằng ping hoặc iperf3 để thấy số liệu thay đổi.
Đo lường Latency với Tracepoint
Để đo độ trễ (latency) của một gói tin, chúng ta cần ghi lại thời điểm gói tin được gửi và thời điểm nhận được phản hồi. Chúng ta sẽ sử dụng map hash để lưu timestamp.
Đường dẫn file: /root/tcp_latency.bt
Nội dung file hoàn chỉnh:
@/root/tcp_latency.bt
tracepoint:tcp:tcp_sendmsg {
$ts = nsecs;
@start_ts[pid] = $ts;
}
tracepoint:tcp:tcp_recvmsg {
if (@start_ts[pid]) {
$duration = nsecs - @start_ts[pid];
@latency = hist($duration / 1000); // Chuyển sang microsecond
delete(@start_ts[pid]);
}
}
interval:s:1 {
printf("TCP Latency Distribution (us):\n");
@latency;
delete(@latency);
}
Thực thi lệnh để chạy script đo latency:
sudo bpftrace /root/tcp_latency.bt
Kết quả mong đợi: Hiển thị biểu đồ histogram phân bố độ trễ (microseconds) của các gói tin TCP. Các giá trị nhỏ hơn nghĩa là mạng nhanh hơn.
Triển khai XDP để lọc gói tin ở tầng Driver
XDP (eXpress Data Path) cho phép chạy code eBPF ngay tại driver mạng, trước khi gói tin được xử lý bởi stack TCP/IP của kernel. Điều này giúp giảm tải cho CPU và lọc gói tin độc hại hoặc không cần thiết cực nhanh.
Trên Raspberry Pi CM5 (ARM64), chúng ta sẽ sử dụng xdp-loader hoặc viết trực tiếp bằng bpf2elf và ip. Ở đây, chúng ta dùng bpftrace để đơn giản hóa việc deploy, nhưng để hiệu năng tối đa, thường dùng C + clang. Tuy nhiên, để minh họa logic lọc, ta sẽ dùng xdp-tools (có sẵn trong bpfcc-tools) hoặc script C đơn giản.
Viết chương trình XDP bằng C để drop gói tin
Chúng ta sẽ viết một chương trình C đơn giản để drop tất cả các gói tin ICMP (Ping) đi qua giao diện eth0. Đây là ví dụ điển hình của firewall ở tầng driver.
Đường dẫn file: /root/xdp_drop_icmp.c
Nội dung file hoàn chỉnh:
@/root/xdp_drop_icmp.c
#include
#include
SEC("xdp")
int xdp_drop_icmp(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
// Kiểm tra header Ethernet (14 bytes) và IP header (20 bytes)
if (data + 14 + 20 > data_end)
return XDP_PASS; // Không đủ dữ liệu, cho qua
struct ethhdr *eth = data;
if (eth->h_proto != 0x0800) // Chỉ xử lý IPv4
return XDP_PASS;
struct iphdr *iph = (struct iphdr *)(eth + 1);
if (iph->protocol == 1) { // Protocol 1 là ICMP
return XDP_DROP; // Drop gói tin ICMP
}
return XDP_PASS; // Cho qua các gói tin khác
}
char LICENSE[] SEC("license") = "GPL";
Biên dịch chương trình trên ARM64 (trên CM5 hoặc cross-compile):
clang -O2 -target bpf -c /root/xdp_drop_icmp.c -o /root/xdp_drop_icmp.o
Kết quả mong đợi: Tạo ra file object xdp_drop_icmp.o. Nếu lỗi, kiểm tra xem clang và bpf-tools đã cài đặt đúng chưa.
Deploy chương trình XDP vào giao diện mạng
Sử dụng lệnh ip để load file object vào driver mạng. Chúng ta sẽ load vào mode native (khuyên dùng cho hiệu năng cao trên CM5) hoặc generic (nếu driver không hỗ trợ native).
Thực thi lệnh sau (giả sử interface là eth0):
ip link set dev eth0 xdp obj /root/xdp_drop_icmp.o mode native
Kiểm tra xem XDP đã được load thành công chưa:
ip -s link show eth0 | grep -A 5 xdp
Kết quả mong đợi: Dòng xdp hiển thị attached và mode native. Nếu mode native không được hỗ trợ, hãy thử lại với mode generic.
Verify kết quả lọc gói tin
Để xác nhận XDP đang hoạt động, hãy thực hiện ping từ một máy khác đến CM5 hoặc ping từ CM5 ra ngoài. Nếu XDP drop ICMP, bạn sẽ thấy gói tin bị mất.
Thực thi lệnh ping từ CM5:
ping -c 4 8.8.8.8
Kết quả mong đợi: Nếu XDP drop ICMP đi ra (tùy logic code, ở trên code drop ICMP đến), bạn sẽ thấy Request timeout hoặc tỷ lệ drop cao. Để kiểm tra chính xác, hãy mở terminal khác và chạy tcpdump hoặc xem log ip -s link show eth0 để thấy số packet drop tăng lên.
Để gỡ bỏ XDP (khi cần khôi phục mạng bình thường):
ip link set dev eth0 xdp off
Đo lường Throughput và Latency tổng hợp bằng eBPF
Để có cái nhìn tổng quan về hiệu năng mạng, chúng ta kết hợp các kỹ thuật trên để đo throughput (lượng dữ liệu qua/giây) và latency (thời gian trễ) một cách đồng bộ.
Chúng ta sẽ sử dụng bpftrace với các tracepoint net:netif_rx_entry và net:netif_tx_entry để đếm byte vào/ra ở tầng driver.
Script đo Throughput mạng
Script này sẽ đếm tổng số byte vào (RX) và ra (TX) mỗi giây cho tất cả các giao diện mạng.
Đường dẫn file: /root/network_throughput.bt
Nội dung file hoàn chỉnh:
@/root/network_throughput.bt
tracepoint:net:netif_rx_entry {
@rx_bytes[comm] = sum(args->len);
}
tracepoint:net:netif_tx_entry {
@tx_bytes[comm] = sum(args->len);
}
interval:s:1 {
printf("Network Throughput (bytes/sec):\n");
printf(" Process\tRX\tTX\n");
@rx_bytes;
@tx_bytes;
delete(@rx_bytes);
delete(@tx_bytes);
}
Chạy script để bắt đầu đo lường:
sudo bpftrace /root/network_throughput.bt
Kết quả mong đợi: Hiển thị bảng thống kê throughput theo từng tiến trình (process) đang sử dụng mạng. Ví dụ: iperf3 sẽ có số byte rất lớn.
Đo Latency tổng hợp với XDP và Tracepoint
Để đo latency từ lúc gói tin vào driver (XDP) đến lúc được xử lý bởi TCP stack, chúng ta cần hook vào cả XDP và tracepoint TCP. Tuy nhiên, để đơn giản và hiệu quả trên CM5, chúng ta sẽ đo latency từ lúc gói tin vào driver (netif_rx_entry) đến lúc gửi đi (netif_tx_entry) cho các gói tin cụ thể.
Đường dẫn file: /root/network_latency.bt
Nội dung file hoàn chỉnh:
@/root/network_latency.bt
tracepoint:net:netif_rx_entry {
$ts = nsecs;
@recv_ts[pid] = $ts;
}
tracepoint:net:netif_tx_entry {
if (@recv_ts[pid]) {
$duration = nsecs - @recv_ts[pid];
@latency = hist($duration / 1000); // microsecond
delete(@recv_ts[pid]);
}
}
interval:s:1 {
printf("Network Latency (us):\n");
@latency;
delete(@latency);
}
Thực thi lệnh để chạy script đo latency:
sudo bpftrace /root/network_latency.bt
Kết quả mong đợi: Hiển thị phân bố độ trễ (histogram) của quá trình xử lý gói tin từ khi nhận vào driver đến khi gửi đi. Các giá trị thấp (dưới 100us) cho thấy hiệu năng mạng tốt trên CM5.
Verify kết quả cuối cùng
Để xác minh toàn bộ hệ thống giám sát đang hoạt động hiệu quả:
- Chạy
iperf3 -c [SERVER_IP] trên CM5 để tạo tải mạng lớn.
- Quan sát output của script
network_throughput.bt: Số byte TX/RX phải tăng nhanh và khớp với throughput của iperf3.
- Quan sát output của script
network_latency.bt: Latency nên ổn định ở mức thấp (microseconds). Nếu latency tăng đột biến, có thể do CPU bị quá tải.
- Nếu đã deploy XDP drop ICMP, thử ping
ping -c 1 [SERVER_IP] và kiểm tra log drop trong ip -s link show eth0.
Kết quả mong đợi: Tất cả các script chạy ổn định, số liệu thống kê phản ánh đúng tình trạng mạng thực tế, và không gây ra lỗi kernel (OOPS) hay treo hệ thống trên Raspberry Pi CM5.
Điều hướng series:
Mục lục: Series: Tối ưu hóa Linux Kernel cho Raspberry Pi CM5 với BPF và eBPF
« Phần 5: Sử dụng kprobe và kretprobe để giám sát hệ thống trên CM5
Phần 7: Tối ưu hóa sử dụng tài nguyên và giảm overhead trên CM5 »