Semua dengan liburan yang lalu!
Kami memutuskan untuk mencurahkan artikel pertama kami setelah liburan ke Linux, yaitu untuk kursus
Administrator Linux kami yang luar biasa, yang kami miliki dalam kelompok kursus yang paling dinamis, yaitu, dengan materi dan praktik yang paling relevan. Yah dan, karenanya, kami menawarkan artikel menarik dan
pelajaran terbuka .
Diposting oleh Matteo Croce
Judul asli: debugging jaringan dengan eBPF (RHEL 8 Beta)PendahuluanJaringan adalah pengalaman yang menyenangkan, tetapi masalah tidak selalu dihindari. Pemecahan masalah bisa rumit, seperti mencoba mereproduksi perilaku yang salah yang terjadi "di lapangan."
Untungnya, ada alat yang dapat membantu dengan ini: ruang nama jaringan, mesin virtual,
tc
dan
netfilter
. Pengaturan jaringan sederhana dapat direproduksi menggunakan ruang nama jaringan dan perangkat veth, sedangkan pengaturan yang lebih kompleks memerlukan menghubungkan mesin virtual dengan jembatan perangkat lunak dan menggunakan alat jaringan standar, seperti
iptables
atau
tc
, untuk mensimulasikan perilaku yang salah. Jika ada masalah dengan respons ICMP yang dihasilkan ketika server SSH
iptables -A INPUT -p tcp --dport 22 -j REJECT --reject-with icmp-host-unreachable
,
iptables -A INPUT -p tcp --dport 22 -j REJECT --reject-with icmp-host-unreachable
di namespace yang benar dapat membantu menyelesaikan masalah.
Artikel ini menjelaskan cara memecahkan masalah jaringan yang kompleks dengan
eBPF (extended BPF) , versi lanjutan dari Berkeley Packet Filter. eBPF adalah teknologi yang relatif baru, proyek ini pada tahap awal, sehingga dokumentasi dan SDK belum siap. Tapi mari kita berharap untuk perbaikan, terutama karena XDP (eXpress Data Path) dikirimkan bersama
Red Hat Enterprise Linux 8 Beta , yang dapat Anda unduh dan jalankan sekarang.
eBPF tidak akan menyelesaikan semua masalah, tetapi masih merupakan alat debugging jaringan yang kuat yang perlu diperhatikan. Saya yakin itu akan memainkan peran yang sangat penting di masa depan jaringan.
MasalahSaya sedang men-debug masalah jaringan
Open vSwitch (OVS) yang melibatkan instalasi yang sangat kompleks: beberapa paket TCP tersebar dan dikirim dalam urutan yang salah, dan bandwidth mesin virtual turun dari stabil 6 Gb / s menjadi berfluktuasi 2-4 Gb / s. Analisis menunjukkan bahwa paket TCP pertama dari setiap koneksi dengan flag PSH dikirim dalam urutan yang salah: hanya yang pertama dan hanya satu per koneksi.
Saya mencoba mereproduksi pengaturan ini dengan dua mesin virtual dan, setelah banyak artikel bantuan dan permintaan pencarian, saya menemukan bahwa
iptables
atau
nftables
tidak dapat memanipulasi flag TCP, sementara
tc
dapat, tetapi hanya dengan menimpa flag dan mengganggu koneksi baru dan TCP secara umum.
Dimungkinkan untuk menyelesaikan masalah dengan kombinasi
iptables
,
conntrack
, dan
tc
, tetapi saya memutuskan bahwa ini adalah pekerjaan hebat bagi eBPF.
Apa itu eBPF?eBPF adalah versi yang disempurnakan dari Berkeley Packet Filter. Dia membawa banyak perbaikan ke BPF. Secara khusus, ini memungkinkan Anda untuk menulis di memori, dan tidak hanya membaca, sehingga paket tidak hanya dapat difilter, tetapi juga diedit.
Seringkali eBPF hanya disebut BPF, dan BPF itu sendiri disebut cBPF (klasik (klasik) BPF), sehingga kata "BPF" dapat digunakan untuk berarti kedua versi, tergantung pada konteksnya: dalam artikel ini saya selalu berbicara tentang versi yang diperluas.
βUnder the hoodβ eBPF memiliki mesin virtual yang sangat sederhana yang dapat mengeksekusi fragmen kecil bytecode dan mengedit beberapa buffer memori. Ada batasan dalam eBPF yang melindunginya dari penggunaan jahat:
- Siklus dilarang sehingga program selalu berakhir pada waktu tertentu;
- Itu hanya dapat mengakses memori melalui stack and scratch buffer;
- Hanya fungsi kernel yang diizinkan yang bisa dipanggil.
Suatu program dapat dimuat ke dalam kernel dengan berbagai cara menggunakan
debugging dan tracing . Dalam kasus kami, eBPF tertarik untuk bekerja dengan subsistem jaringan. Ada dua cara untuk menggunakan program eBPF:
- Terhubung melalui XDP ke awal jalur RX kartu jaringan fisik atau virtual;
- Terhubung melalui
tc
ke qdisc dalam input atau output.
Untuk membuat program eBPF untuk menghubungkan, cukup tulis kode C dan konversikan menjadi bytecode. Berikut ini adalah contoh sederhana menggunakan XDP:
SEC("prog") int xdp_main(struct xdp_md *ctx) { void *data_end = (void *)(uintptr_t)ctx->data_end; void *data = (void *)(uintptr_t)ctx->data; struct ethhdr *eth = data; struct iphdr *iph = (struct iphdr *)(eth + 1); struct icmphdr *icmph = (struct icmphdr *)(iph + 1); if (icmph + 1 > data_end) return XDP_PASS; if (eth->h_proto != ntohs(ETH_P_IP) || iph->protocol != IPPROTO_ICMP || icmph->type != ICMP_ECHOREPLY) return XDP_PASS; if (iph->ttl) { uint16_t *ttlproto = (uint16_t *)&iph->ttl; uint16_t old_ttlproto = *ttlproto; iph->ttl = bpf_get_prandom_u32() % iph->ttl + 1; csum_replace2(&iph->check, old_ttlproto, *ttlproto); } return XDP_PASS; } char _license[] SEC("license") = "GPL";
Cuplikan di atas, tanpa
include
ekspresi, helper dan kode opsional, adalah program XDP yang mengubah TTL dari balasan gema ICMP yang diterima, yaitu pong, dengan nomor acak. Fungsi utama mendapatkan struktur
xdp_md
, yang berisi dua petunjuk awal dan akhir paket.
Untuk mengkompilasi kode kami ke dalam bytecode eBPF, diperlukan kompiler dengan dukungan yang sesuai. Dentang mendukungnya dan membuat bytecode eBPF dengan menetapkan bpf sebagai target pada waktu kompilasi:
$ clang -O2 -target bpf -c xdp_manglepong.c -o xdp_manglepong.o
Perintah di atas membuat file yang, pada pandangan pertama, tampak seperti file objek normal, tetapi setelah diperiksa lebih dekat, ternyata tipe komputer yang ditentukan adalah Linux eBPF, dan bukan tipe asli sistem operasi:
$ readelf -h xdp_manglepong.o ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: Linux BPF <--- HERE [...]
Setelah menerima pembungkus file objek biasa, program eBPF siap untuk mengunduh dan terhubung ke perangkat melalui XDP. Ini dapat dilakukan dengan menggunakan
ip
dari paket
iproute2
dengan sintaks berikut:
Perintah ini menentukan antarmuka target wlan0 dan, berkat opsi-force, menimpa kode eBPF yang sudah ada yang telah dimuat. Setelah memuat byBode eBPF, sistem berperilaku sebagai berikut:
$ ping -c10 192.168.85.1 PING 192.168.85.1 (192.168.85.1) 56(84) bytes of data. 64 bytes from 192.168.85.1: icmp_seq=1 ttl=41 time=0.929 ms 64 bytes from 192.168.85.1: icmp_seq=2 ttl=7 time=0.954 ms 64 bytes from 192.168.85.1: icmp_seq=3 ttl=17 time=0.944 ms 64 bytes from 192.168.85.1: icmp_seq=4 ttl=64 time=0.948 ms 64 bytes from 192.168.85.1: icmp_seq=5 ttl=9 time=0.803 ms 64 bytes from 192.168.85.1: icmp_seq=6 ttl=22 time=0.780 ms 64 bytes from 192.168.85.1: icmp_seq=7 ttl=32 time=0.847 ms 64 bytes from 192.168.85.1: icmp_seq=8 ttl=50 time=0.750 ms 64 bytes from 192.168.85.1: icmp_seq=9 ttl=24 time=0.744 ms 64 bytes from 192.168.85.1: icmp_seq=10 ttl=42 time=0.791 ms --- 192.168.85.1 ping statistics --- 10 packets transmitted, 10 received, 0% packet loss, time 125ms rtt min/avg/max/mdev = 0.744/0.849/0.954/0.082 ms
Setiap paket melewati eBPF, yang pada akhirnya membuat beberapa perubahan dan memutuskan apakah akan menjatuhkan paket atau melewatkannya.
Bagaimana eBPF Dapat MembantuKembali ke masalah jaringan asli, kami ingat bahwa perlu menandai beberapa flag TCP, satu per koneksi, dan
iptables
atau
tc
tidak dapat melakukan ini. Menulis kode untuk skenario ini tidak sulit sama sekali: mengkonfigurasi dua mesin virtual yang terhubung oleh jembatan OVS, dan cukup menghubungkan eBPF ke salah satu perangkat VM virtual.
Kedengarannya seperti solusi yang bagus, tetapi perlu diingat bahwa XDP hanya mendukung pemrosesan paket yang diterima, dan menghubungkan eBPF ke jalur
rx
dari mesin virtual penerima tidak akan memiliki efek pada sakelar.
Untuk mengatasi masalah ini, eBPF harus dimuat menggunakan
tc
dan terhubung ke jalur output VM, karena
tc
dapat memuat dan menghubungkan program-program eBPF ke qdisk. Untuk menandai paket yang meninggalkan host, eBPF harus terhubung ke output qdisk.
Saat memuat program eBPF, ada beberapa perbedaan antara
XDP
dan
tc
API: secara default, nama bagian yang berbeda, jenis struktur argumen fungsi utama, nilai pengembalian yang berbeda. Tapi ini bukan masalah. Di bawah ini adalah cuplikan dari program yang menandai TCP saat bergabung dengan tindakan tc:
#define RATIO 10 SEC("action") int bpf_main(struct __sk_buff *skb) { void *data = (void *)(uintptr_t)skb->data; void *data_end = (void *)(uintptr_t)skb->data_end; struct ethhdr *eth = data; struct iphdr *iph = (struct iphdr *)(eth + 1); struct tcphdr *tcphdr = (struct tcphdr *)(iph + 1); if ((void *)(tcphdr + 1) > data_end) return TC_ACT_OK; if (eth->h_proto != __constant_htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP) return TC_ACT_OK; if (tcphdr->syn || tcphdr->fin || tcphdr->rst || tcphdr->psh) return TC_ACT_OK; if (bpf_get_prandom_u32() % RATIO == 0) tcphdr->psh = 1; return TC_ACT_OK; } char _license[] SEC("license") = "GPL";
Kompilasi menjadi bytecode dilakukan seperti yang ditunjukkan pada contoh XDP di atas menggunakan yang berikut:
clang -O2 -target bpf -c tcp_psh.c -o tcp_psh.o
Tetapi unduhannya berbeda:
Sekarang eBPF dimuat di tempat yang tepat dan paket yang meninggalkan VM ditandai. Setelah memeriksa paket yang diterima di VM kedua, kita akan melihat yang berikut:

tcpdump
mengkonfirmasi bahwa kode eBPF baru berfungsi, dan sekitar 1 dari setiap 10 paket TCP memiliki flag PSH yang ditetapkan. Hanya 20 baris kode-C yang diperlukan untuk secara selektif menandai paket TCP yang meninggalkan mesin virtual, mereproduksi kesalahan yang terjadi "dalam pertempuran", dan semua tanpa mengkompilasi ulang atau bahkan memulai kembali! Ini sangat menyederhanakan verifikasi
perbaikan Open vSwitch , yang tidak mungkin dicapai dengan alat lain.
KesimpulaneBPF adalah teknologi yang cukup baru, dan masyarakat memiliki pendapat yang jelas tentang implementasinya. Perlu juga dicatat bahwa proyek berbasis eBPF, seperti
bpfilter , menjadi lebih populer, dan sebagai hasilnya, banyak pemasok peralatan mulai menerapkan dukungan eBPF langsung pada kartu jaringan.
eBPF tidak akan menyelesaikan semua masalah, jadi jangan menyalahgunakannya, tetapi tetap saja itu merupakan alat yang sangat kuat untuk debugging jaringan dan patut mendapat perhatian. Saya yakin itu akan memainkan peran penting di masa depan jaringan.
AKHIRKami menunggu komentar Anda di sini, dan kami juga mengundang Anda untuk mengunjungi
pelajaran terbuka kami, di mana jika Anda dapat mengajukan pertanyaan juga.