BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Sa sinugdanan adunay usa ka teknolohiya ug kini gitawag nga BPF. Gitan-aw namo siya nauna, Daang Tugon nga artikulo niini nga serye. Sa 2013, pinaagi sa mga paningkamot ni Alexei Starovoitov ug Daniel Borkman, usa ka gipaayo nga bersyon niini, na-optimize alang sa modernong 64-bit nga mga makina, naugmad ug gilakip sa Linux kernel. Kining bag-ong teknolohiya gitawag ug Internal nga BPF, unya giilisan ang ngalan nga Extended BPF, ug karon, human sa pipila ka tuig, ang tanan nagtawag niini nga BPF.

Sa kasagaran nga pagsulti, ang BPF nagtugot kanimo sa pagpadagan sa arbitraryong code nga gihatag sa user sa Linux kernel space, ug ang bag-ong arkitektura nahimong malampuson kaayo nga nagkinahanglan kami og usa ka dosena nga mga artikulo aron ihulagway ang tanan nga mga aplikasyon niini. (Ang bugtong butang nga dili maayo nga nahimo sa mga developer, ingon sa imong makita sa performance code sa ubos, mao ang paghimo og usa ka desente nga logo.)

Kini nga artikulo naghulagway sa istruktura sa BPF virtual machine, kernel interface alang sa pagtrabaho uban sa BPF, development tools, ingon man sa usa ka mubo, mubo kaayo nga overview sa kasamtangan nga mga kapabilidad, i.e. tanan nga atong gikinahanglan sa umaabot alang sa mas lawom nga pagtuon sa praktikal nga aplikasyon sa BPF.
BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Sumaryo sa artikulo

Pasiuna sa arkitektura sa BPF. Una, magtan-aw kita sa arkitektura sa BPF ug maglatid sa mga nag-unang sangkap.

Mga rehistro ug command system sa BPF virtual machine. Naa nay ideya sa arkitektura sa kinatibuk-an, atong ihulagway ang istruktura sa BPF virtual machine.

Siklo sa kinabuhi sa BPF nga mga butang, bpffs file system. Niini nga seksyon, atong susihon pag-ayo ang siklo sa kinabuhi sa mga butang sa BPF - mga programa ug mapa.

Pagdumala sa mga butang gamit ang bpf system call. Uban sa pipila ka pagsabut sa sistema nga anaa na sa lugar, sa katapusan atong tan-awon kung giunsa paghimo ug pagmaniobra ang mga butang gikan sa wanang sa gumagamit gamit ang usa ka espesyal nga tawag sa sistema − bpf(2).

Пишем программы BPF с помощью libbpf. Siyempre, mahimo nimong isulat ang mga programa gamit ang usa ka tawag sa sistema. Pero lisod. Para sa mas realistiko nga senaryo, ang mga programmer nga nukleyar naghimo sing librarya libbpf. Maghimo kami usa ka sukaranan nga kalabera sa aplikasyon sa BPF nga among gamiton sa sunod nga mga pananglitan.

Mga Katabang sa Kernel. Dinhi atong mahibal-an kung giunsa ang mga programa sa BPF maka-access sa mga function sa katabang sa kernel - usa ka himan nga, kauban ang mga mapa, sukaranan nga nagpalapad sa mga kapabilidad sa bag-ong BPF kumpara sa usa nga klasiko.

Pag-access sa mga mapa gikan sa mga programa sa BPF. Niini nga punto, igo na ang atong nahibal-an aron masabtan kung giunsa nato paghimo ang mga programa nga naggamit sa mga mapa. Ug ato pa gani tan-awon dayon ang bantugan ug gamhanang verifier.

Mga galamiton sa pagpalambo. Tabang nga seksyon kung giunsa pag-assemble ang gikinahanglan nga mga utilities ug kernel alang sa mga eksperimento.

Ang konklusyon. Sa kataposan sa artikulo, kadtong nagbasa niini nga layo makakitag makapadasig nga mga pulong ug mubong kahubitan kon unsay mahitabo sa sunod nga mga artikulo. Maglista usab kami og ubay-ubay nga mga link alang sa self-study alang niadtong walay tinguha o abilidad sa paghulat sa pagpadayon.

Pasiuna sa BPF Architecture

Sa dili pa nato sugdan ang pagkonsiderar sa arkitektura sa BPF, atong hisgotan ang kataposang higayon (oh). klasiko nga BPF, nga naugmad isip tubag sa pag-abot sa mga makina sa RISC ug nasulbad ang problema sa episyente nga packet filtering. Ang arkitektura nahimong malampuson kaayo nga, nga natawo sa dashing nineties sa Berkeley UNIX, kini gibalhin ngadto sa kadaghanan sa kasamtangan nga mga operating system, naluwas ngadto sa buang nga twenties ug sa gihapon sa pagpangita sa bag-ong mga aplikasyon.

Ang bag-ong BPF gimugna isip tubag sa ubiquity sa 64-bit machines, cloud services ug ang dugang nga panginahanglan alang sa mga himan sa paghimo sa SDN (Skasagarang-defined networking). Gipalambo sa mga inhenyero sa kernel network isip usa ka gipaayo nga kapuli sa klasiko nga BPF, ang bag-ong BPF literal nga unom ka bulan ang milabay nakit-an ang mga aplikasyon sa lisud nga tahas sa pagsubay sa mga sistema sa Linux, ug karon, unom ka tuig pagkahuman sa hitsura niini, kinahanglan namon ang usa ka tibuuk nga sunod nga artikulo aron lang ilista ang lain-laing matang sa mga programa.

Kataw-anan nga mga hulagway

Sa kinauyokan niini, ang BPF usa ka sandbox virtual machine nga nagtugot kanimo sa pagpadagan sa "arbitraryong" code sa kernel space nga walay pagkompromiso sa seguridad. Ang mga programa sa BPF gihimo sa wanang sa tiggamit, gikarga sa kernel, ug konektado sa pipila nga gigikanan sa panghitabo. Ang usa ka panghitabo mahimong, pananglitan, ang paghatud sa usa ka pakete sa usa ka interface sa network, ang paglansad sa pipila nga function sa kernel, ug uban pa. Sa kaso sa usa ka pakete, ang BPF nga programa adunay access sa data ug metadata sa package (alang sa pagbasa ug, posible, pagsulat, depende sa matang sa programa); sa kaso sa pagpadagan sa kernel function, ang mga argumento sa ang function, lakip ang mga pointer sa memorya sa kernel, ug uban pa.

Atong tan-awon pag-ayo kini nga proseso. Sa pagsugod, maghisgot kita bahin sa una nga kalainan gikan sa klasiko nga BPF, mga programa nga gisulat sa assembler. Sa bag-ong bersyon, ang arkitektura gipalapdan aron ang mga programa masulat sa taas nga lebel nga mga pinulongan, ilabina, siyempre, sa C. Alang niini, usa ka backend alang sa llvm ang naugmad, nga nagtugot kanimo sa pagmugna og bytecode alang sa arkitektura sa BPF.

BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Ang arkitektura sa BPF gidisenyo, sa bahin, aron modagan nga episyente sa modernong mga makina. Aron mahimo kini nga buhat sa praktis, ang BPF bytecode, sa higayon nga gikarga sa kernel, gihubad ngadto sa lumad nga code gamit ang usa ka component nga gitawag ug JIT compiler (JUST In Time). Sunod, kung mahinumduman nimo, sa klasiko nga BPF ang programa gikarga sa kernel ug gilakip sa gigikanan sa panghitabo atomically - sa konteksto sa usa ka tawag sa sistema. Sa bag-ong arkitektura, kini mahitabo sa duha ka yugto - una, ang code gikarga sa kernel gamit ang usa ka tawag sa sistema bpf(2)ug unya, sa ulahi, pinaagi sa ubang mga mekanismo nga lainlain depende sa klase sa programa, ang programa motapot sa tinubdan sa panghitabo.

Dinhi ang magbabasa mahimong adunay pangutana: posible ba? Sa unsang paagi gigarantiyahan ang kaluwasan sa pagpatuman sa maong code? Ang kaluwasan sa pagpatuman gigarantiyahan kanamo pinaagi sa yugto sa pagkarga sa mga programa sa BPF nga gitawag ug verifier (sa English kini nga yugto gitawag ug verifier ug ako magpadayon sa paggamit sa English nga pulong):

BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Ang Verifier usa ka static nga analista nga nagsiguro nga ang usa ka programa dili makabalda sa normal nga operasyon sa kernel. Kini, sa paagi, wala magpasabut nga ang programa dili makabalda sa operasyon sa sistema - Ang mga programa sa BPF, depende sa tipo, makabasa ug makasulat pag-usab sa mga seksyon sa memorya sa kernel, ibalik ang mga kantidad sa mga function, trim, idugang, isulat pag-usab ug bisan pa sa forward network packets. Ang Verifier naggarantiya nga ang pagpadagan sa usa ka BPF nga programa dili maka-crash sa kernel ug nga ang usa ka programa nga, sumala sa mga lagda, adunay access sa pagsulat, pananglitan, ang datos sa usa ka outgoing packet, dili makahimo sa pag-overwrite sa kernel memory sa gawas sa pakete. Atong tan-awon ang verifier sa usa ka gamay nga dugang nga detalye sa katugbang nga seksyon, pagkahuman nga nahibal-an namon ang tanan nga uban pang mga sangkap sa BPF.

Busa unsa ang atong nakat-onan sa pagkakaron? Ang user nagsulat sa usa ka programa sa C, nagkarga niini sa kernel gamit ang usa ka tawag sa sistema bpf(2), diin kini gisusi sa usa ka verifier ug gihubad ngadto sa lumad nga bytecode. Unya ang parehas o lain nga tiggamit nagkonektar sa programa sa gigikanan sa panghitabo ug nagsugod kini sa pagpatuman. Ang pagbulag sa boot ug koneksyon gikinahanglan sa daghang mga hinungdan. Una, ang pagpadagan sa usa ka verifier medyo mahal ug pinaagi sa pag-download sa parehas nga programa sa daghang mga higayon nag-usik kami sa oras sa kompyuter. Ikaduha, eksakto kung giunsa ang pagkonektar sa usa ka programa nagdepende sa tipo niini, ug ang usa ka "unibersal" nga interface nga naugmad usa ka tuig ang milabay mahimong dili angay alang sa mga bag-ong tipo sa mga programa. (Bisan tuod karon nga ang arkitektura nahimong mas hamtong, adunay usa ka ideya sa paghiusa niini nga interface sa lebel libbpf.)

Ang matinagdanon nga magbabasa mahimong makamatikod nga wala pa kami nahuman sa mga litrato. Sa tinuud, ang tanan sa ibabaw wala nagpatin-aw kung giunsa pagbag-o sa BPF ang litrato kung itandi sa klasiko nga BPF. Duha ka mga kabag-ohan nga labi nga nagpalapad sa sakup sa pagpadapat mao ang katakus sa paggamit sa gipaambit nga memorya ug mga function sa pagtabang sa kernel. Sa BPF, ang gipaambit nga panumduman gipatuman gamit ang gitawag nga mga mapa - gipaambit nga mga istruktura sa datos nga adunay usa ka piho nga API. Tingali nakuha nila kini nga ngalan tungod kay ang una nga tipo sa mapa nga makita usa ka lamesa sa hash. Unya mitungha ang mga arrays, local (per-CPU) hash tables ug local arrays, search trees, mga mapa nga adunay mga pointer sa BPF programs ug daghan pa. Ang nakapaikag kanamo karon mao nga ang mga programa sa BPF karon adunay katakus sa pagpadayon sa estado taliwala sa mga tawag ug ipaambit kini sa ubang mga programa ug sa wanang sa tiggamit.

Ang mga mapa ma-access gikan sa mga proseso sa user gamit ang usa ka tawag sa sistema bpf(2), ug gikan sa mga programa sa BPF nga nagdagan sa kernel gamit ang mga function sa katabang. Dugang pa, ang mga katabang anaa dili lamang sa pagtrabaho sa mga mapa, apan usab sa pag-access sa ubang mga kapabilidad sa kernel. Pananglitan, ang mga programa sa BPF makagamit sa mga function sa katabang sa pagpasa sa mga pakete sa ubang mga interface, pagmugna og perf nga mga panghitabo, pag-access sa mga istruktura sa kernel, ug uban pa.

BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Sa katingbanan, ang BPF naghatag ug katakus sa pagkarga sa arbitraryo, i.e., verifier-tested, user code ngadto sa kernel space. Kini nga code makaluwas sa estado tali sa mga tawag ug pagbayloay og data sa user space, ug usab adunay access sa kernel subsystems nga gitugotan niining matang sa programa.

Kini susama na sa mga kapabilidad nga gihatag sa kernel modules, kon itandi diin ang BPF adunay pipila ka mga bentaha (siyempre, mahimo ra nimo itandi ang susama nga mga aplikasyon, pananglitan, pagsubay sa sistema - dili ka makasulat sa usa ka arbitraryong drayber nga adunay BPF). Mahimo nimong matikdan ang usa ka ubos nga threshold sa pagsulod (pipila ka mga utilities nga naggamit sa BPF wala magkinahanglan nga ang tiggamit adunay mga kahanas sa kernel programming, o mga kahanas sa programming sa kinatibuk-an), kaluwasan sa runtime (ipataas ang imong kamot sa mga komento alang sa mga wala makaguba sa sistema sa pagsulat. o mga modulo sa pagsulay), atomicity - adunay downtime sa pag-reload sa mga module, ug ang subsystem sa BPF nagsiguro nga walay mga panghitabo nga gimingaw (aron patas, kini dili tinuod alang sa tanang matang sa mga programa sa BPF).

Ang presensya sa ingon nga mga kapabilidad naghimo sa BPF nga usa ka unibersal nga himan alang sa pagpalapad sa kernel, nga gipamatud-an sa praktis: nagkadaghan nga mga bag-ong klase sa mga programa ang gidugang sa BPF, nagkadaghan ang mga dagkong kompanya nga naggamit sa BPF sa mga server sa kombat 24 × 7, labi pa ug daghan pa. Ang mga startup nagtukod sa ilang negosyo sa mga solusyon nga gibase sa base sa BPF. Ang BPF gigamit bisan asa: sa pagpanalipod batok sa mga pag-atake sa DDoS, paghimo sa SDN (pananglitan, pagpatuman sa mga network alang sa mga kubernetes), isip ang nag-unang sistema sa pagsubay sa himan ug statistics collector, sa intrusion detection system ug sandbox system, ug uban pa.

Atong tapuson ang kinatibuk-ang bahin sa artikulo dinhi ug tan-awon ang virtual machine ug ang BPF ecosystem sa mas detalyado.

Digression: mga utilities

Aron makahimo sa pagpadagan sa mga panig-ingnan sa mosunod nga mga seksyon, tingali kinahanglan nimo ang daghang mga utilities, labing menos llvm/clang uban sa suporta sa bpf ug bpftool. Sa seksyon Mga Himan sa Pag-uswag Mahimo nimong basahon ang mga panudlo alang sa pag-assemble sa mga utilities, ingon man ang imong kernel. Kini nga seksyon gibutang sa ubos aron dili makabalda sa panag-uyon sa among presentasyon.

BPF Virtual Machine Registers ug Instruction System

Ang arkitektura ug sistema sa komand sa BPF gipalambo nga gikonsiderar ang kamatuoran nga ang mga programa isulat sa C nga sinultian ug, pagkahuman sa pagkarga sa kernel, gihubad sa lumad nga code. Busa, ang gidaghanon sa mga rehistro ug ang hugpong sa mga sugo gipili uban sa usa ka mata ngadto sa intersection, sa matematika nga diwa, sa mga kapabilidad sa modernong mga makina. Dugang pa, ang lainlaing mga pagdili gipahamtang sa mga programa, pananglitan, hangtod karon dili mahimo ang pagsulat sa mga loop ug subroutine, ug ang gidaghanon sa mga panudlo limitado sa 4096 (karon ang mga pribilehiyo nga programa mahimo’g mag-load hangtod sa usa ka milyon nga mga panudlo).

Ang BPF adunay onse ka user-accessible 64-bit registers r0-r10 ug usa ka counter sa programa. Pagrehistro r10 adunay usa ka frame pointer ug read-only. Ang mga programa adunay access sa usa ka 512-byte stack sa runtime ug usa ka walay kinutuban nga gidaghanon sa shared memory sa porma sa mga mapa.

Ang mga programa sa BPF gitugotan sa pagpadagan sa usa ka espesipikong set sa program-type kernel helpers ug, bag-o lang, regular nga mga gimbuhaton. Ang matag gitawag nga function mahimo’g hangtod sa lima ka mga argumento, gipasa sa mga rehistro r1-r5, ug ang bili sa pagbalik ipasa ngadto sa r0. Gigarantiyahan nga pagkahuman sa pagbalik gikan sa function, ang sulud sa mga rehistro r6-r9 Dili mausab.

Para sa episyente nga paghubad sa programa, mga rehistro r0-r11 kay ang tanan nga gisuportahan nga mga arkitektura talagsaon nga gimapa sa tinuod nga mga rehistro, nga gikonsiderar ang mga bahin sa ABI sa kasamtangang arkitektura. Pananglitan, alang sa x86_64 mga rehistro r1-r5, nga gigamit sa pagpasa sa mga parameter sa function, gipakita sa rdi, rsi, rdx, rcx, r8, nga gigamit sa pagpasa sa mga parameter sa mga function x86_64. Pananglitan, ang code sa wala gihubad ngadto sa code sa tuo sama niini:

1:  (b7) r1 = 1                    mov    $0x1,%rdi
2:  (b7) r2 = 2                    mov    $0x2,%rsi
3:  (b7) r3 = 3                    mov    $0x3,%rdx
4:  (b7) r4 = 4                    mov    $0x4,%rcx
5:  (b7) r5 = 5                    mov    $0x5,%r8
6:  (85) call pc+1                 callq  0x0000000000001ee8

Pagrehistro r0 gigamit usab aron ibalik ang resulta sa pagpatuman sa programa, ug sa rehistro r1 ang programa gipasa usa ka pointer sa konteksto - depende sa klase sa programa, mahimo kini, pananglitan, usa ka istruktura struct xdp_md (alang sa XDP) o istruktura struct __sk_buff (alang sa lain-laing mga programa sa network) o istruktura struct pt_regs (alang sa lain-laing matang sa mga programa sa pagsubay), ug uban pa.

Mao nga, kami adunay usa ka set sa mga rehistro, mga katabang sa kernel, usa ka stack, usa ka pointer sa konteksto ug gipaambit nga memorya sa porma sa mga mapa. Dili nga kining tanan gikinahanglan sa biyahe, apan...

Atong ipadayon ang paghulagway ug maghisgot bahin sa command system alang sa pagtrabaho uban niini nga mga butang. Tanan (Halos tanan) Ang mga instruksyon sa BPF adunay pirmi nga 64-bit nga gidak-on. Kung imong tan-awon ang usa ka panudlo sa usa ka 64-bit nga Big Endian nga makina imong makita

BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

kini mao ang Code - kini ang pag-encode sa panudlo, Dst/Src mao ang mga pag-encode sa tigdawat ug tinubdan, matag usa, Off - 16-bit nga gipirmahan nga indentation, ug Imm usa ka 32-bit nga gipirmahan nga integer nga gigamit sa pipila ka mga instruksyon (susama sa cBPF constant K). Pag-encode Code adunay usa sa duha ka matang:

BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Ang mga klase sa pagtudlo 0, 1, 2, 3 naghubit sa mga sugo alang sa pagtrabaho uban ang memorya. Sila gitawag, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, matag usa. Klase 4, 7 (BPF_ALU, BPF_ALU64) naglangkob sa usa ka hugpong sa mga instruksyon sa ALU. Klase 5, 6 (BPF_JMP, BPF_JMP32) adunay mga instruksyon sa paglukso.

Ang dugang nga plano alang sa pagtuon sa sistema sa panudlo sa BPF mao ang mga musunud: imbis nga makutihon nga paglista sa tanan nga mga panudlo ug ang ilang mga parameter, tan-awon namon ang usa ka pares nga mga pananglitan sa kini nga seksyon ug gikan kanila mahimong tin-aw kung giunsa ang paglihok sa mga panudlo ug kung giunsa mano-mano nga pag-disassemble sa bisan unsang binary file para sa BPF. Aron makonsolida ang materyal sa ulahi sa artikulo, makigtagbo usab kami sa mga indibidwal nga panudlo sa mga seksyon bahin sa Verifier, JIT compiler, paghubad sa klasiko nga BPF, ingon man usab sa pagtuon sa mga mapa, mga function sa pagtawag, ug uban pa.

Kung maghisgot kami bahin sa indibidwal nga mga panudlo, maghisgot kami sa kinauyokan nga mga file bpf.h и bpf_common.h, nga naghubit sa mga numerical code sa mga instruksyon sa BPF. Kung nagtuon ka sa arkitektura sa imong kaugalingon ug / o pag-parse sa mga binary, makit-an nimo ang mga semantiko sa mga musunud nga gigikanan, gisunud sa pagkakomplikado: Dili opisyal nga eBPF spec, BPF ug XDP Reference Guide, Instruction Set, Dokumentasyon/networking/filter.txt ug, siyempre, sa Linux source code - verifier, JIT, BPF interpreter.

Pananglitan: pagdisassemble sa BPF sa imong ulo

Atong tan-awon ang usa ka pananglitan diin kita nag-compile sa usa ka programa readelf-example.c ug tan-awa ang resulta nga binary. Atong ibutyag ang orihinal nga sulod readelf-example.c sa ubos, human nato ibalik ang lohika niini gikan sa binary code:

$ clang -target bpf -c readelf-example.c -o readelf-example.o -O2
$ llvm-readelf -x .text readelf-example.o
Hex dump of section '.text':
0x00000000 b7000000 01000000 15010100 00000000 ................
0x00000010 b7000000 02000000 95000000 00000000 ................

Unang kolum sa output readelf usa ka indentation ug ang among programa naglangkob sa upat ka mga sugo:

Code Dst Src Off  Imm
b7   0   0   0000 01000000
15   0   1   0100 00000000
b7   0   0   0000 02000000
95   0   0   0000 00000000

Ang mga command code managsama b7, 15, b7 и 95. Hinumdomi nga ang labing gamay nga hinungdanon nga tulo ka mga piraso mao ang klase sa panudlo. Sa among kaso, ang ikaupat nga bit sa tanan nga mga panudlo walay sulod, mao nga ang mga klase sa pagtudlo mao ang 7, 5, 7, 5, matag usa. Ang Klase 7 mao ang BPF_ALU64ug 5, BPF_JMP. Para sa duha ka klase, pareho ang format sa instruksiyon (tan-awa sa ibabaw) ug mahimo natong isulat pag-usab ang atong programa sama niini (sa samang higayon atong isulat pag-usab ang nahibiling mga kolum sa porma sa tawo):

Op S  Class   Dst Src Off  Imm
b  0  ALU64   0   0   0    1
1  0  JMP     0   1   1    0
b  0  ALU64   0   0   0    2
9  0  JMP     0   0   0    0

Operasyon b grade ALU64 Mao ba BPF_MOV. Naghatag kini og bili sa rehistro sa destinasyon. Kung ang bit gitakda s (tinubdan), unya ang kantidad gikuha gikan sa gigikanan nga rehistro, ug kung, sama sa among kaso, wala kini gitakda, nan ang kantidad gikuha gikan sa uma. Imm. Mao nga sa una ug ikatulo nga mga panudlo gihimo namon ang operasyon r0 = Imm. Dugang pa, ang JMP class 1 nga operasyon mao ang BPF_JEQ (ambak kon managsama). Sa among kaso, sukad sa gamay S mao ang zero, kini nagtandi sa bili sa tinubdan register uban sa uma Imm. Kung ang mga kantidad managsama, ang pagbalhin mahitabo sa PC + Offdiin PC, sama sa naandan, naglangkob sa adres sa sunod nga instruksiyon. Sa katapusan, ang JMP Class 9 Operation mao BPF_EXIT. Kini nga panudlo nagtapos sa programa, nga mobalik sa kernel r0. Magdugang ta ug bag-ong kolum sa among lamesa:

Op    S  Class   Dst Src Off  Imm    Disassm
MOV   0  ALU64   0   0   0    1      r0 = 1
JEQ   0  JMP     0   1   1    0      if (r1 == 0) goto pc+1
MOV   0  ALU64   0   0   0    2      r0 = 2
EXIT  0  JMP     0   0   0    0      exit

Mahimo natong isulat pag-usab kini sa mas sayon ​​nga porma:

     r0 = 1
     if (r1 == 0) goto END
     r0 = 2
END:
     exit

Kung atong mahinumduman kung unsa ang naa sa rehistro r1 ang programa gipasa usa ka pointer sa konteksto gikan sa kernel, ug sa rehistro r0 ang bili gibalik sa kernel, unya atong makita nga kung ang pointer sa konteksto zero, unya atong ibalik ang 1, ug kung dili - 2. Atong susihon nga kita husto pinaagi sa pagtan-aw sa tinubdan:

$ cat readelf-example.c
int foo(void *ctx)
{
        return ctx ? 2 : 1;
}

Oo, kini usa ka walay kahulogan nga programa, apan kini gihubad ngadto sa upat lamang ka yano nga mga instruksyon.

Exception nga pananglitan: 16-byte nga instruksyon

Among gihisgutan sa sayo pa nga ang pipila ka mga instruksyon nagkinahanglan og labaw pa sa 64 bits. Kini magamit, pananglitan, sa mga panudlo lddw (Kodigo = 0x18 = BPF_LD | BPF_DW | BPF_IMM) — load sa usa ka double pulong gikan sa mga uma ngadto sa rehistro Imm. Ang kamatuoran mao kana Imm adunay gidak-on nga 32, ug ang doble nga pulong mao ang 64 ka bit, busa ang pagkarga sa usa ka 64-bit nga diha-diha nga kantidad sa usa ka rehistro sa usa ka 64-bit nga panudlo dili molihok. Aron mahimo kini, duha ka kasikbit nga mga panudlo ang gigamit sa pagtipig sa ikaduha nga bahin sa 64-bit nga kantidad sa uma. Imm. Usa ka pananglitan:

$ cat x64.c
long foo(void *ctx)
{
        return 0x11223344aabbccdd;
}
$ clang -target bpf -c x64.c -o x64.o -O2
$ llvm-readelf -x .text x64.o
Hex dump of section '.text':
0x00000000 18000000 ddccbbaa 00000000 44332211 ............D3".
0x00000010 95000000 00000000                   ........

Adunay duha ra ka panudlo sa usa ka binary nga programa:

Binary                                 Disassm
18000000 ddccbbaa 00000000 44332211    r0 = Imm[0]|Imm[1]
95000000 00000000                      exit

Magkita kita pag-usab uban ang mga panudlo lddw, kung maghisgot kami bahin sa mga pagbalhin ug pagtrabaho sa mga mapa.

Pananglitan: pag-disassembling sa BPF gamit ang standard tools

Mao nga, nakakat-on kami sa pagbasa sa BPF binary code ug andam nga mag-parse sa bisan unsang panudlo kung kinahanglan. Bisan pa, angay nga isulti nga sa praktis mas sayon ​​​​ug mas paspas ang pag-disassemble sa mga programa gamit ang standard nga mga himan, pananglitan:

$ llvm-objdump -d x64.o

Disassembly of section .text:

0000000000000000 <foo>:
 0: 18 00 00 00 dd cc bb aa 00 00 00 00 44 33 22 11 r0 = 1234605617868164317 ll
 2: 95 00 00 00 00 00 00 00 exit

Lifecycle sa BPF nga mga butang, bpffs file system

(Ako unang nakakat-on sa pipila sa mga detalye nga gihulagway niini nga subseksyon gikan sa pagpuasa Alexei Starovoitov sa BPF Blog.)

Ang mga butang sa BPF - mga programa ug mga mapa - gihimo gikan sa wanang sa gumagamit gamit ang mga mando BPF_PROG_LOAD и BPF_MAP_CREATE tawag sa sistema bpf(2), maghisgot kita bahin sa eksakto kung giunsa kini mahitabo sa sunod nga seksyon. Naghimo kini og mga istruktura sa datos sa kernel ug alang sa matag usa niini refcount (ihap sa pakisayran) gibutang sa usa, ug usa ka deskriptor sa file nga nagpunting sa butang ibalik sa tiggamit. Human masira ang kuptanan refcount ang butang mikunhod sa usa, ug kung kini moabut sa zero, ang butang malaglag.

Kung ang programa naggamit sa mga mapa, nan refcount kini nga mga mapa nadugangan sa usa pagkahuman sa pagkarga sa programa, i.e. ang ilang mga file descriptor mahimong sirado gikan sa proseso sa user ug sa gihapon refcount dili mahimong zero:

BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Pagkahuman sa malampuson nga pagkarga sa usa ka programa, kasagaran namong ilakip kini sa usa ka matang sa generator sa panghitabo. Pananglitan, mahimo natong ibutang kini sa usa ka interface sa network aron maproseso ang umaabot nga mga pakete o makonektar kini sa pipila tracepoint sa kinauyokan. Niini nga punto, ang reference counter modaghan usab ug usa ug mahimo namong isira ang file descriptor sa loader program.

Unsa ang mahitabo kung atong isira ang bootloader? Nagdepende kini sa matang sa generator sa panghitabo (hook). Ang tanan nga mga kaw-it sa network maglungtad pagkahuman makompleto ang loader, kini ang gitawag nga global nga mga kaw-it. Ug, pananglitan, ang mga programa sa pagsubay ipagawas pagkahuman matapos ang proseso nga nagmugna kanila (ug busa gitawag nga lokal, gikan sa "lokal hangtod sa proseso"). Sa teknikal nga paagi, ang mga lokal nga kaw-it kanunay adunay usa ka katugbang nga file descriptor sa wanang sa gumagamit ug busa hapit kung ang proseso sirado, apan ang mga global nga kaw-it wala. Sa mosunud nga numero, gamit ang pula nga mga krus, gisulayan nako nga ipakita kung giunsa ang pagtapos sa programa sa loader makaapekto sa kinabuhi sa mga butang sa kaso sa lokal ug global nga mga kaw-it.

BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Ngano nga adunay kalainan tali sa lokal ug global nga mga kaw-it? Ang pagpadagan sa pipila ka mga matang sa mga programa sa network makatarunganon nga walay usa ka userspace, pananglitan, hunahunaa ang proteksyon sa DDoS - ang bootloader nagsulat sa mga lagda ug nagkonektar sa BPF nga programa ngadto sa network interface, nga human niana ang bootloader mahimong moadto ug mopatay sa iyang kaugalingon. Sa laing bahin, hunahunaa ang usa ka debugging trace program nga imong gisulat sa imong tuhod sa napulo ka minuto - kung nahuman na, gusto nimo nga wala’y basura nga nahabilin sa sistema, ug ang mga lokal nga kaw-it ang makasiguro niana.

Sa laing bahin, hunahunaa nga gusto nimo nga makonektar sa usa ka tracepoint sa kernel ug mangolekta mga estadistika sa daghang mga tuig. Sa kini nga kaso, gusto nimo nga makompleto ang bahin sa tiggamit ug mobalik sa estadistika matag karon ug unya. Ang bpf file system naghatag niini nga oportunidad. Kini usa ka in-memorya nga pseudo-file system nga nagtugot sa paghimo sa mga file nga nag-refer sa mga butang sa BPF ug sa ingon nagdugang. refcount mga butang. Pagkahuman niini, ang loader mahimong mogawas, ug ang mga butang nga gihimo niini magpabilin nga buhi.

BPF alang sa mga gagmay, bahin sa usa: gipalugway nga BPF

Ang paghimo og mga file sa mga bpff nga nag-refer sa mga butang sa BPF gitawag nga "pinning" (sama sa mosunod nga hugpong sa mga pulong: "ang proseso mahimong mag-pin sa usa ka BPF nga programa o mapa"). Ang paghimo og mga file nga mga butang alang sa mga butang sa BPF makatarunganon dili lamang sa pagpalugway sa kinabuhi sa lokal nga mga butang, kondili alang usab sa usability sa global nga mga butang - balik sa panig-ingnan sa global nga programa sa pagpanalipod sa DDoS, gusto namong makaadto ug motan-aw sa mga estadistika matag karon ug unya.

Ang BPF file system kasagarang gi-mount /sys/fs/bpf, apan mahimo usab kini i-mount sa lokal, pananglitan, sama niini:

$ mkdir bpf-mountpoint
$ sudo mount -t bpf none bpf-mountpoint

Ang mga ngalan sa file system gihimo gamit ang command BPF_OBJ_PIN BPF sistema nga tawag. Sa pag-ilustrar, magkuha kita og usa ka programa, i-compile kini, i-upload kini, ug i-pin kini sa bpffs. Wala’y mahimo ang among programa nga mapuslanon, gipresentar lang namon ang code aron mahimo nimo nga kopyahon ang pananglitan:

$ cat test.c
__attribute__((section("xdp"), used))
int test(void *ctx)
{
        return 0;
}

char _license[] __attribute__((section("license"), used)) = "GPL";

Himoon nato kini nga programa ug maghimo og lokal nga kopya sa file system bpffs:

$ clang -target bpf -c test.c -o test.o
$ mkdir bpf-mountpoint
$ sudo mount -t bpf none bpf-mountpoint

Karon atong i-download ang atong programa gamit ang utility bpftool ug tan-awa ang nag-uban nga mga tawag sa sistema bpf(2) (pipila ka walay kalabotan nga linya gikuha gikan sa strace output):

$ sudo strace -e bpf bpftool prog load ./test.o bpf-mountpoint/test
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, prog_name="test", ...}, 120) = 3
bpf(BPF_OBJ_PIN, {pathname="bpf-mountpoint/test", bpf_fd=3}, 120) = 0

Dinhi among gikarga ang programa gamit BPF_PROG_LOAD, nakadawat usa ka deskriptor sa file gikan sa kernel 3 ug gamit ang command BPF_OBJ_PIN gi-pin kini nga file descriptor isip usa ka file "bpf-mountpoint/test". Human niini ang bootloader nga programa bpftool nahuman na sa pagtrabaho, apan ang among programa nagpabilin sa kernel, bisan kung wala namon kini gilakip sa bisan unsang interface sa network:

$ sudo bpftool prog | tail -3
783: xdp  name test  tag 5c8ba0cf164cb46c  gpl
        loaded_at 2020-05-05T13:27:08+0000  uid 0
        xlated 24B  jited 41B  memlock 4096B

Mahimo natong papason ang file object sa kasagaran unlink(2) ug human niana ang katugbang nga programa mapapas:

$ sudo rm ./bpf-mountpoint/test
$ sudo bpftool prog show id 783
Error: get by id (783): No such file or directory

Pagtangtang sa mga butang

Naghisgot bahin sa pagtangtang sa mga butang, kinahanglan nga ipatin-aw nga pagkahuman namon madiskonekta ang programa gikan sa kaw-it (generator sa panghitabo), wala’y bisan usa ka bag-ong panghitabo nga mag-aghat sa paglansad niini, bisan pa, ang tanan nga karon nga mga higayon sa programa makompleto sa normal nga pagkasunud. .

Ang pipila ka mga matang sa mga programa sa BPF nagtugot kanimo sa pag-ilis sa programa sa langaw, i.e. paghatag og sequence atomicity replace = detach old program, attach new program. Sa kini nga kaso, ang tanan nga aktibo nga mga higayon sa daan nga bersyon sa programa makatapos sa ilang trabaho, ug ang mga bag-ong tigdumala sa panghitabo pagahimoon gikan sa bag-ong programa, ug ang "atomicity" dinhi nagpasabut nga wala’y bisan usa ka panghitabo nga makalimtan.

Pagdugtong sa mga programa sa mga tinubdan sa panghitabo

Niini nga artikulo, dili kami maglainlain nga ihulagway ang pagkonektar sa mga programa sa mga gigikanan sa panghitabo, tungod kay makatarunganon nga tun-an kini sa konteksto sa usa ka piho nga klase sa programa. Cm. usa ka panig-ingnan sa ubos, diin among gipakita kung giunsa ang mga programa sama sa XDP konektado.

Pagmaniobra sa mga Butang Gamit ang bpf System Call

Mga programa sa BPF

Ang tanan nga mga butang sa BPF gihimo ug gidumala gikan sa wanang sa gumagamit gamit ang usa ka tawag sa sistema bpf, nga adunay mosunod nga prototype:

#include <linux/bpf.h>

int bpf(int cmd, union bpf_attr *attr, unsigned int size);

Ania ang team cmd usa sa mga kantidad sa tipo enum bpf_cmd, attr - usa ka pointer sa mga parameter alang sa usa ka piho nga programa ug size - gidak-on sa butang sumala sa pointer, i.e. kasagaran niini sizeof(*attr). Sa kernel 5.8 ang tawag sa sistema bpf nagsuporta sa 34 lain-laing mga sugo, ug kahulugan union bpf_attr nag-okupar sa 200 ka linya. Apan dili kita angay nga mahadlok niini, tungod kay kita mahimong pamilyar sa atong mga kaugalingon sa mga sugo ug mga parameter sa dagan sa daghang mga artikulo.

Magsugod ta sa team BPF_PROG_LOAD, nga nagmugna sa mga programa sa BPF - nagkuha usa ka set sa mga panudlo sa BPF ug gikarga kini sa kernel. Sa panahon sa pagkarga, ang verifier gilunsad, ug dayon ang JIT compiler ug, human sa malampuson nga pagpatuman, ang program file descriptor ibalik sa user. Nakita namon ang sunod nga nahitabo kaniya sa miaging seksyon mahitungod sa siklo sa kinabuhi sa mga butang sa BPF.

Magsulat kami karon ug usa ka naandan nga programa nga magkarga sa usa ka yano nga programa sa BPF, apan kinahanglan una namon nga magdesisyon kung unsang klase nga programa ang gusto namon i-load - kinahanglan namon nga pilion type sa ug sulod sa gambalay niini nga matang, pagsulat ug programa nga mopasar sa verifier test. Bisan pa, aron dili makomplikado ang proseso, ania ang usa ka andam nga solusyon: magkuha kami usa ka programa sama BPF_PROG_TYPE_XDP, nga ibalik ang bili XDP_PASS (laktawan ang tanan nga pakete). Sa BPF assembler kini tan-awon nga yano kaayo:

r0 = 2
exit

After namo naka decide nga kami mag-upload, makasulti kami kanimo kung giunsa namo kini buhaton:

#define _GNU_SOURCE
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/bpf.h>

static inline __u64 ptr_to_u64(const void *ptr)
{
        return (__u64) (unsigned long) ptr;
}

int main(void)
{
    struct bpf_insn insns[] = {
        {
            .code = BPF_ALU64 | BPF_MOV | BPF_K,
            .dst_reg = BPF_REG_0,
            .imm = XDP_PASS
        },
        {
            .code = BPF_JMP | BPF_EXIT
        },
    };

    union bpf_attr attr = {
        .prog_type = BPF_PROG_TYPE_XDP,
        .insns     = ptr_to_u64(insns),
        .insn_cnt  = sizeof(insns)/sizeof(insns[0]),
        .license   = ptr_to_u64("GPL"),
    };

    strncpy(attr.prog_name, "woo", sizeof(attr.prog_name));
    syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));

    for ( ;; )
        pause();
}

Ang makapainteres nga mga panghitabo sa usa ka programa nagsugod sa kahulugan sa usa ka laray insns - among BPF nga programa sa machine code. Sa kini nga kaso, ang matag panudlo sa programa sa BPF giputos sa istruktura bpf_insn. Unang elemento insns nagsunod sa mga instruksyon r0 = 2, ang ikaduha - exit.

Pag-atras. Ang kernel naghubit sa mas sayon ​​​​nga macros alang sa pagsulat sa mga code sa makina, ug gamit ang kernel header file tools/include/linux/filter.h makasulat kami

struct bpf_insn insns[] = {
    BPF_MOV64_IMM(BPF_REG_0, XDP_PASS),
    BPF_EXIT_INSN()
};

Apan tungod kay ang pagsulat sa mga programa sa BPF sa lumad nga kodigo gikinahanglan lamang alang sa pagsulat sa mga pagsulay sa kernel ug mga artikulo mahitungod sa BPF, ang pagkawala niini nga mga macro dili gayud makapakomplikado sa kinabuhi sa developer.

Pagkahuman sa pagtino sa programa sa BPF, nagpadayon kami sa pagkarga niini sa kernel. Ang among minimalist nga set sa mga parameter attr naglakip sa matang sa programa, set ug gidaghanon sa mga instruksyon, gikinahanglang lisensya, ug ngalan "woo", nga among gigamit sa pagpangita sa among programa sa sistema human sa pag-download. Ang programa, ingon sa gisaad, gikarga sa sistema gamit ang usa ka tawag sa sistema bpf.

Sa katapusan sa programa kita matapos sa usa ka walay katapusan nga loop nga simulate sa payload. Kung wala kini, ang programa mapatay sa kernel kung ang file descriptor nga gibalik sa sistema nga tawag kanamo sirado bpf, ug dili nato kini makita sa sistema.

Aw, andam na kami alang sa pagsulay. Atong tigumon ug padaganon ang programa ubos stracearon masusi nga ang tanan nagtrabaho ingon nga kini kinahanglan:

$ clang -g -O2 simple-prog.c -o simple-prog

$ sudo strace ./simple-prog
execve("./simple-prog", ["./simple-prog"], 0x7ffc7b553480 /* 13 vars */) = 0
...
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, insn_cnt=2, insns=0x7ffe03c4ed50, license="GPL", log_level=0, log_size=0, log_buf=NULL, kern_version=KERNEL_V
ERSION(0, 0, 0), prog_flags=0, prog_name="woo", prog_ifindex=0, expected_attach_type=BPF_CGROUP_INET_INGRESS}, 72) = 3
pause(

Maayo ang tanan, bpf(2) mibalik sa gunitanan 3 kanamo ug kami miadto sa usa ka walay kinutuban nga loop uban sa pause(). Atong sulayan nga pangitaon ang atong programa sa sistema. Aron mahimo kini moadto kami sa laing terminal ug gamiton ang utility bpftool:

# bpftool prog | grep -A3 woo
390: xdp  name woo  tag 3b185187f1855c4c  gpl
        loaded_at 2020-08-31T24:66:44+0000  uid 0
        xlated 16B  jited 40B  memlock 4096B
        pids simple-prog(10381)

Nakita namon nga adunay usa ka loaded nga programa sa sistema woo kansang global ID mao ang 390 ug karon nagpadayon simple-prog adunay usa ka bukas nga deskriptor sa file nga nagtudlo sa programa (ug kung simple-prog tapuson ang trabaho, unya woo mawala). Sama sa gipaabot, ang programa woo nagkinahanglan og 16 bytes - duha ka instruksyon - sa binary codes sa BPF architecture, apan sa iyang lumad nga porma (x86_64) kini 40 bytes na. Atong tan-awon ang atong programa sa orihinal nga porma niini:

# bpftool prog dump xlated id 390
   0: (b7) r0 = 2
   1: (95) exit

walay surpresa. Karon atong tan-awon ang code nga gihimo sa JIT compiler:

# bpftool prog dump jited id 390
bpf_prog_3b185187f1855c4c_woo:
   0:   nopl   0x0(%rax,%rax,1)
   5:   push   %rbp
   6:   mov    %rsp,%rbp
   9:   sub    $0x0,%rsp
  10:   push   %rbx
  11:   push   %r13
  13:   push   %r14
  15:   push   %r15
  17:   pushq  $0x0
  19:   mov    $0x2,%eax
  1e:   pop    %rbx
  1f:   pop    %r15
  21:   pop    %r14
  23:   pop    %r13
  25:   pop    %rbx
  26:   leaveq
  27:   retq

dili kaayo epektibo alang sa exit(2), pero in fairness, simple ra kaayo ang atong programa, ug para sa mga non-trivial nga mga programa ang prologue ug epilogue nga gidugang sa JIT compiler, siyempre, gikinahanglan.

Mapa nga Kalabut sa

Ang mga programa sa BPF makagamit sa structured memory nga mga lugar nga ma-access sa uban nga BPF programs ug sa mga programa sa user space. Kini nga mga butang gitawag nga mga mapa ug sa kini nga seksyon ipakita namon kung giunsa kini pagmaniobra gamit ang usa ka tawag sa sistema bpf.

Ingnon ta dayon nga ang mga kapabilidad sa mga mapa dili limitado lamang sa pag-access sa shared memory. Adunay mga espesyal nga katuyoan nga mga mapa nga adunay sulud, pananglitan, mga punto sa mga programa sa BPF o mga punto sa mga interface sa network, mga mapa alang sa pagtrabaho sa mga panghitabo sa perf, ug uban pa. Dili nato sila hisgutan dinhi, aron dili malibog ang magbabasa. Gawas pa niini, gibalewala namon ang mga isyu sa pag-synchronize, tungod kay dili kini hinungdanon sa among mga pananglitan. Ang usa ka kompleto nga lista sa magamit nga mga tipo sa mapa makit-an sa <linux/bpf.h>, ug sa niini nga seksyon atong kuhaon ingon nga usa ka pananglitan ang una nga tipo sa kasaysayan, ang hash table BPF_MAP_TYPE_HASH.

Kung maghimo ka usa ka hash table sa, ingnon, C ++, imong isulti unordered_map<int,long> woo, nga sa Russian nagkahulogang “I need a table woo walay kinutuban nga gidak-on, kansang mga yawe kay sa matang int, ug ang mga kantidad mao ang tipo long" Aron makahimo og BPF hash table, kinahanglan natong buhaton ang parehas nga butang, gawas nga kinahanglan natong ipiho ang pinakataas nga gidak-on sa lamesa, ug imbis nga ipiho ang mga tipo sa mga yawe ug mga bili, kinahanglan natong ipiho ang ilang mga gidak-on sa bytes . Aron makahimo og mga mapa gamita ang command BPF_MAP_CREATE tawag sa sistema bpf. Atong tan-awon ang mas gamay o gamay nga programa nga nagmugna og mapa. Pagkahuman sa miaging programa nga nag-load sa mga programa sa BPF, kini kinahanglan nga yano ra kanimo:

$ cat simple-map.c
#define _GNU_SOURCE
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/bpf.h>

int main(void)
{
    union bpf_attr attr = {
        .map_type = BPF_MAP_TYPE_HASH,
        .key_size = sizeof(int),
        .value_size = sizeof(int),
        .max_entries = 4,
    };
    strncpy(attr.map_name, "woo", sizeof(attr.map_name));
    syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));

    for ( ;; )
        pause();
}

Dinhi among gihubit ang usa ka hugpong sa mga parameter attr, diin kami moingon nga "Kinahanglan ko ang usa ka hash nga lamesa nga adunay mga yawe ug mga kantidad sa gidak-on sizeof(int), diin ako makabutang ug labing taas nga upat ka elemento." Sa paghimo sa mga mapa sa BPF, mahimo nimong ipiho ang ubang mga parameter, pananglitan, sa parehas nga paagi sama sa pananglitan sa programa, gipiho namon ang ngalan sa butang ingon "woo".

Atong i-compile ug ipadagan ang programa:

$ clang -g -O2 simple-map.c -o simple-map
$ sudo strace ./simple-map
execve("./simple-map", ["./simple-map"], 0x7ffd40a27070 /* 14 vars */) = 0
...
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_HASH, key_size=4, value_size=4, max_entries=4, map_name="woo", ...}, 72) = 3
pause(

Ania ang tawag sa sistema bpf(2) gibalik kanamo ang numero sa mapa sa deskriptor 3 ug dayon ang programa, sama sa gipaabut, naghulat alang sa dugang nga mga panudlo sa tawag sa sistema pause(2).

Karon ipadala nato ang atong programa sa background o ablihi ang laing terminal ug tan-awon ang atong butang gamit ang utility bpftool (mahimo natong mailhan ang atong mapa gikan sa uban pinaagi sa ngalan niini):

$ sudo bpftool map
...
114: hash  name woo  flags 0x0
        key 4B  value 4B  max_entries 4  memlock 4096B
...

Ang numero 114 mao ang global ID sa atong butang. Ang bisan unsang programa sa sistema makagamit niini nga ID sa pag-abli sa kasamtangan nga mapa gamit ang command BPF_MAP_GET_FD_BY_ID tawag sa sistema bpf.

Karon makadula na kami sa among hash table. Atong tan-awon ang mga sulod niini:

$ sudo bpftool map dump id 114
Found 0 elements

Walay sulod. Atong ibutang ang bili niini hash[1] = 1:

$ sudo bpftool map update id 114 key 1 0 0 0 value 1 0 0 0

Atong tan-awon pag-usab ang lamesa:

$ sudo bpftool map dump id 114
key: 01 00 00 00  value: 01 00 00 00
Found 1 element

Hooray! Nakadugang kami usa ka elemento. Timan-i nga kinahanglan kitang magtrabaho sa lebel sa byte aron mahimo kini, tungod kay bptftool wala mahibal-an kung unsang klase ang mga kantidad sa lamesa sa hash. (Kini nga kahibalo mahimong ibalhin ngadto kaniya gamit ang BTF, apan labaw pa niana karon.)

Giunsa gyud pagbasa ug pagdugang sa bpftool ang mga elemento? Atong tan-awon ubos sa hood:

$ sudo strace -e bpf bpftool map dump id 114
bpf(BPF_MAP_GET_FD_BY_ID, {map_id=114, next_id=0, open_flags=0}, 120) = 3
bpf(BPF_MAP_GET_NEXT_KEY, {map_fd=3, key=NULL, next_key=0x55856ab65280}, 120) = 0
bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3, key=0x55856ab65280, value=0x55856ab652a0}, 120) = 0
key: 01 00 00 00  value: 01 00 00 00
bpf(BPF_MAP_GET_NEXT_KEY, {map_fd=3, key=0x55856ab65280, next_key=0x55856ab65280}, 120) = -1 ENOENT

Una among giablihan ang mapa pinaagi sa iyang global ID gamit ang command BPF_MAP_GET_FD_BY_ID и bpf(2) mibalik sa deskriptor 3 kanamo. Padayon sa paggamit sa sugo BPF_MAP_GET_NEXT_KEY among nakit-an ang unang yawe sa lamesa pinaagi sa pagpasa NULL isip usa ka pointer sa "kaniadto" nga yawe. Kung naa namo ang yawe mahimo namo BPF_MAP_LOOKUP_ELEMnga nagbalik sa usa ka kantidad sa usa ka pointer value. Ang sunod nga lakang mao ang among pagsulay sa pagpangita sa sunod nga elemento pinaagi sa pagpasa sa usa ka pointer sa kasamtangan nga yawe, apan ang among lamesa adunay usa lamang ka elemento ug ang sugo. BPF_MAP_GET_NEXT_KEY ningbalik ENOENT.

Okay, usbon nato ang bili pinaagi sa yawe 1, ingnon ta nga ang atong lohika sa negosyo nagkinahanglan nga magparehistro hash[1] = 2:

$ sudo strace -e bpf bpftool map update id 114 key 1 0 0 0 value 2 0 0 0
bpf(BPF_MAP_GET_FD_BY_ID, {map_id=114, next_id=0, open_flags=0}, 120) = 3
bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3, key=0x55dcd72be260, value=0x55dcd72be280, flags=BPF_ANY}, 120) = 0

Sama sa gipaabut, kini yano ra kaayo: ang mando BPF_MAP_GET_FD_BY_ID nagbukas sa among mapa pinaagi sa ID, ug ang mando BPF_MAP_UPDATE_ELEM gi-overwrite ang elemento.

Busa, human sa paghimo sa usa ka hash table gikan sa usa ka programa, kita makabasa ug makasulat sa mga sulod niini gikan sa lain. Timan-i nga kung nakahimo kami niini gikan sa command line, nan ang bisan unsang programa sa sistema makahimo niini. Dugang pa sa mga sugo nga gihulagway sa ibabaw, alang sa pagtrabaho sa mga mapa gikan sa user space, следующие:

  • BPF_MAP_LOOKUP_ELEM: pangitag bili pinaagi sa yawe
  • BPF_MAP_UPDATE_ELEM: pag-update/paghimo og bili
  • BPF_MAP_DELETE_ELEM: kuhaa ang yawe
  • BPF_MAP_GET_NEXT_KEY: pangitaa ang sunod (o una) nga yawe
  • BPF_MAP_GET_NEXT_ID: nagtugot kanimo sa pag-agi sa tanan nga anaa nga mga mapa, mao kana ang paagi niini bpftool map
  • BPF_MAP_GET_FD_BY_ID: pag-abli sa kasamtangan nga mapa pinaagi sa iyang global ID
  • BPF_MAP_LOOKUP_AND_DELETE_ELEM: atomically i-update ang bili sa usa ka butang ug ibalik ang daan
  • BPF_MAP_FREEZE: himoa nga dili mausab ang mapa gikan sa userspace (kini nga operasyon dili mabawi)
  • BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, BPF_MAP_UPDATE_BATCH, BPF_MAP_DELETE_BATCH: mga operasyong masa. Pananglitan, BPF_MAP_LOOKUP_AND_DELETE_BATCH - kini ang bugtong kasaligan nga paagi sa pagbasa ug pag-reset sa tanan nga mga kantidad gikan sa mapa

Dili tanan niini nga mga sugo nagtrabaho alang sa tanan nga mga matang sa mapa, apan sa kinatibuk-an nga pagtrabaho uban sa uban nga mga matang sa mga mapa gikan sa user luna tan-awon sama gayud sa pagtrabaho uban sa hash mga lamesa.

Alang sa pagkahan-ay, tapuson nato ang mga eksperimento sa hash table. Hinumdumi nga naghimo kami usa ka lamesa nga adunay sulud hangtod sa upat ka mga yawe? Atong idugang ang pipila pa ka elemento:

$ sudo bpftool map update id 114 key 2 0 0 0 value 1 0 0 0
$ sudo bpftool map update id 114 key 3 0 0 0 value 1 0 0 0
$ sudo bpftool map update id 114 key 4 0 0 0 value 1 0 0 0

Sa ingon nga layo sa ingon nga maayo:

$ sudo bpftool map dump id 114
key: 01 00 00 00  value: 01 00 00 00
key: 02 00 00 00  value: 01 00 00 00
key: 04 00 00 00  value: 01 00 00 00
key: 03 00 00 00  value: 01 00 00 00
Found 4 elements

Atong sulayan sa pagdugang og usa pa:

$ sudo bpftool map update id 114 key 5 0 0 0 value 1 0 0 0
Error: update failed: Argument list too long

Sama sa gipaabot, wala mi molampos. Atong tan-awon ang sayop sa mas detalyado:

$ sudo strace -e bpf bpftool map update id 114 key 5 0 0 0 value 1 0 0 0
bpf(BPF_MAP_GET_FD_BY_ID, {map_id=114, next_id=0, open_flags=0}, 120) = 3
bpf(BPF_OBJ_GET_INFO_BY_FD, {info={bpf_fd=3, info_len=80, info=0x7ffe6c626da0}}, 120) = 0
bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3, key=0x56049ded5260, value=0x56049ded5280, flags=BPF_ANY}, 120) = -1 E2BIG (Argument list too long)
Error: update failed: Argument list too long
+++ exited with 255 +++

Maayo ang tanan: sama sa gipaabut, ang team BPF_MAP_UPDATE_ELEM misulay sa paghimo og bag-o, ikalima, yawe, apan nahagsa E2BIG.

Busa, makahimo kami ug makakarga sa mga programa sa BPF, ingon man usab sa paghimo ug pagdumala sa mga mapa gikan sa wanang sa tiggamit. Karon makatarunganon nga tan-awon kung giunsa naton magamit ang mga mapa gikan sa mga programa sa BPF mismo. Mahimo natong hisgutan kini sa pinulongan nga lisud basahon nga mga programa sa mga macro code sa makina, apan sa pagkatinuod ang panahon miabut na aron ipakita kung giunsa ang mga programa sa BPF aktuwal nga gisulat ug gipadayon - gamit libbpf.

(Alang sa mga magbabasa nga wala matagbaw sa kakulang sa usa ka ubos nga lebel nga pananglitan: among analisahon sa detalye ang mga programa nga naggamit sa mga mapa ug mga function sa katabang nga gihimo gamit ang libbpf ug isulti kanimo kung unsa ang mahitabo sa lebel sa panudlo. Para sa mga magbabasa nga wala matagbaw kaayo, midugang kami usa ka panig-ingnan sa angay nga dapit sa artikulo.)

Pagsulat sa mga programa sa BPF gamit ang libbpf

Ang pagsulat sa mga programa sa BPF gamit ang mga code sa makina mahimong makaiikag lamang sa unang higayon, ug dayon ang pagkabusog. Niining higayona kinahanglan nimo nga ipunting ang imong atensyon llvm, nga adunay backend alang sa pagmugna og code alang sa arkitektura sa BPF, ingon man usa ka librarya libbpf, nga nagtugot kanimo sa pagsulat sa bahin sa gumagamit sa mga aplikasyon sa BPF ug pagkarga sa code sa mga programa sa BPF nga gihimo gamit ang llvm/clang.

Sa pagkatinuod, ingon sa atong makita niini ug sa sunod nga mga artikulo, libbpf daghan kaayo nga trabaho kung wala kini (o parehas nga mga himan - iproute2, libbcc, libbpf-go, ug uban pa) imposible nga mabuhi. Usa sa mga makapatay nga bahin sa proyekto libbpf mao ang BPF CO-RE (Compile Once, Run Everywhere) - usa ka proyekto nga nagtugot kanimo sa pagsulat sa mga programa sa BPF nga madaladala gikan sa usa ka kernel ngadto sa lain, nga adunay abilidad sa pagdagan sa lain-laing mga API (pananglitan, kung ang kernel structure mausab gikan sa bersyon sa bersyon). Aron makahimo sa pagtrabaho uban sa CO-RE, ang imong kernel kinahanglan nga gihugpong uban sa BTF nga suporta (among gihulagway kung unsaon pagbuhat niini sa seksyon Mga Himan sa Pag-uswag. Mahimo nimong susihon kung ang imong kernel gitukod gamit ang BTF o dili kaayo yano - pinaagi sa presensya sa mosunod nga file:

$ ls -lh /sys/kernel/btf/vmlinux
-r--r--r-- 1 root root 2.6M Jul 29 15:30 /sys/kernel/btf/vmlinux

Kini nga payl nagtipig og impormasyon mahitungod sa tanang matang sa datos nga gigamit sa kernel ug gigamit sa tanan natong mga pananglitan sa paggamit libbpf. Maghisgot kami sa detalye bahin sa CO-RE sa sunod nga artikulo, apan niining usa - paghimo lang sa imong kaugalingon nga usa ka kernel CONFIG_DEBUG_INFO_BTF.

librarya libbpf nagpuyo diha mismo sa direktoryo tools/lib/bpf kernel ug ang pagpalambo niini gihimo pinaagi sa mailing list [email protected]. Bisan pa, usa ka bulag nga repository ang gipadayon alang sa mga panginahanglanon sa mga aplikasyon nga nagpuyo sa gawas sa kernel https://github.com/libbpf/libbpf diin ang librarya sa kernel gisalamin alang sa pag-access sa pagbasa labi pa o dili kaayo.

Niini nga seksyon atong tan-awon kung giunsa nimo paghimo ang usa ka proyekto nga gigamit libbpf, isulat nato ang pipila (kapin o dili kaayo walay kahulogan) nga mga programa sa pagsulay ug analisahon sa detalye kung giunsa kini tanan. Kini magtugot kanamo sa mas sayon ​​nga pagpatin-aw sa mosunod nga mga seksyon kon sa unsang paagi ang mga programa sa BPF nakig-uban sa mga mapa, mga katabang sa kernel, BTF, ug uban pa.

Kasagaran nga gigamit ang mga proyekto libbpf pagdugang usa ka GitHub repository ingon usa ka git submodule, buhaton namon ang parehas:

$ mkdir /tmp/libbpf-example
$ cd /tmp/libbpf-example/
$ git init-db
Initialized empty Git repository in /tmp/libbpf-example/.git/
$ git submodule add https://github.com/libbpf/libbpf.git
Cloning into '/tmp/libbpf-example/libbpf'...
remote: Enumerating objects: 200, done.
remote: Counting objects: 100% (200/200), done.
remote: Compressing objects: 100% (103/103), done.
remote: Total 3354 (delta 101), reused 118 (delta 79), pack-reused 3154
Receiving objects: 100% (3354/3354), 2.05 MiB | 10.22 MiB/s, done.
Resolving deltas: 100% (2176/2176), done.

Pag-adto sa libbpf simple kaayo:

$ cd libbpf/src
$ mkdir build
$ OBJDIR=build DESTDIR=root make -s install
$ find root
root
root/usr
root/usr/include
root/usr/include/bpf
root/usr/include/bpf/bpf_tracing.h
root/usr/include/bpf/xsk.h
root/usr/include/bpf/libbpf_common.h
root/usr/include/bpf/bpf_endian.h
root/usr/include/bpf/bpf_helpers.h
root/usr/include/bpf/btf.h
root/usr/include/bpf/bpf_helper_defs.h
root/usr/include/bpf/bpf.h
root/usr/include/bpf/libbpf_util.h
root/usr/include/bpf/libbpf.h
root/usr/include/bpf/bpf_core_read.h
root/usr/lib64
root/usr/lib64/libbpf.so.0.1.0
root/usr/lib64/libbpf.so.0
root/usr/lib64/libbpf.a
root/usr/lib64/libbpf.so
root/usr/lib64/pkgconfig
root/usr/lib64/pkgconfig/libbpf.pc

Ang among sunod nga plano niini nga seksyon mao ang mosunod: magsulat kami og BPF nga programa sama sa BPF_PROG_TYPE_XDP, parehas sa miaging pananglitan, apan sa C, gi-compile namo kini gamit clang, ug pagsulat ug helper program nga magkarga niini sa kernel. Sa mosunod nga mga seksyon atong palapdan ang mga kapabilidad sa BPF nga programa ug sa katabang nga programa.

Pananglitan: paghimo sa usa ka bug-os nga aplikasyon gamit ang libbpf

Sa pagsugod, gigamit namon ang file /sys/kernel/btf/vmlinux, nga gihisgutan sa ibabaw, ug paghimo sa katumbas niini sa porma sa usa ka header file:

$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

Kini nga file magtipig sa tanan nga mga istruktura sa datos nga magamit sa among kernel, pananglitan, ingon niini kung giunsa ang paghubit sa header sa IPv4 sa kernel:

$ grep -A 12 'struct iphdr {' vmlinux.h
struct iphdr {
    __u8 ihl: 4;
    __u8 version: 4;
    __u8 tos;
    __be16 tot_len;
    __be16 id;
    __be16 frag_off;
    __u8 ttl;
    __u8 protocol;
    __sum16 check;
    __be32 saddr;
    __be32 daddr;
};

Karon atong isulat ang atong BPF nga programa sa C:

$ cat xdp-simple.bpf.c
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

SEC("xdp/simple")
int simple(void *ctx)
{
        return XDP_PASS;
}

char LICENSE[] SEC("license") = "GPL";

Bisan kung ang among programa nahimo nga yano ra kaayo, kinahanglan gihapon namon nga hatagan pagtagad ang daghang mga detalye. Una, ang una nga header file nga among gilakip mao ang vmlinux.h, nga bag-o lang namo namugna gamit bpftool btf dump - karon dili na namo kinahanglan nga i-install ang kernel-headers package aron mahibal-an kung unsa ang hitsura sa mga istruktura sa kernel. Ang mosunod nga header file moabut kanato gikan sa librarya libbpf. Karon kinahanglan ra naton kini aron mahibal-an ang macro SEC, nga nagpadala sa karakter sa angay nga seksyon sa ELF object file. Ang among programa naa sa seksyon xdp/simple, diin sa wala pa ang slash atong gihubit ang matang sa programa nga BPF - kini ang kombensiyon nga gigamit sa libbpf, base sa ngalan sa seksyon kini mopuli sa husto nga tipo sa pagsugod bpf(2). Ang programa sa BPF mismo mao C - yano kaayo ug naglangkob sa usa ka linya return XDP_PASS. Sa katapusan, usa ka bulag nga seksyon "license" naglangkob sa ngalan sa lisensya.

Mahimo natong i-compile ang atong programa gamit ang llvm/clang, version >= 10.0.0, o mas maayo pa, mas dako (tan-awa ang seksyon Mga Himan sa Pag-uswag):

$ clang --version
clang version 11.0.0 (https://github.com/llvm/llvm-project.git afc287e0abec710398465ee1f86237513f2b5091)
...

$ clang -O2 -g -c -target bpf -I libbpf/src/root/usr/include xdp-simple.bpf.c -o xdp-simple.bpf.o

Lakip sa mga makapaikag nga bahin: gipakita namon ang target nga arkitektura -target bpf ug ang dalan paingon sa mga ulohan libbpf, nga bag-o lang namo na-install. Usab, ayaw kalimti ang bahin sa -O2, kung wala kini nga kapilian mahimo ka nga adunay mga sorpresa sa umaabot. Atong tan-awon ang among code, nakahimo ba kami pagsulat sa programa nga among gusto?

$ llvm-objdump --section=xdp/simple --no-show-raw-insn -D xdp-simple.bpf.o

xdp-simple.bpf.o:       file format elf64-bpf

Disassembly of section xdp/simple:

0000000000000000 <simple>:
       0:       r0 = 2
       1:       exit

Oo, kini nagtrabaho! Karon, kami adunay usa ka binary file nga adunay programa, ug gusto namon nga maghimo usa ka aplikasyon nga magkarga niini sa kernel. Alang niini nga katuyoan ang librarya libbpf nagtanyag kanamo duha ka kapilian - gamita ang usa ka ubos nga lebel nga API o usa ka taas nga lebel nga API. Moadto kami sa ikaduhang paagi, tungod kay gusto namon nga makat-on unsaon pagsulat, pagkarga ug pagkonektar sa mga programa sa BPF nga adunay gamay nga paningkamot alang sa ilang sunod nga pagtuon.

Una, kinahanglan natong i-generate ang "skeleton" sa atong programa gikan sa binary niini gamit ang samang utility bpftool — ang Swiss kutsilyo sa BPF nga kalibutan (nga mahimong literal, tungod kay si Daniel Borkman, usa sa mga tiglalang ug tigmentinar sa BPF, Swiss):

$ bpftool gen skeleton xdp-simple.bpf.o > xdp-simple.skel.h

Sa file xdp-simple.skel.h naglangkob sa binary code sa among programa ug mga gimbuhaton alang sa pagdumala - pagkarga, pag-attach, pagtangtang sa among butang. Sa among yano nga kaso kini morag overkill, apan kini usab nagtrabaho sa kaso diin ang object file naglangkob sa daghang mga BPF nga mga programa ug mga mapa ug sa pag-load niining higanteng ELF kinahanglan lang nato nga makamugna ang kalabera ug tawagan ang usa o duha ka mga function gikan sa custom nga aplikasyon nga atong nagsulat Magpadayon ta karon.

Sa estrikto nga pagkasulti, ang among loader nga programa gamay ra:

#include <err.h>
#include <unistd.h>
#include "xdp-simple.skel.h"

int main(int argc, char **argv)
{
    struct xdp_simple_bpf *obj;

    obj = xdp_simple_bpf__open_and_load();
    if (!obj)
        err(1, "failed to open and/or load BPF objectn");

    pause();

    xdp_simple_bpf__destroy(obj);
}

kini mao ang struct xdp_simple_bpf gihubit sa file xdp-simple.skel.h ug naghulagway sa among object file:

struct xdp_simple_bpf {
    struct bpf_object_skeleton *skeleton;
    struct bpf_object *obj;
    struct {
        struct bpf_program *simple;
    } progs;
    struct {
        struct bpf_link *simple;
    } links;
};

Makita nato ang mga timailhan sa ubos nga lebel nga API dinhi: ang istruktura struct bpf_program *simple и struct bpf_link *simple. Ang una nga istruktura espesipikong naghulagway sa among programa, nga gisulat sa seksyon xdp/simple, ug ang ikaduha naghulagway kung giunsa ang programa nagkonektar sa tinubdan sa panghitabo.

function xdp_simple_bpf__open_and_load, nag-abli sa usa ka ELF nga butang, nag-parse niini, nagmugna sa tanan nga mga istruktura ug mga substructure (gawas sa programa, ang ELF naglakip usab sa ubang mga seksyon - data, readonly data, debugging nga impormasyon, lisensya, ug uban pa), ug dayon i-load kini sa kernel gamit ang usa ka sistema tawag bpf, nga atong masusi pinaagi sa pag-compile ug pagpadagan sa programa:

$ clang -O2 -I ./libbpf/src/root/usr/include/ xdp-simple.c -o xdp-simple ./libbpf/src/root/usr/lib64/libbpf.a -lelf -lz

$ sudo strace -e bpf ./xdp-simple
...
bpf(BPF_BTF_LOAD, 0x7ffdb8fd9670, 120)  = 3
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, insn_cnt=2, insns=0xdfd580, license="GPL", log_level=0, log_size=0, log_buf=NULL, kern_version=KERNEL_VERSION(5, 8, 0), prog_flags=0, prog_name="simple", prog_ifindex=0, expected_attach_type=0x25 /* BPF_??? */, ...}, 120) = 4

Atong tan-awon karon ang atong programa gamit bpftool. Pangitaon nato iyang ID:

# bpftool p | grep -A4 simple
463: xdp  name simple  tag 3b185187f1855c4c  gpl
        loaded_at 2020-08-01T01:59:49+0000  uid 0
        xlated 16B  jited 40B  memlock 4096B
        btf_id 185
        pids xdp-simple(16498)

ug dump (among gigamit ang pinamubo nga porma sa command bpftool prog dump xlated):

# bpftool p d x id 463
int simple(void *ctx):
; return XDP_PASS;
   0: (b7) r0 = 2
   1: (95) exit

Usa ka butang nga bag-o! Ang programa nag-imprinta og mga tipik sa atong C source file. Gihimo kini sa library libbpf, nga nakit-an ang seksyon sa debug sa binary, gihugpong kini sa usa ka butang nga BTF, gikarga kini sa kernel gamit ang BPF_BTF_LOAD, ug dayon gipiho ang resulta nga deskriptor sa file kung gikarga ang programa gamit ang mando BPG_PROG_LOAD.

Mga Katabang sa Kernel

Ang mga programa sa BPF mahimong magpadagan sa "gawas" nga mga gimbuhaton - mga katabang sa kernel. Gitugotan sa kini nga mga function sa katabang ang mga programa sa BPF nga ma-access ang mga istruktura sa kernel, pagdumala sa mga mapa, ug makigsulti usab sa "tinuod nga kalibutan" - paghimo mga panghitabo sa perf, pagkontrol sa hardware (pananglitan, pag-redirect sa mga pakete), ug uban pa.

Pananglitan: bpf_get_smp_processor_id

Sulod sa gambalay sa paradigm sa "pagkat-on pinaagi sa panig-ingnan", atong tagdon ang usa sa mga gimbuhaton sa katabang, bpf_get_smp_processor_id(), sigurado sa file kernel/bpf/helpers.c. Gibalik niini ang numero sa processor diin nagdagan ang programa sa BPF nga nagtawag niini. Apan dili kami interesado sa mga semantika niini sama sa kamatuoran nga ang pagpatuman niini nagkinahanglan og usa ka linya:

BPF_CALL_0(bpf_get_smp_processor_id)
{
    return smp_processor_id();
}

Ang BPF helper function definitions susama sa Linux system call definitions. Dinhi, pananglitan, ang usa ka function gihubit nga walay mga argumento. (Usa ka function nga nagkinahanglan, ingnon ta, tulo ka argumento ang gihubit gamit ang macro BPF_CALL_3. Ang maximum nga gidaghanon sa mga argumento mao ang lima.) Apan, kini mao lamang ang unang bahin sa kahulugan. Ang ikaduha nga bahin mao ang paghubit sa tipo nga istruktura struct bpf_func_proto, nga adunay usa ka paghulagway sa function sa katabang nga nasabtan sa verifier:

const struct bpf_func_proto bpf_get_smp_processor_id_proto = {
    .func     = bpf_get_smp_processor_id,
    .gpl_only = false,
    .ret_type = RET_INTEGER,
};

Pagparehistro sa Katabang Function

Aron magamit sa mga programa sa BPF sa usa ka partikular nga tipo kini nga function, kinahanglan nila nga irehistro kini, pananglitan alang sa tipo BPF_PROG_TYPE_XDP usa ka function ang gihubit sa kernel xdp_func_proto, nga nagtino gikan sa helper function ID kung ang XDP nagsuporta niini nga function o dili. Ang among function mao nagsuporta:

static const struct bpf_func_proto *
xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
    switch (func_id) {
    ...
    case BPF_FUNC_get_smp_processor_id:
        return &bpf_get_smp_processor_id_proto;
    ...
    }
}

Ang mga bag-ong tipo sa programa sa BPF "gihubit" sa file include/linux/bpf_types.h gamit ang macro BPF_PROG_TYPE. Gihubit sa mga kinutlo tungod kay kini usa ka lohikal nga kahulugan, ug sa mga termino sa C nga pinulongan ang kahulugan sa usa ka tibuuk nga hugpong sa mga konkretong istruktura mahitabo sa ubang mga lugar. Sa partikular, sa file kernel/bpf/verifier.c tanan nga mga kahulugan gikan sa file bpf_types.h gigamit sa paghimo sa usa ka han-ay sa mga istruktura bpf_verifier_ops[]:

static const struct bpf_verifier_ops *const bpf_verifier_ops[] = {
#define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) 
    [_id] = & _name ## _verifier_ops,
#include <linux/bpf_types.h>
#undef BPF_PROG_TYPE
};

Kana mao, alang sa matag matang sa programa sa BPF, usa ka pointer sa usa ka istruktura sa datos sa tipo ang gihubit struct bpf_verifier_ops, nga gisugdan sa kantidad _name ## _verifier_ops, sa ato pa, xdp_verifier_ops alang sa xdp. Istruktura xdp_verifier_ops nga gitino pinaagi sa file net/core/filter.c ingon sa mosunod:

const struct bpf_verifier_ops xdp_verifier_ops = {
    .get_func_proto     = xdp_func_proto,
    .is_valid_access    = xdp_is_valid_access,
    .convert_ctx_access = xdp_convert_ctx_access,
    .gen_prologue       = bpf_noop_prologue,
};

Dinhi atong makita ang atong pamilyar nga function xdp_func_proto, nga magpadagan sa verifier matag higayon nga makasugat kini og hagit pila ka klase naglihok sulod sa usa ka programa sa BPF, tan-awa verifier.c.

Atong tan-awon kung giunsa ang usa ka hypothetical nga BPF nga programa naggamit sa function bpf_get_smp_processor_id. Aron mahimo kini, among isulat pag-usab ang programa gikan sa among miaging seksyon sama sa mosunod:

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

SEC("xdp/simple")
int simple(void *ctx)
{
    if (bpf_get_smp_processor_id() != 0)
        return XDP_DROP;
    return XDP_PASS;
}

char LICENSE[] SEC("license") = "GPL";

Simbolo bpf_get_smp_processor_id nga gitino pinaagi в <bpf/bpf_helper_defs.h> mga librarya libbpf sa unsa nga paagi

static u32 (*bpf_get_smp_processor_id)(void) = (void *) 8;

mao, bpf_get_smp_processor_id mao ang usa ka function pointer kansang bili mao ang 8, diin 8 mao ang bili BPF_FUNC_get_smp_processor_id type enum bpf_fun_id, nga gihubit alang kanamo sa file vmlinux.h (file bpf_helper_defs.h sa kernel gihimo pinaagi sa usa ka script, mao nga ang "magic" nga mga numero ok). Kini nga function wala magkinahanglan og mga argumento ug nagbalik sa usa ka bili sa tipo __u32. Kung gipadagan namon kini sa among programa, clang nagmugna og instruksyon BPF_CALL "ang husto nga matang" Atong tigumon ang programa ug tan-awon ang seksyon xdp/simple:

$ clang -O2 -g -c -target bpf -I libbpf/src/root/usr/include xdp-simple.bpf.c -o xdp-simple.bpf.o
$ llvm-objdump -D --section=xdp/simple xdp-simple.bpf.o

xdp-simple.bpf.o:       file format elf64-bpf

Disassembly of section xdp/simple:

0000000000000000 <simple>:
       0:       85 00 00 00 08 00 00 00 call 8
       1:       bf 01 00 00 00 00 00 00 r1 = r0
       2:       67 01 00 00 20 00 00 00 r1 <<= 32
       3:       77 01 00 00 20 00 00 00 r1 >>= 32
       4:       b7 00 00 00 02 00 00 00 r0 = 2
       5:       15 01 01 00 00 00 00 00 if r1 == 0 goto +1 <LBB0_2>
       6:       b7 00 00 00 01 00 00 00 r0 = 1

0000000000000038 <LBB0_2>:
       7:       95 00 00 00 00 00 00 00 exit

Sa unang linya atong makita ang mga instruksyon call, parametro IMM nga katumbas sa 8, ug SRC_REG - sero. Sumala sa kasabutan sa ABI nga gigamit sa verifier, kini usa ka tawag sa helper function number otso. Sa higayon nga kini gilusad, ang lohika mao ang yano. Ibalik ang bili gikan sa rehistro r0 gikopya sa r1 ug sa mga linya 2,3 kini nakabig ngadto sa tipo u32 - ang ibabaw nga 32 bits gilimpyohan. Sa linya 4,5,6,7 mibalik kami sa 2 (XDP_PASS) o 1 (XDP_DROP) depende kung ang function sa helper gikan sa linya 0 mibalik sa usa ka zero o dili-zero nga kantidad.

Atong sulayan ang atong kaugalingon: i-load ang programa ug tan-awon ang output bpftool prog dump xlated:

$ bpftool gen skeleton xdp-simple.bpf.o > xdp-simple.skel.h
$ clang -O2 -g -I ./libbpf/src/root/usr/include/ -o xdp-simple xdp-simple.c ./libbpf/src/root/usr/lib64/libbpf.a -lelf -lz
$ sudo ./xdp-simple &
[2] 10914

$ sudo bpftool p | grep simple
523: xdp  name simple  tag 44c38a10c657e1b0  gpl
        pids xdp-simple(10915)

$ sudo bpftool p d x id 523
int simple(void *ctx):
; if (bpf_get_smp_processor_id() != 0)
   0: (85) call bpf_get_smp_processor_id#114128
   1: (bf) r1 = r0
   2: (67) r1 <<= 32
   3: (77) r1 >>= 32
   4: (b7) r0 = 2
; }
   5: (15) if r1 == 0x0 goto pc+1
   6: (b7) r0 = 1
   7: (95) exit

Ok, ang verifier nakit-an ang husto nga kernel-helper.

Pananglitan: pagpasa sa mga argumento ug sa katapusan pagpadagan sa programa!

Ang tanan nga run-level helper function adunay prototype

u64 fn(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)

Ang mga parameter sa mga function sa katabang gipasa sa mga rehistro r1-r5, ug ang bili ibalik sa rehistro r0. Walay mga gimbuhaton nga nagkinahanglan og labaw sa lima ka mga argumento, ug ang suporta alang kanila wala gilauman nga idugang sa umaabot.

Atong tan-awon ang bag-ong katabang sa kernel ug kung giunsa ang pagpasa sa BPF sa mga parameter. Atong isulat pag-usab xdp-simple.bpf.c ingon sa mosunod (ang uban nga mga linya wala mausab):

SEC("xdp/simple")
int simple(void *ctx)
{
    bpf_printk("running on CPU%un", bpf_get_smp_processor_id());
    return XDP_PASS;
}

Ang among programa nag-imprinta sa gidaghanon sa CPU diin kini nagdagan. Himoon nato kini ug tan-awon ang code:

$ llvm-objdump -D --section=xdp/simple --no-show-raw-insn xdp-simple.bpf.o

0000000000000000 <simple>:
       0:       r1 = 10
       1:       *(u16 *)(r10 - 8) = r1
       2:       r1 = 8441246879787806319 ll
       4:       *(u64 *)(r10 - 16) = r1
       5:       r1 = 2334956330918245746 ll
       7:       *(u64 *)(r10 - 24) = r1
       8:       call 8
       9:       r1 = r10
      10:       r1 += -24
      11:       r2 = 18
      12:       r3 = r0
      13:       call 6
      14:       r0 = 2
      15:       exit

Sa linya 0-7 atong isulat ang hilo running on CPU%un, ug dayon sa linya 8 among gipadagan ang pamilyar bpf_get_smp_processor_id. Sa linya 9-12 giandam namo ang mga argumento sa katabang bpf_printk - mga rehistro r1, r2, r3. Nganong tulo man sila ug dili duha? Kay bpf_printkkini usa ka macro wrapper palibot sa tinuod nga katabang bpf_trace_printk, nga kinahanglang ipasa ang gidak-on sa format nga string.

Magdugang ta karon og duha ka linya sa xdp-simple.caron ang among programa magkonektar sa interface lo ug nagsugod gyud!

$ cat xdp-simple.c
#include <linux/if_link.h>
#include <err.h>
#include <unistd.h>
#include "xdp-simple.skel.h"

int main(int argc, char **argv)
{
    __u32 flags = XDP_FLAGS_SKB_MODE;
    struct xdp_simple_bpf *obj;

    obj = xdp_simple_bpf__open_and_load();
    if (!obj)
        err(1, "failed to open and/or load BPF objectn");

    bpf_set_link_xdp_fd(1, -1, flags);
    bpf_set_link_xdp_fd(1, bpf_program__fd(obj->progs.simple), flags);

cleanup:
    xdp_simple_bpf__destroy(obj);
}

Dinhi among gigamit ang function bpf_set_link_xdp_fd, nga nagkonektar sa XDP-type nga BPF nga mga programa sa mga interface sa network. Gi-hardcode namo ang numero sa interface lo, nga mao ang kanunay nga 1. Among gipadagan ang function kaduha aron una nga matangtang ang daan nga programa kung kini gilakip. Matikdi nga karon wala na kita magkinahanglan og hagit pause o usa ka walay kinutuban nga loop: ang among loader nga programa mogawas, apan ang BPF nga programa dili mapatay tungod kay kini konektado sa tinubdan sa panghitabo. Human sa malampuson nga pag-download ug koneksyon, ang programa ilunsad alang sa matag network packet nga moabot sa lo.

Atong i-download ang programa ug tan-awon ang interface lo:

$ sudo ./xdp-simple
$ sudo bpftool p | grep simple
669: xdp  name simple  tag 4fca62e77ccb43d6  gpl
$ ip l show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    prog/xdp id 669

Ang programa nga among gi-download adunay ID 669 ug among makita ang parehas nga ID sa interface lo. Magpadala kami og duha ka pakete sa 127.0.0.1 (hangyo + tubag):

$ ping -c1 localhost

ug karon atong tan-awon ang mga sulod sa debug virtual file /sys/kernel/debug/tracing/trace_pipe, diin bpf_printk misulat sa iyang mga mensahe:

# cat /sys/kernel/debug/tracing/trace_pipe
ping-13937 [000] d.s1 442015.377014: bpf_trace_printk: running on CPU0
ping-13937 [000] d.s1 442015.377027: bpf_trace_printk: running on CPU0

Duha ka pakete ang nakit-an lo ug giproseso sa CPU0 - ang among unang bug-os nga walay kahulogan nga BPF nga programa nagtrabaho!

Kini angay nga hinumdoman nga bpf_printk Dili alang sa bisan unsa nga kini nagsulat sa debug file: dili kini ang labing malampuson nga katabang alang sa paggamit sa produksiyon, apan ang among katuyoan mao ang pagpakita sa usa ka butang nga yano.

Pag-access sa mga mapa gikan sa mga programa sa BPF

Pananglitan: gamit ang mapa gikan sa BPF program

Sa miaging mga seksyon nahibal-an namon kung giunsa paghimo ug paggamit ang mga mapa gikan sa wanang sa gumagamit, ug karon tan-awon naton ang bahin sa kernel. Magsugod kita, sama sa naandan, sa usa ka pananglitan. Atong isulat pag-usab ang atong programa xdp-simple.bpf.c ingon sa mosunod:

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

struct {
    __uint(type, BPF_MAP_TYPE_ARRAY);
    __uint(max_entries, 8);
    __type(key, u32);
    __type(value, u64);
} woo SEC(".maps");

SEC("xdp/simple")
int simple(void *ctx)
{
    u32 key = bpf_get_smp_processor_id();
    u32 *val;

    val = bpf_map_lookup_elem(&woo, &key);
    if (!val)
        return XDP_ABORTED;

    *val += 1;

    return XDP_PASS;
}

char LICENSE[] SEC("license") = "GPL";

Sa sinugdanan sa programa gidugang namo ang kahulugan sa mapa woo: Kini usa ka 8-element array nga nagtipig sa mga kantidad sama sa u64 (sa C atong ipasabut ang ingon nga array sama sa u64 woo[8]). Sa usa ka programa "xdp/simple" atong makuha ang kasamtangan nga numero sa processor ngadto sa usa ka variable key ug dayon gamit ang function sa katabang bpf_map_lookup_element makakuha kami usa ka pointer sa katugbang nga entry sa array, nga among gidugangan sa usa. Gihubad sa Russian: among gikalkulo ang mga estadistika kung diin giproseso sa CPU ang mga umaabot nga pakete. Atong sulayan ang pagpadagan sa programa:

$ clang -O2 -g -c -target bpf -I libbpf/src/root/usr/include xdp-simple.bpf.c -o xdp-simple.bpf.o
$ bpftool gen skeleton xdp-simple.bpf.o > xdp-simple.skel.h
$ clang -O2 -g -I ./libbpf/src/root/usr/include/ -o xdp-simple xdp-simple.c ./libbpf/src/root/usr/lib64/libbpf.a -lelf -lz
$ sudo ./xdp-simple

Atong tan-awon nga siya nalambigit sa lo ug ipadala ang pipila ka mga pakete:

$ ip l show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    prog/xdp id 108

$ for s in `seq 234`; do sudo ping -f -c 100 127.0.0.1 >/dev/null 2>&1; done

Karon atong tan-awon ang mga sulod sa array:

$ sudo bpftool map dump name woo
[
    { "key": 0, "value": 0 },
    { "key": 1, "value": 400 },
    { "key": 2, "value": 0 },
    { "key": 3, "value": 0 },
    { "key": 4, "value": 0 },
    { "key": 5, "value": 0 },
    { "key": 6, "value": 0 },
    { "key": 7, "value": 46400 }
]

Hapit tanan nga mga proseso giproseso sa CPU7. Dili kini hinungdanon kanamo, ang panguna nga butang mao nga ang programa nagtrabaho ug nahibal-an namon kung giunsa ang pag-access sa mga mapa gikan sa mga programa sa BPF - gamit ang хелперов bpf_mp_*.

Mystical nga indeks

Busa, ma-access nato ang mapa gikan sa BPF program gamit ang mga tawag sama sa

val = bpf_map_lookup_elem(&woo, &key);

diin ang function sa katabang ingon

void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)

pero nagpasa mi ug pointer &woo sa usa ka wala nganli nga istruktura struct { ... }...

Kon atong tan-awon ang programa assembler, atong makita nga ang bili &woo dili tinuod nga gihubit (linya 4):

llvm-objdump -D --section xdp/simple xdp-simple.bpf.o

xdp-simple.bpf.o:       file format elf64-bpf

Disassembly of section xdp/simple:

0000000000000000 <simple>:
       0:       85 00 00 00 08 00 00 00 call 8
       1:       63 0a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r0
       2:       bf a2 00 00 00 00 00 00 r2 = r10
       3:       07 02 00 00 fc ff ff ff r2 += -4
       4:       18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
       6:       85 00 00 00 01 00 00 00 call 1
...

ug anaa sa mga relokasyon:

$ llvm-readelf -r xdp-simple.bpf.o | head -4

Relocation section '.relxdp/simple' at offset 0xe18 contains 1 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name
0000000000000020  0000002700000001 R_BPF_64_64            0000000000000000 woo

Apan kung atong tan-awon ang na-load na nga programa, atong makita ang usa ka pointer sa husto nga mapa (linya 4):

$ sudo bpftool prog dump x name simple
int simple(void *ctx):
   0: (85) call bpf_get_smp_processor_id#114128
   1: (63) *(u32 *)(r10 -4) = r0
   2: (bf) r2 = r10
   3: (07) r2 += -4
   4: (18) r1 = map[id:64]
...

Sa ingon, makahinapos kita nga sa panahon sa paglansad sa among loader nga programa, ang link sa &woo gipulihan sa usa ka butang nga adunay librarya libbpf. Una atong tan-awon ang output strace:

$ sudo strace -e bpf ./xdp-simple
...
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_ARRAY, key_size=4, value_size=8, max_entries=8, map_name="woo", ...}, 120) = 4
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, prog_name="simple", ...}, 120) = 5

Atong makita kana libbpf naghimo ug mapa woo ug dayon gi-download ang among programa simple. Atong tan-awon pag-ayo kon giunsa nato pagkarga ang programa:

  • tawag xdp_simple_bpf__open_and_load gikan sa file xdp-simple.skel.h
  • nga hinungdan xdp_simple_bpf__load gikan sa file xdp-simple.skel.h
  • nga hinungdan bpf_object__load_skeleton gikan sa file libbpf/src/libbpf.c
  • nga hinungdan bpf_object__load_xattr gikan sa libbpf/src/libbpf.c

Ang katapusan nga function, sa taliwala sa ubang mga butang, motawag bpf_object__create_maps, nga nagmugna o nagbukas sa kasamtangan nga mga mapa, nga gihimo kini nga mga deskriptor sa file. (Dinhi atong makita BPF_MAP_CREATE sa output strace.) Sunod ang function gitawag bpf_object__relocate ug siya mao ang nakapaikag kanamo, tungod kay kami nahinumdom sa among nakita woo sa relocation table. Ang pagsuhid niini, sa katapusan nakit-an namon ang among kaugalingon sa function bpf_program__relocate, nga naghisgot sa mga relokasyon sa mapa:

case RELO_LD64:
    insn[0].src_reg = BPF_PSEUDO_MAP_FD;
    insn[0].imm = obj->maps[relo->map_idx].fd;
    break;

Busa among gisunod ang among mga instruksyon

18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll

ug pulihan ang tinubdan nga rehistro niini sa BPF_PSEUDO_MAP_FD, ug ang una nga IMM sa file descriptor sa among mapa ug, kung parehas kini, pananglitan, 0xdeadbeef, unya isip resulta makadawat kita sa instruksiyon

18 11 00 00 ef eb ad de 00 00 00 00 00 00 00 00 r1 = 0 ll

Ingon niini kung giunsa ang impormasyon sa mapa gibalhin sa usa ka piho nga gikarga nga programa sa BPF. Sa kini nga kaso, ang mapa mahimong mahimo gamit ang BPF_MAP_CREATE, ug giablihan pinaagi sa ID gamit BPF_MAP_GET_FD_BY_ID.

Total, kon gamiton libbpf ang algorithm mao ang mosunod:

  • atol sa paghugpong, ang mga rekord gihimo sa relokasyon nga talaan para sa mga link sa mga mapa
  • libbpf ablihan ang ELF object book, pangitaa ang tanang gigamit nga mga mapa ug paghimo og mga deskriptor sa file alang kanila
  • Ang mga deskriptor sa file gikarga sa kernel isip bahin sa panudlo LD64

Sama sa imong mahanduraw, adunay daghan pa nga moabut ug kinahanglan naton tan-awon ang kinauyokan. Maayo na lang, kami adunay usa ka timailhan - among gisulat ang kahulogan BPF_PSEUDO_MAP_FD ngadto sa tinubdan nga rehistro ug kita makalubong niini, nga modala kanato ngadto sa balaan sa tanang mga santos - kernel/bpf/verifier.c, diin ang usa ka function nga adunay lahi nga ngalan nagpuli sa usa ka deskriptor sa file nga adunay adres sa usa ka istruktura nga tipo struct bpf_map:

static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env) {
    ...

    f = fdget(insn[0].imm);
    map = __bpf_map_get(f);
    if (insn->src_reg == BPF_PSEUDO_MAP_FD) {
        addr = (unsigned long)map;
    }
    insn[0].imm = (u32)addr;
    insn[1].imm = addr >> 32;

(makita ang tibuok code link). Aron mapalapad namon ang among algorithm:

  • samtang nagkarga sa programa, gisusi sa verifier ang husto nga paggamit sa mapa ug gisulat ang adres sa katugbang nga istruktura struct bpf_map

Kung nag-download sa ELF binary gamit ang libbpf Daghan pa ang mahitabo, apan atong hisgotan kana sa ubang mga artikulo.

Nag-load sa mga programa ug mga mapa nga walay libbpf

Sama sa gisaad, ania ang usa ka panig-ingnan alang sa mga magbabasa nga gusto mahibal-an kung giunsa paghimo ug pagkarga sa usa ka programa nga naggamit mga mapa, nga wala’y tabang. libbpf. Mahimong mapuslanon kini kung nagtrabaho ka sa usa ka palibot diin dili ka makatukod mga dependency, o pagtipig sa matag gamay, o pagsulat sa usa ka programa sama sa ply, nga nagmugna sa BPF binary code sa langaw.

Aron mas sayon ​​ang pagsunod sa lohika, atong isulat pag-usab ang atong panig-ingnan alang niini nga mga katuyoan xdp-simple. Ang kompleto ug gamay nga gipalapdan nga code sa programa nga gihisgutan niini nga pananglitan makita niini hinungdanon.

Ang lohika sa among aplikasyon mao ang mosunod:

  • paghimo ug tipo nga mapa BPF_MAP_TYPE_ARRAY gamit ang sugo BPF_MAP_CREATE,
  • paghimo og programa nga naggamit niini nga mapa,
  • ikonektar ang programa sa interface lo,

nga gihubad ngadto sa tawo ingon nga

int main(void)
{
    int map_fd, prog_fd;

    map_fd = map_create();
    if (map_fd < 0)
        err(1, "bpf: BPF_MAP_CREATE");

    prog_fd = prog_load(map_fd);
    if (prog_fd < 0)
        err(1, "bpf: BPF_PROG_LOAD");

    xdp_attach(1, prog_fd);
}

kini mao ang map_create nagmugna og mapa sa samang paagi sama sa atong gibuhat sa unang pananglitan mahitungod sa system call bpf - "kernel, palihug paghimo kanako usa ka bag-ong mapa sa porma sa usa ka han-ay sa 8 nga mga elemento sama __u64 ug ibalik kanako ang file descriptor":

static int map_create()
{
    union bpf_attr attr;

    memset(&attr, 0, sizeof(attr));
    attr.map_type = BPF_MAP_TYPE_ARRAY,
    attr.key_size = sizeof(__u32),
    attr.value_size = sizeof(__u64),
    attr.max_entries = 8,
    strncpy(attr.map_name, "woo", sizeof(attr.map_name));
    return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
}

Ang programa dali usab nga ma-load:

static int prog_load(int map_fd)
{
    union bpf_attr attr;
    struct bpf_insn insns[] = {
        ...
    };

    memset(&attr, 0, sizeof(attr));
    attr.prog_type = BPF_PROG_TYPE_XDP;
    attr.insns     = ptr_to_u64(insns);
    attr.insn_cnt  = sizeof(insns)/sizeof(insns[0]);
    attr.license   = ptr_to_u64("GPL");
    strncpy(attr.prog_name, "woo", sizeof(attr.prog_name));
    return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
}

Ang lisud nga bahin prog_load mao ang depinisyon sa atong BPF nga programa isip usa ka han-ay sa mga istruktura struct bpf_insn insns[]. Apan tungod kay naggamit kami usa ka programa nga naa kanamo sa C, mahimo kaming manikas gamay:

$ llvm-objdump -D --section xdp/simple xdp-simple.bpf.o

0000000000000000 <simple>:
       0:       85 00 00 00 08 00 00 00 call 8
       1:       63 0a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r0
       2:       bf a2 00 00 00 00 00 00 r2 = r10
       3:       07 02 00 00 fc ff ff ff r2 += -4
       4:       18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
       6:       85 00 00 00 01 00 00 00 call 1
       7:       b7 01 00 00 00 00 00 00 r1 = 0
       8:       15 00 04 00 00 00 00 00 if r0 == 0 goto +4 <LBB0_2>
       9:       61 01 00 00 00 00 00 00 r1 = *(u32 *)(r0 + 0)
      10:       07 01 00 00 01 00 00 00 r1 += 1
      11:       63 10 00 00 00 00 00 00 *(u32 *)(r0 + 0) = r1
      12:       b7 01 00 00 02 00 00 00 r1 = 2

0000000000000068 <LBB0_2>:
      13:       bf 10 00 00 00 00 00 00 r0 = r1
      14:       95 00 00 00 00 00 00 00 exit

Sa kinatibuk-an, kinahanglan namon nga isulat ang 14 nga mga panudlo sa porma sa mga istruktura sama struct bpf_insn (tambag: kuhaa ang dump gikan sa ibabaw, basaha pag-usab ang seksyon sa mga panudlo, ablihi linux/bpf.h и linux/bpf_common.h ug pagsulay sa pagtino struct bpf_insn insns[] sa kaugalingon):

struct bpf_insn insns[] = {
    /* 85 00 00 00 08 00 00 00 call 8 */
    {
        .code = BPF_JMP | BPF_CALL,
        .imm = 8,
    },

    /* 63 0a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r0 */
    {
        .code = BPF_MEM | BPF_STX,
        .off = -4,
        .src_reg = BPF_REG_0,
        .dst_reg = BPF_REG_10,
    },

    /* bf a2 00 00 00 00 00 00 r2 = r10 */
    {
        .code = BPF_ALU64 | BPF_MOV | BPF_X,
        .src_reg = BPF_REG_10,
        .dst_reg = BPF_REG_2,
    },

    /* 07 02 00 00 fc ff ff ff r2 += -4 */
    {
        .code = BPF_ALU64 | BPF_ADD | BPF_K,
        .dst_reg = BPF_REG_2,
        .imm = -4,
    },

    /* 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll */
    {
        .code = BPF_LD | BPF_DW | BPF_IMM,
        .src_reg = BPF_PSEUDO_MAP_FD,
        .dst_reg = BPF_REG_1,
        .imm = map_fd,
    },
    { }, /* placeholder */

    /* 85 00 00 00 01 00 00 00 call 1 */
    {
        .code = BPF_JMP | BPF_CALL,
        .imm = 1,
    },

    /* b7 01 00 00 00 00 00 00 r1 = 0 */
    {
        .code = BPF_ALU64 | BPF_MOV | BPF_K,
        .dst_reg = BPF_REG_1,
        .imm = 0,
    },

    /* 15 00 04 00 00 00 00 00 if r0 == 0 goto +4 <LBB0_2> */
    {
        .code = BPF_JMP | BPF_JEQ | BPF_K,
        .off = 4,
        .src_reg = BPF_REG_0,
        .imm = 0,
    },

    /* 61 01 00 00 00 00 00 00 r1 = *(u32 *)(r0 + 0) */
    {
        .code = BPF_MEM | BPF_LDX,
        .off = 0,
        .src_reg = BPF_REG_0,
        .dst_reg = BPF_REG_1,
    },

    /* 07 01 00 00 01 00 00 00 r1 += 1 */
    {
        .code = BPF_ALU64 | BPF_ADD | BPF_K,
        .dst_reg = BPF_REG_1,
        .imm = 1,
    },

    /* 63 10 00 00 00 00 00 00 *(u32 *)(r0 + 0) = r1 */
    {
        .code = BPF_MEM | BPF_STX,
        .src_reg = BPF_REG_1,
        .dst_reg = BPF_REG_0,
    },

    /* b7 01 00 00 02 00 00 00 r1 = 2 */
    {
        .code = BPF_ALU64 | BPF_MOV | BPF_K,
        .dst_reg = BPF_REG_1,
        .imm = 2,
    },

    /* <LBB0_2>: bf 10 00 00 00 00 00 00 r0 = r1 */
    {
        .code = BPF_ALU64 | BPF_MOV | BPF_X,
        .src_reg = BPF_REG_1,
        .dst_reg = BPF_REG_0,
    },

    /* 95 00 00 00 00 00 00 00 exit */
    {
        .code = BPF_JMP | BPF_EXIT
    },
};

Usa ka ehersisyo alang niadtong wala magsulat niini sa ilang kaugalingon - pangitaa map_fd.

Adunay usa pa nga wala gibutyag nga bahin nga nahabilin sa among programa - xdp_attach. Ikasubo, ang mga programa sama sa XDP dili makonektar gamit ang usa ka tawag sa sistema bpf. Ang mga tawo nga naghimo sa BPF ug XDP gikan sa online Linux nga komunidad, nga nagpasabut nga gigamit nila ang usa nga labing pamilyar sa kanila (apan dili sa normal tawo) interface alang sa pagpakig-uban sa kernel: mga socket sa netlink, tan-awa usab RFC3549. Ang pinakasimple nga paagi sa pagpatuman xdp_attach nagkopya sa code gikan sa libbpf, nga mao, gikan sa file netlink.c, nga mao ang among gibuhat, gipamubo kini og gamay:

Welcome sa kalibutan sa netlink sockets

Ablihi ang netlink socket type NETLINK_ROUTE:

int netlink_open(__u32 *nl_pid)
{
    struct sockaddr_nl sa;
    socklen_t addrlen;
    int one = 1, ret;
    int sock;

    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;

    sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (sock < 0)
        err(1, "socket");

    if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, &one, sizeof(one)) < 0)
        warnx("netlink error reporting not supported");

    if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0)
        err(1, "bind");

    addrlen = sizeof(sa);
    if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0)
        err(1, "getsockname");

    *nl_pid = sa.nl_pid;
    return sock;
}

Atong mabasa gikan niini nga socket:

static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq)
{
    bool multipart = true;
    struct nlmsgerr *errm;
    struct nlmsghdr *nh;
    char buf[4096];
    int len, ret;

    while (multipart) {
        multipart = false;
        len = recv(sock, buf, sizeof(buf), 0);
        if (len < 0)
            err(1, "recv");

        if (len == 0)
            break;

        for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
                nh = NLMSG_NEXT(nh, len)) {
            if (nh->nlmsg_pid != nl_pid)
                errx(1, "wrong pid");
            if (nh->nlmsg_seq != seq)
                errx(1, "INVSEQ");
            if (nh->nlmsg_flags & NLM_F_MULTI)
                multipart = true;
            switch (nh->nlmsg_type) {
                case NLMSG_ERROR:
                    errm = (struct nlmsgerr *)NLMSG_DATA(nh);
                    if (!errm->error)
                        continue;
                    ret = errm->error;
                    // libbpf_nla_dump_errormsg(nh); too many code to copy...
                    goto done;
                case NLMSG_DONE:
                    return 0;
                default:
                    break;
            }
        }
    }
    ret = 0;
done:
    return ret;
}

Sa katapusan, ania ang among function nga nagbukas sa usa ka socket ug nagpadala usa ka espesyal nga mensahe niini nga adunay sulud nga deskriptor sa file:

static int xdp_attach(int ifindex, int prog_fd)
{
    int sock, seq = 0, ret;
    struct nlattr *nla, *nla_xdp;
    struct {
        struct nlmsghdr  nh;
        struct ifinfomsg ifinfo;
        char             attrbuf[64];
    } req;
    __u32 nl_pid = 0;

    sock = netlink_open(&nl_pid);
    if (sock < 0)
        return sock;

    memset(&req, 0, sizeof(req));
    req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
    req.nh.nlmsg_type = RTM_SETLINK;
    req.nh.nlmsg_pid = 0;
    req.nh.nlmsg_seq = ++seq;
    req.ifinfo.ifi_family = AF_UNSPEC;
    req.ifinfo.ifi_index = ifindex;

    /* started nested attribute for XDP */
    nla = (struct nlattr *)(((char *)&req)
            + NLMSG_ALIGN(req.nh.nlmsg_len));
    nla->nla_type = NLA_F_NESTED | IFLA_XDP;
    nla->nla_len = NLA_HDRLEN;

    /* add XDP fd */
    nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
    nla_xdp->nla_type = IFLA_XDP_FD;
    nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
    memcpy((char *)nla_xdp + NLA_HDRLEN, &prog_fd, sizeof(prog_fd));
    nla->nla_len += nla_xdp->nla_len;

    /* if user passed in any flags, add those too */
    __u32 flags = XDP_FLAGS_SKB_MODE;
    nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
    nla_xdp->nla_type = IFLA_XDP_FLAGS;
    nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
    memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
    nla->nla_len += nla_xdp->nla_len;

    req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);

    if (send(sock, &req, req.nh.nlmsg_len, 0) < 0)
        err(1, "send");
    ret = bpf_netlink_recv(sock, nl_pid, seq);

cleanup:
    close(sock);
    return ret;
}

Busa, andam na ang tanan alang sa pagsulay:

$ cc nolibbpf.c -o nolibbpf
$ sudo strace -e bpf ./nolibbpf
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_ARRAY, map_name="woo", ...}, 72) = 3
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, insn_cnt=15, prog_name="woo", ...}, 72) = 4
+++ exited with 0 +++

Atong tan-awon kon ang atong programa konektado sa lo:

$ ip l show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    prog/xdp id 160

Magpadala kita og mga ping ug tan-awon ang mapa:

$ for s in `seq 234`; do sudo ping -f -c 100 127.0.0.1 >/dev/null 2>&1; done
$ sudo bpftool m dump name woo
key: 00 00 00 00  value: 90 01 00 00 00 00 00 00
key: 01 00 00 00  value: 00 00 00 00 00 00 00 00
key: 02 00 00 00  value: 00 00 00 00 00 00 00 00
key: 03 00 00 00  value: 00 00 00 00 00 00 00 00
key: 04 00 00 00  value: 00 00 00 00 00 00 00 00
key: 05 00 00 00  value: 00 00 00 00 00 00 00 00
key: 06 00 00 00  value: 40 b5 00 00 00 00 00 00
key: 07 00 00 00  value: 00 00 00 00 00 00 00 00
Found 8 elements

Hurray, ang tanan nagtrabaho. Hinumdumi, sa paagi, nga ang among mapa gipakita pag-usab sa porma sa mga byte. Kini tungod sa kamatuoran nga, dili sama libbpf wala namo gikarga ang type information (BTF). Apan hisgotan pa nato kini sa sunod higayon.

Mga Himan sa Pag-uswag

Niini nga seksyon, atong tan-awon ang minimum BPF developer toolkit.

Sa kinatibuk-an nga pagsulti, dili nimo kinahanglan ang bisan unsang espesyal aron mapalambo ang mga programa sa BPF - Ang BPF nagdagan sa bisan unsang disente nga kernel sa pag-apod-apod, ug ang mga programa gitukod gamit ang clang, nga mahimong mahatag gikan sa pakete. Bisan pa, tungod sa kamatuoran nga ang BPF gipailalom sa pag-uswag, ang kernel ug mga himan kanunay nga nagbag-o, kung dili nimo gusto nga isulat ang mga programa sa BPF gamit ang karaan nga mga pamaagi gikan sa 2019, nan kinahanglan nimo nga mag-compile.

  • llvm/clang
  • pahole
  • kinauyokan niini
  • bpftool

(Alang sa pakisayran, kini nga seksyon ug ang tanan nga mga pananglitan sa artikulo gipadagan sa Debian 10.)

llvm/clang

Ang BPF mahigalaon sa LLVM ug, bisan kung bag-o lang ang mga programa para sa BPF mahimong matipon gamit ang gcc, ang tanan nga karon nga pag-uswag gihimo alang sa LLVM. Busa, una sa tanan, atong tukuron ang kasamtangan nga bersyon clang gikan sa git:

$ sudo apt install ninja-build
$ git clone --depth 1 https://github.com/llvm/llvm-project.git
$ mkdir -p llvm-project/llvm/build/install
$ cd llvm-project/llvm/build
$ cmake .. -G "Ninja" -DLLVM_TARGETS_TO_BUILD="BPF;X86" 
                      -DLLVM_ENABLE_PROJECTS="clang" 
                      -DBUILD_SHARED_LIBS=OFF 
                      -DCMAKE_BUILD_TYPE=Release 
                      -DLLVM_BUILD_RUNTIME=OFF
$ time ninja
... много времени спустя
$

Karon atong masusi kung ang tanan nagkahiusa sa husto:

$ ./bin/llc --version
LLVM (http://llvm.org/):
  LLVM version 11.0.0git
  Optimized build.
  Default target: x86_64-unknown-linux-gnu
  Host CPU: znver1

  Registered Targets:
    bpf    - BPF (host endian)
    bpfeb  - BPF (big endian)
    bpfel  - BPF (little endian)
    x86    - 32-bit X86: Pentium-Pro and above
    x86-64 - 64-bit X86: EM64T and AMD64

(Mga instruksiyon sa asembliya clang gikuha nako gikan sa bpf_devel_QA.)

Dili namo i-install ang mga programa nga bag-o pa lang namon gitukod, apan idugang lang kini PATHsama pananglit:

export PATH="`pwd`/bin:$PATH"

(Kini mahimong idugang sa .bashrc o sa usa ka bulag nga file. Sa personal, gidugang nako ang mga butang nga sama niini ~/bin/activate-llvm.sh ug kung gikinahanglan buhaton ko kini . activate-llvm.sh.)

Pahole ug BTF

Gamit pahole gigamit sa pagtukod sa kernel sa paghimo sa debugging nga impormasyon sa BTF format. Dili kami magdetalye niini nga artikulo bahin sa mga detalye sa teknolohiya sa BTF, gawas sa kamatuoran nga kini sayon ​​​​ug gusto namong gamiton kini. Busa kung magtukod ka sa imong kernel, magtukod una pahole (wala pahole dili ka makahimo sa pagtukod sa kernel nga adunay kapilian CONFIG_DEBUG_INFO_BTF:

$ git clone https://git.kernel.org/pub/scm/devel/pahole/pahole.git
$ cd pahole/
$ sudo apt install cmake
$ mkdir build
$ cd build/
$ cmake -D__LIB=lib ..
$ make
$ sudo make install
$ which pahole
/usr/local/bin/pahole

Mga kernel alang sa pag-eksperimento sa BPF

Kung gisuhid ang mga posibilidad sa BPF, gusto nako nga tipunon ang akong kaugalingon nga kinauyokan. Kini, sa kasagaran nga pagsulti, dili kinahanglan, tungod kay makahimo ka sa pag-compile ug pag-load sa mga programa sa BPF sa kernel sa pag-apod-apod, bisan pa, ang pagbaton sa imong kaugalingon nga kernel nagtugot kanimo sa paggamit sa labing bag-o nga mga bahin sa BPF, nga makita sa imong pag-apod-apod sa labing kaayo nga mga bulan. , o, sama sa kaso sa pipila ka mga himan sa pag-debug dili gyud maputos sa umaabot nga umaabot. Usab, ang kaugalingon nga kinauyokan nagpabati nga hinungdanon nga mag-eksperimento sa code.

Aron makahimo og kernel kinahanglan nimo, una, ang kernel mismo, ug ikaduha, usa ka kernel configuration file. Sa pag-eksperimento sa BPF mahimo natong gamiton ang naandan vanilla kernel o usa sa mga kernel sa pag-uswag. Sa kasaysayan, ang pag-uswag sa BPF mahitabo sulod sa Linux networking community ug busa ang tanang kausaban sa madugay o sa madali moagi kang David Miller, ang Linux networking maintainer. Depende sa ilang kinaiyahan - mga pag-edit o bag-ong mga bahin - ang mga pagbag-o sa network nahulog sa usa sa duha nga mga cores - net o net-next. Ang mga pagbag-o alang sa BPF giapod-apod sa parehas nga paagi taliwala bpf и bpf-next, nga unya gipundok ngadto sa pukot ug net-sunod, sa tinagsa. Alang sa dugang mga detalye, tan-awa bpf_devel_QA и netdev-FAQ. Busa pagpili og kernel base sa imong lami ug sa kalig-on nga mga panginahanglan sa sistema nga imong gisulayan (*-next Ang mga kernel mao ang labing dili lig-on sa mga nalista).

Labaw pa sa sakup sa kini nga artikulo ang paghisgot kung giunsa pagdumala ang mga file sa pagsumpo sa kernel - gituohan nga nahibal-an na nimo kung giunsa kini buhaton, o andam sa pagkat-on sa kaugalingon. Bisan pa, ang mosunod nga mga panudlo kinahanglan nga labi pa o dili kaayo igo aron mahatagan ka usa ka nagtrabaho nga sistema nga gipagana sa BPF.

Pag-download sa usa sa mga kernel sa ibabaw:

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
$ cd bpf-next

Paghimo usa ka gamay nga nagtrabaho nga kernel config:

$ cp /boot/config-`uname -r` .config
$ make localmodconfig

I-enable ang mga opsyon sa BPF sa file .config sa imong kaugalingong pagpili (lagmit CONFIG_BPF ma-enable na tungod kay gigamit kini sa systemd). Ania ang usa ka lista sa mga kapilian gikan sa kernel nga gigamit alang niini nga artikulo:

CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_LSM=y
CONFIG_BPF_SYSCALL=y
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_IPV6_SEG6_BPF=y
# CONFIG_NETFILTER_XT_MATCH_BPF is not set
# CONFIG_BPFILTER is not set
CONFIG_NET_CLS_BPF=y
CONFIG_NET_ACT_BPF=y
CONFIG_BPF_JIT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_BPF_EVENTS=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_DEBUG_INFO_BTF=y

Unya dali namong ma-assemble ug ma-install ang mga modules ug ang kernel (by the way, mahimo nimong i-assemble ang kernel gamit ang bag-ong na-assemble clangpinaagi sa pagdugang CC=clang):

$ make -s -j $(getconf _NPROCESSORS_ONLN)
$ sudo make modules_install
$ sudo make install

ug pag-reboot gamit ang bag-ong kernel (gigamit nako kini kexec gikan sa package kexec-tools):

v=5.8.0-rc6+ # если вы пересобираете текущее ядро, то можно делать v=`uname -r`
sudo kexec -l -t bzImage /boot/vmlinuz-$v --initrd=/boot/initrd.img-$v --reuse-cmdline &&
sudo kexec -e

bpftool

Ang labing sagad nga gigamit nga gamit sa artikulo mao ang gamit bpftool, gihatag isip bahin sa Linux kernel. Gisulat ug gimentinar kini sa mga developers sa BPF para sa mga developers sa BPF ug mahimong magamit sa pagdumala sa tanang matang sa BPF objects - load programs, paghimo ug pag-edit sa mga mapa, pagsuhid sa kinabuhi sa BPF ecosystem, etc. Makit-an ang dokumentasyon sa porma sa source code para sa mga man page sa kinauyokan o, nahipos na, sa net.

Sa panahon ning pagsulat bpftool andam nga gihimo lamang alang sa RHEL, Fedora ug Ubuntu (tan-awa, pananglitan, kini nga thread, nga nagsulti sa wala mahuman nga istorya sa pagputos bpftool sa Debian). Apan kung natukod na nimo ang imong kernel, dayon pagtukod bpftool ingon kadali sa pie:

$ cd ${linux}/tools/bpf/bpftool
# ... пропишите пути к последнему clang, как рассказано выше
$ make -s

Auto-detecting system features:
...                        libbfd: [ on  ]
...        disassembler-four-args: [ on  ]
...                          zlib: [ on  ]
...                        libcap: [ on  ]
...               clang-bpf-co-re: [ on  ]

Auto-detecting system features:
...                        libelf: [ on  ]
...                          zlib: [ on  ]
...                           bpf: [ on  ]

$

(Dinhi ${linux} - kini ang imong kernel directory.) Human sa pagpatuman niini nga mga sugo bpftool kolektahon sa usa ka direktoryo ${linux}/tools/bpf/bpftool ug kini mahimong idugang sa dalan (una sa tanan sa user root) o kopyaha lang sa /usr/local/sbin.

Pagkolekta bpftool labing maayo nga gamiton ang ulahi clang, gitigum sama sa gihulagway sa ibabaw, ug susiha kung kini gitigum sa husto - gamit, pananglitan, ang sugo

$ sudo bpftool feature probe kernel
Scanning system configuration...
bpf() syscall for unprivileged users is enabled
JIT compiler is enabled
JIT compiler hardening is disabled
JIT compiler kallsyms exports are enabled for root
...

nga magpakita kung unsang mga bahin sa BPF ang gipagana sa imong kernel.

Pinaagi sa dalan, ang miaging sugo mahimong modagan ingon

# bpftool f p k

Gihimo kini pinaagi sa pagtandi sa mga utilities gikan sa package iproute2, diin mahimo naton, pananglitan, isulti ip a s eth0 imbis nga ip addr show dev eth0.

konklusyon

Gitugotan ka sa BPF nga magsapatos sa usa ka pulgas aron epektibo nga masukod ug on-the-fly nga pagbag-o sa pagpaandar sa kinauyokan. Ang sistema nahimo nga malampuson kaayo, sa labing kaayo nga mga tradisyon sa UNIX: usa ka yano nga mekanismo nga nagtugot kanimo sa (pag-program) sa kernel nagtugot sa daghang mga tawo ug organisasyon nga mag-eksperimento. Ug, bisan kung ang mga eksperimento, ingon man ang pag-uswag sa imprastraktura sa BPF mismo, layo pa sa pagkahuman, ang sistema adunay usa ka lig-on nga ABI nga nagtugot kanimo sa pagtukod og kasaligan, ug labing hinungdanon, epektibo nga lohika sa negosyo.

Gusto nakong timan-an nga, sa akong opinyon, ang teknolohiya nahimong popular kaayo tungod kay, sa usa ka bahin, mahimo kini aron magdula (ang arkitektura sa usa ka makina mahimong masabtan nga mas daghan o dili kaayo sa usa ka gabii), ug sa laing bahin, aron masulbad ang mga problema nga dili masulbad (matahum) sa wala pa ang hitsura niini. Kining duha ka mga sangkap naghiusa sa pagpugos sa mga tawo sa pag-eksperimento ug pagdamgo, nga mosangpot sa pagtumaw sa dugang ug mas bag-ong mga solusyon.

Kini nga artikulo, bisan kung dili labi ka mubo, usa lamang ka pasiuna sa kalibutan sa BPF ug wala maghubit sa "advanced" nga mga bahin ug hinungdanon nga mga bahin sa arkitektura. Ang plano sa unahan usa ka butang nga sama niini: ang sunod nga artikulo usa ka kinatibuk-ang panan-aw sa mga tipo sa programa sa BPF (adunay 5.8 nga mga tipo sa programa nga gisuportahan sa 30 kernel), unya tan-awon naton kung giunsa pagsulat ang tinuod nga aplikasyon sa BPF gamit ang mga programa sa pagsubay sa kernel isip usa ka pananglitan, unya panahon na alang sa usa ka mas lawom nga kurso sa arkitektura sa BPF, nga gisundan sa mga pananglitan sa BPF networking ug mga aplikasyon sa seguridad.

Nauna nga mga artikulo niini nga serye

  1. BPF para sa mga gagmay, bahin zero: classic BPF

Mga link

  1. BPF ug XDP Reference Guide — dokumentasyon sa BPF gikan sa cilium, o mas tukma gikan kang Daniel Borkman, usa sa mga tiglalang ug tigmentinar sa BPF. Usa kini sa unang seryosong mga paghubit, nga lahi sa uban kay si Daniel nahibalo gayod kon unsa ang iyang gisulat ug walay mga sayop didto. Sa partikular, kini nga dokumento naghulagway kung giunsa ang pagtrabaho sa mga programa sa BPF sa mga tipo sa XDP ug TC gamit ang ilado nga utility. ip gikan sa package iproute2.

  2. Dokumentasyon/networking/filter.txt - orihinal nga file nga adunay dokumentasyon alang sa klasiko ug dayon gipalawig nga BPF. Usa ka maayong pagbasa kung gusto nimo mahibal-an ang sinultian sa asembliya ug mga detalye sa teknikal nga arkitektura.

  3. Blog bahin sa BPF gikan sa facebook. Talagsa ra kini gi-update, apan tukma, sama sa gisulat ni Alexei Starovoitov (tagsulat sa eBPF) ug Andrii Nakryiko - (maintainer) libbpf).

  4. Mga sekreto sa bpftool. Usa ka makalingaw nga twitter thread gikan sa Quentin Monnet nga adunay mga pananglitan ug mga sekreto sa paggamit sa bpftool.

  5. Dive ngadto sa BPF: usa ka listahan sa mga basahon nga materyal. Usa ka higante (ug gipadayon gihapon) nga lista sa mga link sa dokumentasyon sa BPF gikan sa Quentin Monnet.

Source: www.habr.com

Idugang sa usa ka comment