A Pambuka Brief kanggo BPF lan eBPF

Sugeng rawuh, Habr! Kita pengin ngandhani yen kita lagi nyiapake buku sing bakal dirilis."Linux Observability karo BPF".

A Pambuka Brief kanggo BPF lan eBPF
Wiwit mesin virtual BPF terus berkembang lan aktif digunakake ing laku, kita wis nerjemahake kanggo sampeyan artikel njlèntrèhaké kabisan utama lan negara saiki.

Ing taun-taun pungkasan, alat lan teknik pemrograman dadi populer kanggo ngimbangi watesan kernel Linux ing kasus sing mbutuhake pangolahan paket kanthi kinerja dhuwur. Salah sawijining teknik sing paling populer saka jinis iki diarani bypass kernel (kernel bypass) lan ngidini, ngliwati lapisan jaringan kernel, kanggo nindakake kabeh pangolahan paket saka ruang pangguna. Bypassing kernel uga melu ngontrol kertu jaringan saka papan panganggo. Ing tembung liyane, nalika nggarap kertu jaringan, kita gumantung ing driver papan panganggo.

Kanthi nransfer kontrol lengkap kertu jaringan menyang program ruang pangguna, kita nyuda overhead kernel (ngoper konteks, pangolahan lapisan jaringan, interrupts, lan liya-liyane), sing penting banget nalika mlaku kanthi kecepatan 10Gb / s utawa luwih dhuwur. Kernel bypass plus kombinasi fitur liyane (pangolahan batch) lan tuning kinerja sing ati-ati (akuntansi NUMA, Isolasi CPU, etc.) cocog karo dhasar pangolahan jaringan kinerja dhuwur ing ruang pangguna. Mbok conto teladan saka pendekatan anyar kanggo Processing paket punika DPDK saka Intel (Data Plane Development Kit), sanajan ana alat lan teknik liyane sing kondhang, kalebu Cisco's VPP (Vector Packet Processing), Netmap lan, mesthi, Snabb.

Ngatur interaksi jaringan ing ruang pangguna duwe sawetara kekurangan:

  • Kernel OS minangka lapisan abstraksi kanggo sumber daya hardware. Amarga program ruang pangguna kudu ngatur sumber daya kanthi langsung, uga kudu ngatur hardware dhewe. Iki asring tegese kudu program driver dhewe.
  • Amarga kita nyerahake ruang kernel kabeh, kita uga nyerahake kabeh fungsi jaringan sing diwenehake dening kernel. Program pangguna-ruang kudu ngleksanakake maneh fungsi sing bisa uga wis diwenehake dening kernel utawa sistem operasi.
  • Program beroperasi ing mode kothak wedhi, sing mbatesi interaksi kanthi serius lan nyegah supaya ora bisa digabung karo bagean sistem operasi liyane.

Intine, nalika jaringan ana ing ruang pangguna, keuntungan kinerja digayuh kanthi mindhah pangolahan paket saka kernel menyang ruang pangguna. XDP nindakake persis ngelawan: mindhah program jaringan saka ruang pangguna (filter, solver, routing, lsp) menyang ruang kernel. XDP ngidini kita nindakake fungsi jaringan sanalika paket tekan antarmuka jaringan lan sadurunge wiwit pindhah menyang subsistem jaringan kernel. Akibaté, kacepetan pangolahan paket mundhak sacara signifikan. Nanging, kepiye kernel ngidini pangguna nglakokake program ing ruang kernel? Sadurunge njawab pitakonan iki, ayo dideleng apa BPF.

BPF lan eBPF

Senadyan jeneng mbingungake, BPF (Berkeley Packet Filtering), nyatane, model mesin virtual. Mesin virtual iki wiwitane dirancang kanggo nangani panyaring paket, mula jenenge.

Salah sawijining alat sing paling misuwur nggunakake BPF yaiku tcpdump. Nalika njupuk paket nggunakake tcpdump pangguna bisa nemtokake ekspresi kanggo nyaring paket. Mung paket sing cocog karo ekspresi iki sing bakal dijupuk. Contone, ungkapan "tcp dst port 80” nuduhake kabeh paket TCP teka ing port 80. Compiler bisa shorten expression iki kanthi ngowahi menyang BPF bytecode.

$ sudo tcpdump -d "tcp dst port 80"
(000) ldh [12] (001) jeq #0x86dd jt 2 jf 6
(002) ldb [20] (003) jeq #0x6 jt 4 jf 15
(004) ldh [56] (005) jeq #0x50 jt 14 jf 15
(006) jeq #0x800 jt 7 jf 15
(007) ldb [23] (008) jeq #0x6 jt 9 jf 15
(009) ldh [20] (010) jset #0x1fff jt 15 jf 11
(011) ldxb 4*([14]&0xf)
(012) ldh [x + 16] (013) jeq #0x50 jt 14 jf 15
(014) ret #262144
(015) ret #0

Iki minangka dhasar program ing ndhuwur:

  • Instruksi (000): Muat paket ing offset 12, minangka tembung 16-bit, menyang accumulator. Offset 12 cocog karo ethertype saka paket.
  • Instruksi (001): mbandhingake nilai ing accumulator karo 0x86dd, yaiku, karo nilai ethertype kanggo IPv6. Yen asil kasebut bener, counter program menyang instruksi (002), lan yen ora, banjur menyang (006).
  • Instruksi (006): mbandhingake nilai karo 0x800 (nilai ethertype kanggo IPv4). Yen jawabane bener, banjur program menyang (007), yen ora, banjur menyang (015).

Lan sateruse nganti program panyaring paket ngasilake asil. Iki biasane Boolean. Ngasilake nilai non-nol (instruksi (014)) tegese paket kasebut ditampa, lan mbalekake nilai nol (instruksi (015)) tegese paket kasebut ora ditampa.

Mesin virtual BPF lan bytecode diusulake dening Steve McCann lan Van Jacobson ing pungkasan taun 1992 nalika koran diterbitake. Filter Paket BSD: Arsitektur Anyar kanggo Penangkapan Paket Tingkat Panganggo, teknologi iki pisanan ditampilake ing konferensi Usenix ing mangsa 1993.

Amarga BPF minangka mesin virtual, iku nemtokake lingkungan ing ngendi program mbukak. Saliyane bytecode, iku uga nemtokake model memori kumpulan (instruksi mbukak implicitly Applied kanggo kumpulan), ndhaftar (A lan X; accumulator lan indeks ndhaftar), panyimpenan memori ngeruk, lan counter program implisit. Apike, bytecode BPF dimodelake sawise Motorola 6502 ISA. Minangka Steve McCann ngelingi ing laporan pleno ing Sharkfest '11, piyambakipun menowo mbangun 6502 saka program dina SMA ing Apple II, lan kawruh iki dipengaruhi karya ngrancang BPF bytecode.

Dhukungan BPF dileksanakake ing kernel Linux ing versi v2.5 lan luwih dhuwur, ditambahake utamane dening upaya Jay Schullist. Kode BPF tetep ora owah nganti 2011, nalika Eric Dumaset ngrancang ulang juru basa BPF supaya bisa mlaku ing mode JIT (Sumber: JIT kanggo saringan paket). Sawise iki, kernel, tinimbang nerjemahake bytecode BPF, bisa langsung ngowahi program BPF menyang arsitektur target: x86, ARM, MIPS, lsp.

Mengko, ing 2014, Alexey Starovoitov ngusulake mekanisme JIT anyar kanggo BPF. Nyatane, JIT anyar iki dadi arsitektur basis BPF anyar lan diarani eBPF. Aku loro VMs coexisted kanggo sawetara wektu, nanging saiki paket nyaring dipun ginakaken adhedhasar eBPF. Nyatane, ing pirang-pirang conto dokumentasi modern, BPF dimangerteni minangka eBPF, lan BPF klasik saiki dikenal minangka cBPF.

eBPF ngluwihi mesin virtual BPF klasik kanthi sawetara cara:

  • Adhedhasar arsitektur 64-bit modern. eBPF migunakake 64-dicokot ndhaftar lan nambah nomer kasedhiya saka 2 (accumulator lan X) kanggo 10. eBPF uga menehi opcodes tambahan (BPF_MOV, BPF_JNE, BPF_CALL ...).
  • Kapisah saka subsistem lapisan jaringan. BPF diikat karo model data batch. Wiwit digunakake kanggo panyaring paket, kode kasebut ana ing subsistem sing nyedhiyakake komunikasi jaringan. Nanging, mesin virtual eBPF ora disambungake maneh karo model data lan bisa digunakake kanggo maksud apa wae. Dadi, saiki program eBPF bisa disambungake menyang tracepoint utawa kprobe. Iki mbukak dalan menyang instrumentasi eBPF, analisis kinerja, lan akeh kasus panggunaan liyane ing konteks subsistem kernel liyane. Saiki kode eBPF dumunung ing jalur dhewe: kernel / bpf.
  • nyimpen data global disebut Maps. Peta minangka toko nilai kunci sing ngidini pertukaran data antarane ruang pangguna lan ruang kernel. eBPF nyedhiyakake sawetara jinis peta.
  • Fungsi Sekunder. Utamane, kanggo nulis ulang paket, ngitung checksum, utawa kloning paket. Fungsi-fungsi kasebut mbukak ing njero kernel lan dudu program ruang pangguna. Sampeyan uga bisa nelpon sistem saka program eBPF.
  • Mungkasi telpon. Ukuran program ing eBPF diwatesi nganti 4096 bita. Fitur panggilan buntut ngidini program eBPF nransfer kontrol menyang program eBPF anyar lan kanthi mangkono ngliwati watesan iki (nganti 32 program bisa disambungake kanthi cara iki).

eBPF: contone

Ana sawetara conto kanggo eBPF ing sumber kernel Linux. Padha kasedhiya ing conto / bpf /. Kanggo ngumpulake conto iki, ketik:

$ sudo make samples/bpf/

Aku ora bakal nulis conto anyar kanggo eBPF dhewe, nanging bakal nggunakake salah siji saka conto kasedhiya ing conto / bpf /. Aku bakal katon ing sawetara bagéan saka kode lan nerangake cara kerjane. Minangka conto, aku milih program tracex4.

Umumé, saben conto ing conto/bpf/ kasusun saka rong file. Ing kasus iki:

  • tracex4_kern.c, ngemot kode sumber sing bakal dieksekusi ing kernel minangka bytecode eBPF.
  • tracex4_user.c, ngemot program saka ruang pangguna.

Ing kasus iki, kita kudu ngumpulake tracex4_kern.c menyang eBPF bytecode. Saiki ing gcc ora ana backend kanggo eBPF. Untunge, clang bisa output eBPF bytecode. Makefile nggunakake clang kanggo kompilasi tracex4_kern.c menyang file obyek.

Aku kasebut ing ndhuwur yen salah sawijining fitur eBPF sing paling menarik yaiku peta. tracex4_kern nemtokake siji peta:

struct pair {
    u64 val;
    u64 ip;
};  

struct bpf_map_def SEC("maps") my_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(long),
    .value_size = sizeof(struct pair),
    .max_entries = 1000000,
};

BPF_MAP_TYPE_HASH iku salah siji saka akeh jinis kertu ana dening eBPF. Ing kasus iki, iku mung hash. Sampeyan bisa uga wis ngeweruhi iklan SEC("maps"). SEC minangka makro sing digunakake kanggo nggawe bagean anyar saka file binar. Bener, ing conto tracex4_kern rong bagean liyane ditetepake:

SEC("kprobe/kmem_cache_free")
int bpf_prog1(struct pt_regs *ctx)
{   
    long ptr = PT_REGS_PARM2(ctx);

    bpf_map_delete_elem(&my_map, &ptr); 
    return 0;
}
    
SEC("kretprobe/kmem_cache_alloc_node") 
int bpf_prog2(struct pt_regs *ctx)
{
    long ptr = PT_REGS_RC(ctx);
    long ip = 0;

    // получаем ip-адрес вызывающей стороны kmem_cache_alloc_node() 
    BPF_KRETPROBE_READ_RET_IP(ip, ctx);

    struct pair v = {
        .val = bpf_ktime_get_ns(),
        .ip = ip,
    };
    
    bpf_map_update_elem(&my_map, &ptr, &v, BPF_ANY);
    return 0;
}   

Loro fungsi iki ngidini sampeyan mbusak entri saka peta (kprobe/kmem_cache_free) lan nambah entri anyar menyang peta (kretprobe/kmem_cache_alloc_node). Kabeh jeneng fungsi sing ditulis nganggo huruf kapital cocog karo makro sing ditetepake ing bpf_helpers.h.

Yen aku mbuwang bagean file obyek, aku kudu ndeleng manawa bagean anyar iki wis ditetepake:

$ objdump -h tracex4_kern.o

tracex4_kern.o: file format elf64-little

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000000 0000000000000000 0000000000000000 00000040 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 kprobe/kmem_cache_free 00000048 0000000000000000 0000000000000000 00000040 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
2 kretprobe/kmem_cache_alloc_node 000000c0 0000000000000000 0000000000000000 00000088 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
3 maps 0000001c 0000000000000000 0000000000000000 00000148 2**2
CONTENTS, ALLOC, LOAD, DATA
4 license 00000004 0000000000000000 0000000000000000 00000164 2**0
CONTENTS, ALLOC, LOAD, DATA
5 version 00000004 0000000000000000 0000000000000000 00000168 2**2
CONTENTS, ALLOC, LOAD, DATA
6 .eh_frame 00000050 0000000000000000 0000000000000000 00000170 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

Ana uga tracex4_user.c, program utama. Sejatine, program iki ngrungokake acara kmem_cache_alloc_node. Nalika kedadeyan kasebut, kode eBPF sing cocog bakal dieksekusi. Kode nyimpen atribut IP saka obyek menyang peta, lan obyek banjur loop liwat program utama. Tuladha:

$ sudo ./tracex4
obj 0xffff8d6430f60a00 is 2sec old was allocated at ip ffffffff9891ad90
obj 0xffff8d6062ca5e00 is 23sec old was allocated at ip ffffffff98090e8f
obj 0xffff8d5f80161780 is 6sec old was allocated at ip ffffffff98090e8f

Kepiye hubungane program ruang pangguna lan program eBPF? Ing initialization tracex4_user.c ngemot file obyek tracex4_kern.o nggunakake fungsi load_bpf_file.

int main(int ac, char **argv)
{
    struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
    char filename[256];
    int i;

    snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);

    if (setrlimit(RLIMIT_MEMLOCK, &r)) {
        perror("setrlimit(RLIMIT_MEMLOCK, RLIM_INFINITY)");
        return 1;
    }

    if (load_bpf_file(filename)) {
        printf("%s", bpf_log_buf);
        return 1;
    }

    for (i = 0; ; i++) {
        print_old_objects(map_fd[1]);
        sleep(1);
    }

    return 0;
}

Nalika nindakake load_bpf_file probe sing ditetepake ing file eBPF ditambahake /sys/kernel/debug/tracing/kprobe_events. Saiki kita ngrungokake acara kasebut lan program kita bisa nindakake apa wae nalika kedadeyan.

$ sudo cat /sys/kernel/debug/tracing/kprobe_events
p:kprobes/kmem_cache_free kmem_cache_free
r:kprobes/kmem_cache_alloc_node kmem_cache_alloc_node

Kabeh program liyane ing sampel/bpf/ disusun kanthi cara sing padha. Padha tansah ngemot rong file:

  • XXX_kern.c: Program eBPF.
  • XXX_user.c: program utama.

Program eBPF ngenali peta lan fungsi sing ana gandhengane karo bagean. Nalika kernel ngetokake acara saka jinis tartamtu (contone, tracepoint), fungsi bound dieksekusi. Kertu kasebut nyedhiyakake komunikasi antarane program kernel lan program ruang pangguna.

kesimpulan

Artikel iki mbahas BPF lan eBPF ing istilah umum. Aku ngerti ana akeh informasi lan sumber daya babagan eBPF saiki, mula aku bakal menehi saran sawetara sumber daya liyane kanggo sinau luwih

Aku nyaranake maca:

Source: www.habr.com

Add a comment