BPF għaż-żgħar, l-ewwel parti: BPF estiż

Fil-bidu kien hemm teknoloġija u kienet tissejjaħ BPF. Ħarisna lejha preċedenti, Artiklu tat-Testment il-Qadim ta’ din is-sensiela. Fl-2013, permezz tal-isforzi ta 'Aleksei Starovoitov u Daniel Borkman, verżjoni mtejba tagħha, ottimizzata għal magni moderni 64-bit, ġiet żviluppata u inkluża fil-kernel tal-Linux. Din it-teknoloġija ġdida kienet tissejjaħ fil-qosor Internal BPF, imbagħad issejħet mill-ġdid Extended BPF, u issa, wara diversi snin, kulħadd sempliċement isejħilha BPF.

Bejn wieħed u ieħor, BPF jippermettilek tħaddem kodiċi arbitrarju fornut mill-utent fl-ispazju tal-kernel tal-Linux, u l-arkitettura l-ġdida rriżulta li tant kellha suċċess li se jkollna bżonn tużżana aktar artikoli biex jiddeskrivu l-applikazzjonijiet kollha tagħha. (L-unika ħaġa li l-iżviluppaturi ma għamlux tajjeb, kif tistgħu taraw fil-kodiċi tal-prestazzjoni hawn taħt, kienet li ħolqu logo deċenti.)

Dan l-artikolu jiddeskrivi l-istruttura tal-magna virtwali BPF, interfaces tal-kernel biex taħdem ma 'BPF, għodod ta' żvilupp, kif ukoll ħarsa ġenerali qasira u qasira ħafna tal-kapaċitajiet eżistenti, i.e. dak kollu li se jkollna bżonn fil-futur għal studju aktar profond tal-applikazzjonijiet prattiċi tal-BPF.
BPF għaż-żgħar, l-ewwel parti: BPF estiż

Sommarju tal-artiklu

Introduzzjoni għall-arkitettura BPF. L-ewwel, aħna ser nieħdu ħarsa għajn ta 'l-arkitettura BPF u tiddeskrivi l-komponenti ewlenin.

Reġistri u sistema ta 'kmand tal-magna virtwali BPF. Diġà għandna idea tal-arkitettura kollha kemm hi, se niddeskrivu l-istruttura tal-magna virtwali BPF.

Ċiklu tal-ħajja ta 'oġġetti BPF, sistema ta' fajls bpffs. F'din it-taqsima, se nagħtu ħarsa aktar mill-qrib lejn iċ-ċiklu tal-ħajja ta 'oġġetti BPF - programmi u mapep.

Ġestjoni ta' oġġetti bl-użu tas-sejħa tas-sistema bpf. B'xi fehim tas-sistema diġà fis-seħħ, fl-aħħar se nħarsu lejn kif noħolqu u jimmanipulaw oġġetti mill-ispazju tal-utent billi tuża sejħa speċjali tas-sistema - bpf(2).

Пишем программы BPF с помощью libbpf. Naturalment, tista 'tikteb programmi billi tuża sejħa tas-sistema. Iżda huwa diffiċli. Għal xenarju aktar realistiku, programmaturi nukleari żviluppaw librerija libbpf. Aħna ser noħolqu skeletru bażiku ta 'applikazzjoni BPF li ser nużaw f'eżempji sussegwenti.

Kernel Helpers. Hawnhekk se nitgħallmu kif programmi BPF jistgħu jaċċessaw funzjonijiet helper tal-kernel - għodda li, flimkien mal-mapep, tespandi b'mod fundamentali l-kapaċitajiet tal-BPF il-ġdid meta mqabbla ma 'dak klassiku.

Aċċess għal mapep minn programmi BPF. Sa dan il-punt, se nkunu nafu biżżejjed biex nifhmu eżattament kif nistgħu noħolqu programmi li jużaw mapep. U ejja saħansitra nagħtu ħarsa ħafifa lejn il-verifikatur kbir u qawwi.

Għodod għall-iżvilupp. Sezzjoni ta 'għajnuna dwar kif tiġbor l-utilitajiet u l-qalba meħtieġa għall-esperimenti.

Il-konklużjoni. Fl-​aħħar tal-​artiklu, dawk li jaqraw s’issa jsibu kliem motivanti u deskrizzjoni qasira taʼ x’se jiġri fl-​artikoli li ġejjin. Se nilnukaw ukoll numru ta’ links għall-istudju personali għal dawk li m’għandhomx ix-xewqa jew il-ħila li jistennew il-kontinwazzjoni.

Introduzzjoni għall-Arkitettura BPF

Qabel ma nibdew nikkunsidraw l-arkitettura BPF, se nirreferu għall-aħħar darba (oh). BPF klassika, li ġiet żviluppata bħala tweġiba għall-miġja ta 'magni RISC u solvuta l-problema ta' filtrazzjoni effiċjenti tal-pakketti. L-arkitettura rriżultat li kellha suċċess tant li, wara li twieldet fid-disgħinijiet dashing f'Berkeley UNIX, ġiet trasferita għall-biċċa l-kbira tas-sistemi operattivi eżistenti, baqgħet ħaj fis-snin għoxrin miġnun u għadha qed issib applikazzjonijiet ġodda.

Il-BPF il-ġdid ġie żviluppat bħala reazzjoni għall-ubikwità ta' magni 64-bit, servizzi cloud u l-ħtieġa akbar għal għodod għall-ħolqien ta' SDN (Ssoftwer-ddefiniti networking). Żviluppat minn inġiniera tan-netwerk tal-qalba bħala sostitut imtejjeb għall-BPF klassiku, il-BPF il-ġdid litteralment sitt xhur wara sab applikazzjonijiet fil-kompitu diffiċli ta 'traċċar ta' sistemi Linux, u issa, sitt snin wara d-dehra tiegħu, se jkollna bżonn artiklu sħiħ li jmiss biss biex elenka t-tipi differenti ta' programmi.

Stampi umoristiċi

Fil-qalba tagħha, BPF hija magna virtwali sandbox li tippermettilek tħaddem kodiċi "arbitrarju" fl-ispazju tal-qalba mingħajr ma tikkomprometti s-sigurtà. Programmi BPF huma maħluqa fl-ispazju tal-utent, mgħobbija fil-qalba, u konnessi ma 'xi sors tal-avveniment. Avveniment jista 'jkun, pereżempju, il-kunsinna ta' pakkett għal interface tan-netwerk, it-tnedija ta 'xi funzjoni tal-kernel, eċċ. Fil-każ ta’ pakkett, il-programm BPF ikollu aċċess għad-dejta u l-metadejta tal-pakkett (għall-qari u, possibilment, għall-kitba, skont it-tip ta’ programm); fil-każ tat-tħaddim ta’ funzjoni tal-kernel, l-argumenti ta’ il-funzjoni, inklużi indikaturi għall-memorja tal-qalba, eċċ.

Ejja nagħtu ħarsa aktar mill-qrib lejn dan il-proċess. Biex tibda, ejja nitkellmu dwar l-ewwel differenza mill-BPF klassika, programmi li għalihom ġew miktuba f'assembler. Fil-verżjoni l-ġdida, l-arkitettura ġiet estiża sabiex il-programmi jkunu jistgħu jinkitbu f'lingwi ta 'livell għoli, primarjament, ovvjament, f'C. Għal dan, ġie żviluppat backend għal llvm, li jippermettilek li tiġġenera bytecode għall-arkitettura BPF.

BPF għaż-żgħar, l-ewwel parti: BPF estiż

L-arkitettura BPF kienet iddisinjata, parzjalment, biex taħdem b'mod effiċjenti fuq magni moderni. Biex dan jaħdem fil-prattika, il-bytecode BPF, ladarba jitgħabba fil-kernel, jiġi tradott f'kodiċi nattiv bl-użu ta' komponent imsejjaħ kompilatur JIT (Just In Time). Sussegwentement, jekk tiftakar, fil-BPF klassika l-programm kien mgħobbi fil-qalba u mehmuż mas-sors tal-avveniment atomikament - fil-kuntest ta 'sejħa tas-sistema waħda. Fl-arkitettura l-ġdida, dan iseħħ f'żewġ stadji - l-ewwel, il-kodiċi jitgħabba fil-qalba permezz ta 'sejħa tas-sistema bpf(2)u mbagħad, aktar tard, permezz ta 'mekkaniżmi oħra li jvarjaw skont it-tip ta' programm, il-programm jehmeż mas-sors tal-avveniment.

Hawnhekk il-qarrej jista’ jkollu mistoqsija: kien possibbli? Kif hija garantita s-sikurezza tal-eżekuzzjoni ta' tali kodiċi? Is-sikurezza tal-eżekuzzjoni hija ggarantita lilna mill-istadju tat-tagħbija tal-programmi BPF imsejħa verifikatur (bl-Ingliż dan l-istadju jissejjaħ verifikatur u se nkompli nuża l-kelma Ingliża):

BPF għaż-żgħar, l-ewwel parti: BPF estiż

Verifier huwa analizzatur statiku li jiżgura li programm ma jfixkilx l-operat normali tal-qalba. Dan, mill-mod, ma jfissirx li l-programm ma jistax jinterferixxi mat-tħaddim tas-sistema - programmi BPF, skond it-tip, jistgħu jaqraw u jikteb mill-ġdid sezzjonijiet tal-memorja tal-qalba, jirritorna valuri tal-funzjonijiet, trim, tehmeż, jikteb mill-ġdid u anke tibgħat pakketti tan-netwerk. Verifikatur jiggarantixxi li t-tħaddim ta 'programm BPF mhux se jikkraxxja l-kernel u li programm li, skont ir-regoli, għandu aċċess għall-kitba, pereżempju, id-dejta ta' pakkett ħerġin, ma jkunx jista 'jikteb fuq il-memorja tal-kernel barra l-pakkett. Se nħarsu lejn il-verifikatur fi ftit aktar dettall fit-taqsima korrispondenti, wara li nkunu familjari mal-komponenti l-oħra kollha ta 'BPF.

Allura x’tgħallimna s’issa? L-utent jikteb programm f'C, jgħabbih fil-qalba billi juża sejħa tas-sistema bpf(2), fejn jiġi ċċekkjat minn verifikatur u tradott f'bytecode nattiv. Imbagħad l-istess utent jew ieħor jgħaqqad il-programm mas-sors tal-avveniment u jibda jwettaq. Is-separazzjoni tal-boot u l-konnessjoni hija meħtieġa għal diversi raġunijiet. L-ewwelnett, it-tħaddim ta' verifikatur huwa relattivament għali u billi tniżżel l-istess programm diversi drabi naħlu l-ħin tal-kompjuter. It-tieni nett, eżattament kif programm huwa konness jiddependi fuq it-tip tiegħu, u interface wieħed "universali" żviluppat sena ilu jista 'ma jkunx adattat għal tipi ġodda ta' programmi. (Għalkemm issa li l-arkitettura qed issir aktar matura, hemm idea li tgħaqqad din l-interface fil-livell libbpf.)

Il-qarrej attent jista 'jinnota li għadna m'aħniex lesti bl-istampi. Tabilħaqq, dan kollu ta 'hawn fuq ma jispjegax għaliex BPF jibdel l-istampa b'mod fundamentali meta mqabbel ma' BPF klassiku. Żewġ innovazzjonijiet li jespandu b'mod sinifikanti l-ambitu tal-applikabilità huma l-abbiltà li tuża memorja kondiviża u funzjonijiet helper tal-kernel. Fil-BPF, il-memorja kondiviża hija implimentata bl-użu tal-hekk imsejħa mapep - strutturi tad-dejta kondiviżi b'API speċifika. Probabbilment kisbu dan l-isem minħabba li l-ewwel tip ta 'mappa li tidher kienet tabella hash. Imbagħad dehru arrays, tabelli tal-hash lokali (per-CPU) u arrays lokali, siġar tat-tiftix, mapep li fihom indikaturi għal programmi BPF u ħafna aktar. Dak li hu interessanti għalina issa huwa li l-programmi BPF issa għandhom il-kapaċità li jippersistu stat bejn sejħiet u jaqsmuh ma 'programmi oħra u ma' spazju għall-utent.

Mapep huwa aċċessat mill-proċessi tal-utent permezz ta 'sejħa tas-sistema bpf(2), u minn programmi BPF li jaħdmu fil-kernel bl-użu ta 'funzjonijiet helper. Barra minn hekk, helpers jeżistu mhux biss biex jaħdmu mal-mapep, iżda wkoll biex jaċċessaw kapaċitajiet oħra tal-kernel. Pereżempju, il-programmi BPF jistgħu jużaw funzjonijiet helper biex jgħaddu pakketti lil interfaces oħra, jiġġeneraw avvenimenti perf, jaċċessaw strutturi tal-kernel, eċċ.

BPF għaż-żgħar, l-ewwel parti: BPF estiż

Fil-qosor, BPF jipprovdi l-abbiltà li jgħabbi kodiċi tal-utent arbitrarju, jiġifieri, ittestjat mill-verifikatur, fl-ispazju tal-kernel. Dan il-kodiċi jista 'jiffranka l-istat bejn sejħiet u jiskambja data ma' spazju għall-utent, u għandu wkoll aċċess għal sottosistemi tal-kernel permessi minn dan it-tip ta 'programm.

Dan diġà huwa simili għall-kapaċitajiet ipprovduti mill-moduli tal-qalba, meta mqabbla magħhom BPF għandu xi vantaġġi (naturalment, tista 'biss tqabbel applikazzjonijiet simili, pereżempju, traċċar tas-sistema - ma tistax tikteb sewwieq arbitrarju b'BPF). Tista 'tinnota limitu ta' dħul aktar baxx (xi utilitajiet li jużaw BPF ma jeħtiġux li l-utent ikollu ħiliet ta 'programmar tal-kernel, jew ħiliet ta' programmar b'mod ġenerali), sigurtà tar-runtime (għolli idejk fil-kummenti għal dawk li ma kissrux is-sistema meta tikteb jew moduli ta 'ttestjar), l-atomiċità - hemm ħin ta' waqfien meta jerġgħu jitgħabbew il-moduli, u s-subsistema BPF tiżgura li l-ebda avveniment ma jintilef (biex inkunu ġusti, dan mhux minnu għat-tipi kollha ta 'programmi BPF).

Il-preżenza ta 'tali kapaċitajiet tagħmel BPF għodda universali għall-espansjoni tal-qalba, li hija kkonfermata fil-prattika: aktar u aktar tipi ġodda ta' programmi huma miżjuda ma 'BPF, aktar u aktar kumpaniji kbar jużaw BPF fuq servers tal-ġlieda kontra 24 × 7, aktar u aktar startups jibnu n-negozju tagħhom fuq soluzzjonijiet ibbażati fuqhom huma bbażati fuq BPF. BPF jintuża kullimkien: fil-protezzjoni kontra l-attakki DDoS, il-ħolqien ta 'SDN (per eżempju, l-implimentazzjoni ta' netwerks għal kubernetes), bħala l-għodda ewlenija ta 'traċċar tas-sistema u kollettur tal-istatistika, f'sistemi ta' skoperta ta 'intrużjoni u sistemi sandbox, eċċ.

Ejja nispiċċaw il-parti tal-ħarsa ġenerali tal-artiklu hawn u nħarsu lejn il-magna virtwali u l-ekosistema BPF f'aktar dettall.

Digressjoni: utilitajiet

Sabiex tkun tista’ tħaddem l-eżempji fit-taqsimiet li ġejjin, jista’ jkollok bżonn numru ta’ utilitajiet, mill-inqas llvm/clang bl-appoġġ bpf u bpftool... Fil-kapitolu Għodod għall-Iżvilupp Tista 'taqra l-istruzzjonijiet għall-assemblaġġ tal-utilitajiet, kif ukoll il-qalba tiegħek. Din it-taqsima titpoġġa hawn taħt sabiex ma tfixkelx l-armonija tal-preżentazzjoni tagħna.

BPF Reġistri tal-Magni Virtwali u Sistema ta' Istruzzjoni

L-arkitettura u s-sistema ta 'kmand ta' BPF ġew żviluppati b'kont meħud tal-fatt li l-programmi se jinkitbu fil-lingwa C u, wara t-tagħbija fil-kernel, jiġu tradotti f'kodiċi nattiv. Għalhekk, in-numru ta 'reġistri u s-sett ta' kmandi ġew magħżula b'għajnejhom għall-intersezzjoni, fis-sens matematiku, tal-kapaċitajiet tal-magni moderni. Barra minn hekk, ġew imposti diversi restrizzjonijiet fuq il-programmi, pereżempju, sa ftit ilu ma kienx possibbli li tikteb loops u subroutines, u n-numru ta 'struzzjonijiet kien limitat għal 4096 (issa programmi privileġġjati jistgħu jgħabbu sa miljun istruzzjonijiet).

BPF għandha ħdax-il reġistru 64-bit aċċessibbli għall-utent r0-r10 u counter tal-programm. Irreġistra r10 fih frame pointer u jinqara biss. Il-programmi għandhom aċċess għal munzell ta '512-byte waqt ir-runtime u ammont illimitat ta' memorja kondiviża fil-forma ta 'mapep.

Programmi BPF jitħallew imexxu sett speċifiku ta 'helpers tal-kernel tat-tip ta' programm u, aktar reċentement, funzjonijiet regolari. Kull funzjoni msejħa tista' tieħu sa ħames argumenti, mgħoddija fir-reġistri r1-r5, u l-valur tar-ritorn jiġi mgħoddi lil r0. Huwa garantit li wara r-ritorn mill-funzjoni, il-kontenut tar-reġistri r6-r9 Mhux se jinbidel.

Għal traduzzjoni effiċjenti tal-programm, reġistri r0-r11 għall-arkitetturi kollha appoġġjati huma mmappjati b'mod uniku għal reġistri reali, b'kont meħud tal-karatteristiċi ABI tal-arkitettura attwali. Per eżempju, għal x86_64 reġistri r1-r5, użati biex jgħaddu l-parametri tal-funzjoni, huma murija fuq rdi, rsi, rdx, rcx, r8, li huma użati biex jgħaddu parametri għal funzjonijiet fuq x86_64. Pereżempju, il-kodiċi fuq ix-xellug jittraduċi għall-kodiċi fuq il-lemin bħal dan:

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

Irreġistra r0 użat ukoll biex jirritorna r-riżultat tal-eżekuzzjoni tal-programm, u fir-reġistru r1 il-programm jiġi mgħoddi pointer għall-kuntest - skond it-tip ta 'programm, dan jista' jkun, pereżempju, struttura struct xdp_md (għal XDP) jew struttura struct __sk_buff (għal programmi tan-netwerk differenti) jew struttura struct pt_regs (għal tipi differenti ta’ programmi ta’ traċċar), eċċ.

Allura, kellna sett ta 'reġistri, helpers tal-qalba, munzell, pointer tal-kuntest u memorja kondiviża fil-forma ta' mapep. Mhux li dan kollu huwa assolutament meħtieġ fil-vjaġġ, iżda...

Ejja nkomplu d-deskrizzjoni u nitkellmu dwar is-sistema ta 'kmand biex taħdem ma' dawn l-oġġetti. Kollha (Kważi kollha) L-istruzzjonijiet BPF għandhom daqs fiss ta' 64 bit. Jekk tħares lejn struzzjoni waħda fuq magna Big Endian 64-bit tara

BPF għaż-żgħar, l-ewwel parti: BPF estiż

Hawnhekk Code - din hija l-kodifikazzjoni tal-istruzzjoni, Dst/Src huma l-kodifikazzjonijiet tar-riċevitur u s-sors, rispettivament, Off - Indentazzjoni ffirmata 16-bit, u Imm huwa numru sħiħ iffirmat ta' 32 bit użat f'xi struzzjonijiet (simili għall-kostanti cBPF K). Kodifikazzjoni Code għandu wieħed minn żewġ tipi:

BPF għaż-żgħar, l-ewwel parti: BPF estiż

Klassijiet ta 'struzzjoni 0, 1, 2, 3 jiddefinixxu kmandi biex taħdem bil-memorja. Huma huma msejħa, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, rispettivament. Klassijiet 4, 7 (BPF_ALU, BPF_ALU64) jikkostitwixxu sett ta' struzzjonijiet ALU. Klassijiet 5, 6 (BPF_JMP, BPF_JMP32) fihom istruzzjonijiet tal-qabża.

Il-pjan ulterjuri għall-istudju tas-sistema tal-istruzzjoni BPF huwa kif ġej: minflok ma nilnukaw b'mod metikoluż l-istruzzjonijiet kollha u l-parametri tagħhom, se nħarsu lejn ftit eżempji f'din it-taqsima u minnhom se jsir ċar kif l-istruzzjonijiet fil-fatt jaħdmu u kif għandhom manwalment żarma kwalunkwe fajl binarju għal BPF. Biex tikkonsolida l-materjal aktar tard fl-artikolu, aħna se niltaqgħu wkoll ma 'struzzjonijiet individwali fit-taqsimiet dwar Verifikatur, kompilatur JIT, traduzzjoni ta' BPF klassika, kif ukoll meta nistudjaw mapep, sejħa funzjonijiet, eċċ.

Meta nitkellmu dwar struzzjonijiet individwali, se nirreferu għall-fajls ewlenin bpf.h и bpf_common.h, li jiddefinixxu l-kodiċijiet numeriċi tal-istruzzjonijiet BPF. Meta tistudja l-arkitettura waħdek u/jew tparsing binarji, tista 'ssib is-semantika fis-sorsi li ġejjin, magħżula f'ordni ta' kumplessità: Speċifikazzjoni eBPF mhux uffiċjali, Gwida ta' Referenza BPF u XDP, Sett ta' Istruzzjonijiet, Dokumentazzjoni/netwerking/filter.txt u, ovvjament, fil-kodiċi tas-sors Linux - verifikatur, JIT, interpretu BPF.

Eżempju: iż-żarmar tal-BPF f'rasek

Ejja nħarsu lejn eżempju li fih niġbru programm readelf-example.c u ħares lejn il-binarju li jirriżulta. Aħna se niżvelaw il-kontenut oriġinali readelf-example.c hawn taħt, wara li nirrestawraw il-loġika tagħha minn kodiċi binarji:

$ 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 ................

L-ewwel kolonna fl-output readelf hija indentazzjoni u l-programm tagħna għalhekk jikkonsisti f'erba' kmandi:

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

Il-kodiċijiet tal-kmand huma ugwali b7, 15, b7 и 95. Ifakkar li l-inqas tliet bits sinifikanti huma l-klassi ta 'struzzjoni. Fil-każ tagħna, ir-raba 'bit tal-istruzzjonijiet kollha huwa vojt, għalhekk il-klassijiet tal-istruzzjoni huma 7, 5, 7, 5, rispettivament. Il-klassi 7 hija BPF_ALU64, u 5 hija BPF_JMP. Għaż-żewġ klassijiet, il-format tal-istruzzjoni huwa l-istess (ara hawn fuq) u nistgħu nerġgħu niktbu l-programm tagħna bħal dan (fl-istess ħin se nerġgħu nikteb il-kolonni li fadal f'forma umana):

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

Operazzjoni b klassi ALU64 - dan hu BPF_MOV. Jassenja valur lir-reġistru tad-destinazzjoni. Jekk il-bit ikun issettjat s (sors), allura l-valur jittieħed mir-reġistru tas-sors, u jekk, bħal fil-każ tagħna, ma jkunx issettjat, allura l-valur jittieħed mill-qasam Imm. Allura fl-ewwel u t-tielet istruzzjonijiet nagħmlu l-operazzjoni r0 = Imm. Barra minn hekk, JMP klassi 1 operazzjoni hija BPF_JEQ (qabża jekk ugwali). Fil-każ tagħna, peress li l-bit S hija żero, tqabbel il-valur tar-reġistru tas-sors mal-qasam Imm. Jekk il-valuri jikkoinċidu, allura t-tranżizzjoni sseħħ għal PC + Offfejn PC, bħas-soltu, fih l-indirizz tal-istruzzjoni li jmiss. Fl-aħħarnett, JMP Klassi 9 Operazzjoni hija BPF_EXIT. Din l-istruzzjoni ttemm il-programm, u terġa' lura għall-qalba r0. Ejja nżidu kolonna ġdida mat-tabella tagħna:

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

Nistgħu nerġgħu niktbu dan f'forma aktar konvenjenti:

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

Jekk niftakru x’inhu fir-reġistru r1 il-programm huwa mgħoddi pointer għall-kuntest mill-qalba, u fir-reġistru r0 il-valur jiġi rritornat lill-qalba, allura nistgħu naraw li jekk il-pointer għall-kuntest huwa żero, allura nirritornaw 1, u inkella - 2. Ejja niċċekkjaw li għandna raġun billi nħarsu lejn is-sors:

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

Iva, huwa programm bla sens, iżda jissarraf f'erba' istruzzjonijiet sempliċi biss.

Eżempju ta' eċċezzjoni: istruzzjoni ta' 16-il byte

Semmejna qabel li xi struzzjonijiet jieħdu aktar minn 64 bit. Dan japplika, pereżempju, għall-istruzzjonijiet lddw (Kodiċi = 0x18 = BPF_LD | BPF_DW | BPF_IMM) — tagħbija kelma doppja mill-fields fir-reġistru Imm. Il-fatt hu dak Imm għandha daqs ta '32, u kelma doppja hija 64 bit, għalhekk it-tagħbija ta' valur immedjat ta '64 bit f'reġistru fi istruzzjoni waħda ta' 64 bit mhux se taħdem. Biex tagħmel dan, jintużaw żewġ struzzjonijiet ħdejn xulxin biex jaħżnu t-tieni parti tal-valur 64-bit fil-qasam Imm. Eżempju:

$ 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                   ........

Hemm biss żewġ istruzzjonijiet fi programm binarju:

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

Se nerġgħu niltaqgħu bl-istruzzjonijiet lddw, meta nitkellmu dwar rilokazzjonijiet u ħidma mal-mapep.

Eżempju: iż-żarmar ta' BPF bl-użu ta' għodod standard

Għalhekk, tgħallimna naqraw il-kodiċi binarji BPF u lesti biex naqraw kwalunkwe istruzzjoni jekk meħtieġ. Madankollu, ta 'min jgħid li fil-prattika huwa aktar konvenjenti u aktar mgħaġġel li jiġu żarmati programmi bl-użu ta' għodod standard, pereżempju:

$ 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

Ċiklu tal-ħajja ta 'oġġetti BPF, sistema ta' fajls bpffs

(L-ewwel tgħallimt xi wħud mid-dettalji deskritti f'din is-subtaqsima minn post Alexei Starovoitov fi BPF Blog.)

Oġġetti BPF - programmi u mapep - huma maħluqa mill-ispazju tal-utent bl-użu ta 'kmandi BPF_PROG_LOAD и BPF_MAP_CREATE sejħa tas-sistema bpf(2), nitkellmu eżattament dwar kif dan jiġri fit-taqsima li jmiss. Dan joħloq strutturi tad-dejta tal-qalba u għal kull wieħed minnhom refcount (għadd ta' referenza) huwa ssettjat għal wieħed, u deskrittur tal-fajl li jipponta lejn l-oġġett jintbagħat lura lill-utent. Wara li l-manku jingħalaq refcount l-oġġett jitnaqqas b'wieħed, u meta jilħaq iż-żero, l-oġġett jinqered.

Jekk il-programm juża mapep, allura refcount dawn il-mapep jiżdiedu b'wieħed wara t-tagħbija tal-programm, i.e. id-deskritturi tal-fajl tagħhom jistgħu jingħalqu mill-proċess tal-utent u xorta refcount mhux se jsir żero:

BPF għaż-żgħar, l-ewwel parti: BPF estiż

Wara t-tagħbija b'suċċess ta 'programm, aħna ġeneralment nehmuh ma' xi tip ta 'ġeneratur tal-avvenimenti. Pereżempju, nistgħu npoġġuha fuq interface tan-netwerk biex nipproċessaw pakketti deħlin jew qabbadha ma 'xi wħud tracepoint fil-qalba. F'dan il-punt, il-counter ta 'referenza se jiżdied ukoll b'wieħed u se nkunu nistgħu nagħlqu d-deskrittur tal-fajl fil-programm tal-loader.

X'jiġri jekk issa nagħlqu l-bootloader? Jiddependi fuq it-tip ta 'ġeneratur tal-avvenimenti (ganċ). Il-ganċijiet tan-netwerk kollha se jeżistu wara li jitlesta l-loader, dawn huma l-hekk imsejħa ganċijiet globali. U, pereżempju, programmi ta 'traċċa se jiġu rilaxxati wara li l-proċess li ħoloqhom jintemm (u għalhekk jissejħu lokali, minn "lokali għall-proċess"). Teknikament, is-snanar lokali dejjem ikollhom deskrittur tal-fajl korrispondenti fl-ispazju tal-utent u għalhekk jagħlqu meta l-proċess jingħalaq, iżda l-ganċijiet globali le. Fil-figura li ġejja, bl-użu ta 'slaleb ħomor, nipprova nuri kif it-terminazzjoni tal-programm tal-loader taffettwa l-ħajja tal-oġġetti fil-każ ta' ganċijiet lokali u globali.

BPF għaż-żgħar, l-ewwel parti: BPF estiż

Għaliex hemm distinzjoni bejn ganċijiet lokali u globali? It-tħaddim ta 'xi tipi ta' programmi tan-netwerk jagħmel sens mingħajr spazju għall-utent, pereżempju, immaġina protezzjoni DDoS - il-bootloader jikteb ir-regoli u jgħaqqad il-programm BPF mal-interface tan-netwerk, u warajh il-bootloader jista 'jmur u joqtol lilu nnifsu. Min-naħa l-oħra, immaġina programm ta 'traċċa ta' debugging li ktibt fuq irkopptejk f'għaxar minuti - meta jkun lest, tixtieq li ma jibqax żibel fis-sistema, u ganċijiet lokali jiżguraw dan.

Min-naħa l-oħra, immaġina li trid tikkonnettja ma 'tracepoint fil-qalba u tiġbor statistika fuq ħafna snin. F'dan il-każ, tkun trid timla l-parti tal-utent u terġa 'lura għall-istatistika minn żmien għal żmien. Is-sistema tal-fajl bpf tipprovdi din l-opportunità. Hija sistema psewdo-fajl fil-memorja biss li tippermetti l-ħolqien ta’ fajls li jirreferu għal oġġetti BPF u b’hekk iżidu refcount oġġetti. Wara dan, il-loader jista 'joħroġ, u l-oġġetti li ħoloq jibqgħu ħajjin.

BPF għaż-żgħar, l-ewwel parti: BPF estiż

Il-ħolqien ta' fajls f'bpffs li jirreferu għall-oġġetti BPF jissejjaħ "pinning" (bħal fil-frażi li ġejja: "proċess jista' jimmarka programm jew mappa BPF"). Il-ħolqien ta' oġġetti ta' fajls għal oġġetti BPF jagħmel sens mhux biss għall-estensjoni tal-ħajja ta' oġġetti lokali, iżda wkoll għall-użabilità ta' oġġetti globali - billi tmur lura għall-eżempju bil-programm globali ta' protezzjoni DDoS, irridu nkunu nistgħu niġu u nħarsu lejn l-istatistika minn żmien għal żmien.

Is-sistema tal-fajls BPF normalment tkun immuntata /sys/fs/bpf, iżda jista' wkoll jiġi mmuntat lokalment, pereżempju, bħal dan:

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

Ismijiet tas-sistema tal-fajls huma maħluqa bl-użu tal-kmand BPF_OBJ_PIN Sejħa tas-sistema BPF. Biex nagħtu eżempju, ejja nieħdu programm, ikkumpilawh, ittellgħuh, u nipperfawh bpffs. Il-programm tagħna ma jagħmel xejn utli, aħna qed nippreżentaw biss il-kodiċi sabiex tkun tista' tirriproduċi l-eżempju:

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

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

Ejja niġbru dan il-programm u noħolqu kopja lokali tas-sistema tal-fajls bpffs:

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

Issa ejja tniżżel il-programm tagħna billi tuża l-utilità bpftool u ħares lejn is-sejħiet tas-sistema ta' akkumpanjament bpf(2) (xi linji irrilevanti mneħħija mill-output strace):

$ 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

Hawnhekk għandna mgħobbija l-programm bl-użu BPF_PROG_LOAD, irċieva deskrittur tal-fajl mill-qalba 3 u bl-użu tal-kmand BPF_OBJ_PIN ippinjat dan id-deskrittur tal-fajl bħala fajl "bpf-mountpoint/test". Wara dan il-programm bootloader bpftool lesta taħdem, iżda l-programm tagħna baqa 'fil-qalba, għalkemm aħna ma waħħalnieh ma' l-ebda interface tan-netwerk:

$ 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

Nistgħu nħassru l-oġġett tal-fajl normalment unlink(2) u wara dan il-programm korrispondenti jitħassar:

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

Tħassir ta' oġġetti

Meta wieħed jitkellem dwar it-tħassir ta 'oġġetti, huwa meħtieġ li jiġi ċċarat li wara li nkunu skonnettjaw il-programm mill-ganċ (ġeneratur ta' l-avvenimenti), l-ebda avveniment ġdid wieħed ma jikkawża t-tnedija tiegħu, madankollu, l-istanzi kurrenti kollha tal-programm se jitlestew fl-ordni normali. .

Xi tipi ta 'programmi BPF jippermettulek tissostitwixxi l-programm fuq il-fly, i.e. jipprovdu sekwenza atomiċità replace = detach old program, attach new program. F'dan il-każ, l-istanzi attivi kollha tal-verżjoni l-antika tal-programm se jispiċċaw ix-xogħol tagħhom, u se jinħolqu handlers ta 'avvenimenti ġodda mill-programm il-ġdid, u "atomiċità" hawnhekk tfisser li mhux se jintilef avveniment wieħed.

It-twaħħil ta' programmi ma' sorsi ta' avvenimenti

F'dan l-artikolu, mhux se niddeskrivu separatament programmi ta 'konnessjoni ma' sorsi ta 'avvenimenti, peress li jagħmel sens li nistudjaw dan fil-kuntest ta' tip speċifiku ta 'programm. Cm. eżempju hawn taħt, li fih nuru kif programmi bħal XDP huma konnessi.

Manipulazzjoni ta' Oġġetti Bl-użu tas-Sejħa tas-Sistema bpf

programmi BPF

L-oġġetti kollha tal-BPF huma maħluqa u ġestiti mill-ispazju tal-utent permezz ta' sejħa tas-sistema bpf, li għandu l-prototip li ġej:

#include <linux/bpf.h>

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

Hawn it-tim cmd huwa wieħed mill-valuri tat-tip enum bpf_cmd, attr — punter għal parametri għal programm speċifiku u size — id-daqs tal-oġġett skont il-pointer, i.e. normalment dan sizeof(*attr). Fil-kernel 5.8 is-sejħa tas-sistema bpf jappoġġja 34 kmandi differenti, u determinazzjoni ta ' union bpf_attr tokkupa 200 linja. Iżda m'għandniex inkunu intimidati b'dan, peress li se nkunu qed nifamiljarizzaw lilna nfusna mal-kmandi u l-parametri matul diversi artikli.

Nibdew bit-tim BPF_PROG_LOAD, li joħloq programmi BPF - jieħu sett ta 'struzzjonijiet BPF u jgħabbih fil-qalba. Fil-mument tat-tagħbija, il-verifikatur jiġi mniedi, u mbagħad il-kompilatur JIT u, wara eżekuzzjoni b'suċċess, id-deskrittur tal-fajl tal-programm jintbagħat lura lill-utent. Rajna x’jiġrilu wara fit-taqsima ta’ qabel dwar iċ-ċiklu tal-ħajja ta 'oġġetti BPF.

Issa se niktbu programm tad-dwana li se jgħabbi programm BPF sempliċi, iżda l-ewwel irridu niddeċiedu x’tip ta’ programm irridu tagħbija - ikollna nagħżlu Tip u fi ħdan il-qafas ta 'dan it-tip, ikteb programm li jgħaddi mit-test tal-verifikatur. Madankollu, sabiex ma tikkomplikax il-proċess, hawn soluzzjoni lesta: se nieħdu programm bħal BPF_PROG_TYPE_XDP, li se jirritorna l-valur XDP_PASS (aqbeż il-pakketti kollha). Fl-assemblatur BPF jidher sempliċi ħafna:

r0 = 2
exit

Wara li ddeċidejna li aħna se ntellgħu, nistgħu ngħidulek kif se nagħmluh:

#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();
}

Avvenimenti interessanti fi programm jibdew bid-definizzjoni ta 'firxa insns - il-programm BPF tagħna fil-kodiċi tal-magni. F'dan il-każ, kull istruzzjoni tal-programm BPF hija ppakkjata fl-istruttura bpf_insn. L-ewwel element insns jikkonforma mal-istruzzjonijiet r0 = 2, it-tieni - exit.

Irtir. Il-kernel jiddefinixxi macros aktar konvenjenti għall-kitba tal-kodiċijiet tal-magni, u l-użu tal-fajl header tal-kernel tools/include/linux/filter.h nistgħu niktbu

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

Iżda peress li l-kitba ta 'programmi BPF f'kodiċi nattiv hija meħtieġa biss għall-kitba ta' testijiet fil-qalba u artikli dwar BPF, in-nuqqas ta 'dawn il-macros ma jikkomplikax verament il-ħajja tal-iżviluppatur.

Wara li niddefinixxu l-programm BPF, ngħaddu għat-tagħbija tiegħu fil-qalba. Is-sett minimalista tagħna ta 'parametri attr jinkludi t-tip ta' programm, is-sett u n-numru ta' struzzjonijiet, il-liċenzja meħtieġa, u l-isem "woo", li nużaw biex insibu l-programm tagħna fuq is-sistema wara t-tniżżil. Il-programm, kif imwiegħed, jitgħabba fis-sistema permezz ta 'sejħa tas-sistema bpf.

Fl-aħħar tal-programm nispiċċaw f'linja infinita li tissimula t-tagħbija. Mingħajrha, il-programm jinqatel mill-qalba meta d-deskrittur tal-fajl li s-sejħa tas-sistema rritornatilna jingħalaq bpf, u mhux se narawha fis-sistema.

Ukoll, aħna lesti għall-ittestjar. Ejja niġbru u mexxi l-programm taħt stracebiex tiċċekkja li kollox qed jaħdem kif suppost:

$ 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(

Kollox sew, bpf(2) lura manku 3 lilna u aħna marru fis-linja infinita ma pause(). Ejja nippruvaw insibu l-programm tagħna fis-sistema. Biex nagħmlu dan se mmorru f'terminal ieħor u nużaw l-utilità 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)

Naraw li hemm programm mgħobbi fuq is-sistema woo li l-ID globali tiegħu hija 390 u bħalissa għaddejja simple-prog hemm deskrittur tal-fajl miftuħ li jindika l-programm (u jekk simple-prog se jispiċċa x-xogħol, allura woo se jisparixxi). Kif mistenni, il-programm woo jieħu 16-il byte - żewġ istruzzjonijiet - ta 'kodiċi binarji fl-arkitettura BPF, iżda fil-forma nattiva tagħha (x86_64) huwa diġà 40 bytes. Ejja nħarsu lejn il-programm tagħna fil-forma oriġinali tiegħu:

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

ebda sorpriża. Issa ejja nħarsu lejn il-kodiċi ġġenerat mill-kompilatur JIT:

# 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

mhux effettiv ħafna għal exit(2), iżda b'mod ġust, il-programm tagħna huwa sempliċi wisq, u għal programmi mhux trivjali l-prologu u l-epilogue miżjuda mill-kompilatur JIT huma, ovvjament, meħtieġa.

Mapep

Programmi BPF jistgħu jużaw żoni ta' memorja strutturata li huma aċċessibbli kemm għal programmi BPF oħra kif ukoll għal programmi fl-ispazju tal-utent. Dawn l-oġġetti jissejħu mapep u f'din it-taqsima ser nuru kif timmanipulahom permezz ta' sejħa tas-sistema bpf.

Ejja ngħidu mill-ewwel li l-kapaċitajiet tal-mapep mhumiex limitati biss għall-aċċess għall-memorja kondiviża. Hemm mapep għal skopijiet speċjali li fihom, pereżempju, indikaturi għal programmi BPF jew indikaturi għal interfaces tan-netwerk, mapep biex taħdem ma 'avvenimenti perf, eċċ. Mhux se nitkellmu dwarhom hawn, biex ma nħawdux lill-qarrej. Barra minn dan, aħna ninjoraw kwistjonijiet ta 'sinkronizzazzjoni, peress li dan mhuwiex importanti għall-eżempji tagħna. Lista kompluta tat-tipi ta' mapep disponibbli tista' tinstab fi <linux/bpf.h>, u f'din it-taqsima se nieħdu bħala eżempju l-ewwel tip storikament, it-tabella hash BPF_MAP_TYPE_HASH.

Jekk inti toħloq tabella hash fi, ngħidu aħna, C++, inti tgħid unordered_map<int,long> woo, li bir-Russu tfisser “Għandi bżonn mejda woo daqs illimitat, li ċ-ċwievet tagħhom huma tat-tip int, u l-valuri huma t-tip long" Sabiex noħolqu tabella hash BPF, irridu nagħmlu ħafna l-istess ħaġa, ħlief li rridu nispeċifikaw id-daqs massimu tat-tabella, u minflok ma nispeċifikaw it-tipi ta 'ċwievet u valuri, irridu nispeċifikaw id-daqsijiet tagħhom f'bytes. . Biex toħloq mapep uża l-kmand BPF_MAP_CREATE sejħa tas-sistema bpf. Ejja nħarsu lejn programm xi ftit jew wisq minimu li joħloq mappa. Wara l-programm preċedenti li jgħabbi l-programmi BPF, dan għandu jidher sempliċi għalik:

$ 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();
}

Hawnhekk niddefinixxu sett ta 'parametri attr, li fiha ngħidu “Għandi bżonn tabella hash b’ċwievet u valuri tad-daqs sizeof(int), li fiha nista' npoġġi massimu ta' erba' elementi." Meta toħloq mapep BPF, tista 'tispeċifika parametri oħra, pereżempju, bl-istess mod bħal fl-eżempju mal-programm, speċifikajna l-isem tal-oġġett kif "woo".

Ejja niġbru u nħaddmu l-programm:

$ 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(

Hawn is-sejħa tas-sistema bpf(2) lura lilna n-numru tal-mappa deskrittur 3 u mbagħad il-programm, kif mistenni, jistenna għal aktar istruzzjonijiet fis-sejħa tas-sistema pause(2).

Issa ejja nibagħtu l-programm tagħna fl-isfond jew tiftaħ terminal ieħor u nħarsu lejn l-oġġett tagħna billi tuża l-utilità bpftool (nistgħu niddistingwu l-mappa tagħna minn oħrajn b'isimha):

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

In-numru 114 huwa l-ID globali tal-oġġett tagħna. Kwalunkwe programm fis-sistema jista 'juża din l-ID biex tiftaħ mappa eżistenti billi tuża l-kmand BPF_MAP_GET_FD_BY_ID sejħa tas-sistema bpf.

Issa nistgħu nilagħbu bit-tabella tal-hash tagħna. Ejja nħarsu lejn il-kontenut tiegħu:

$ sudo bpftool map dump id 114
Found 0 elements

Vojta. Ejja npoġġu valur fiha hash[1] = 1:

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

Ejja nerġgħu nħarsu lejn it-tabella:

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

Ħura! Irnexxielna nżidu element wieħed. Innota li rridu naħdmu fil-livell tal-byte biex nagħmlu dan, peress li bptftool ma jafx x'tip huma l-valuri fit-tabella tal-hash. (Dan l-għarfien jista 'jiġi trasferit lilha bl-użu ta' BTF, iżda aktar dwar dan issa.)

Kif eżattament bpftool jaqra u jżid elementi? Ejja nagħtu ħarsa taħt il-barnuża:

$ 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

L-ewwel ftaħna l-mappa bl-ID globali tagħha billi tuża l-kmand BPF_MAP_GET_FD_BY_ID и bpf(2) lura lilna deskrittur 3. Aktar użu tal-kmand BPF_MAP_GET_NEXT_KEY sibna l-ewwel ċavetta fit-tabella billi tgħaddi NULL bħala pointer lejn iċ-ċavetta "preċedenti". Jekk ikollna ċ-ċavetta nistgħu nagħmlu BPF_MAP_LOOKUP_ELEMli jirritorna valur għal pointer value. Il-pass li jmiss huwa li nippruvaw insibu l-element li jmiss billi ngħaddu pointer għaċ-ċavetta kurrenti, iżda t-tabella tagħna fiha biss element wieħed u l-kmand BPF_MAP_GET_NEXT_KEY prospetti ENOENT.

Tajjeb, ejja nbiddlu l-valur biċ-ċavetta 1, ejja ngħidu li l-loġika tan-negozju tagħna teħtieġ li nirreġistraw 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

Kif mistenni, huwa sempliċi ħafna: il-kmand BPF_MAP_GET_FD_BY_ID jiftaħ il-mappa tagħna bl-ID, u l-kmand BPF_MAP_UPDATE_ELEM jissostitwixxi l-element.

Għalhekk, wara li ħoloq tabella hash minn programm wieħed, nistgħu naqraw u niktbu l-kontenut tagħha minn ieħor. Innota li jekk konna kapaċi nagħmlu dan mil-linja tal-kmand, allura kwalunkwe programm ieħor fuq is-sistema jista 'jagħmel dan. Minbarra l-kmandi deskritti hawn fuq, biex taħdem ma’ mapep mill-ispazju tal-utent, Is-segwenti:

  • BPF_MAP_LOOKUP_ELEM: issib il-valur biċ-ċavetta
  • BPF_MAP_UPDATE_ELEM: taġġorna/toħloq valur
  • BPF_MAP_DELETE_ELEM: neħħi ċ-ċavetta
  • BPF_MAP_GET_NEXT_KEY: sib iċ-ċavetta li jmiss (jew l-ewwel).
  • BPF_MAP_GET_NEXT_ID: jippermettilek tgħaddi mill-mapep kollha eżistenti, hekk taħdem bpftool map
  • BPF_MAP_GET_FD_BY_ID: tiftaħ mappa eżistenti mill-ID globali tagħha
  • BPF_MAP_LOOKUP_AND_DELETE_ELEM: taġġorna atomikament il-valur ta 'oġġett u rritorna l-antik
  • BPF_MAP_FREEZE: tagħmel il-mappa immutabbli mill-ispazju tal-utent (din l-operazzjoni ma tistax titneħħa)
  • BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, BPF_MAP_UPDATE_BATCH, BPF_MAP_DELETE_BATCH: operazzjonijiet tal-massa. Pereżempju, BPF_MAP_LOOKUP_AND_DELETE_BATCH - dan huwa l-uniku mod affidabbli biex taqra u tirrisettja l-valuri kollha mill-mappa

Mhux dawn il-kmandi kollha jaħdmu għat-tipi kollha ta 'mapep, iżda b'mod ġenerali l-ħidma ma' tipi oħra ta 'mapep mill-ispazju tal-utent tidher eżattament l-istess bħal taħdem ma' tabelli hash.

Għall-fini tal-ordni, ejja nispiċċaw l-esperimenti tal-hash table tagħna. Ftakar li ħloqna tabella li jista' jkun fiha sa erba' ċwievet? Ejja nżidu ftit elementi oħra:

$ 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

S'issa tajjeb:

$ 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

Ejja nippruvaw inżidu waħda oħra:

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

Kif kien mistenni, ma rnexxilniex. Ejja nħarsu lejn l-iżball f'aktar dettall:

$ 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 +++

Kollox tajjeb: kif mistenni, it-tim BPF_MAP_UPDATE_ELEM jipprova joħloq ċavetta ġdida, il-ħames, iżda tiġġarraf E2BIG.

Allura, nistgħu noħolqu u tagħbija programmi BPF, kif ukoll noħolqu u jimmaniġġjaw mapep mill-ispazju tal-utent. Issa huwa loġiku li nħarsu lejn kif nistgħu nużaw mapep mill-programmi BPF infushom. Nistgħu nitkellmu dwar dan fil-lingwa tal-programmi diffiċli biex jinqraw fil-kodiċi makro tal-magni, iżda fil-fatt wasal iż-żmien li nuru kif il-programmi BPF huma attwalment miktuba u miżmuma - bl-użu libbpf.

(Għall-qarrejja li mhumiex sodisfatti bin-nuqqas ta’ eżempju ta’ livell baxx: se nanalizzaw fid-dettall programmi li jużaw mapep u funzjonijiet helper maħluqa bl-użu libbpf u jgħidlek x'jiġri fil-livell ta' istruzzjoni. Għal qarrejja li mhumiex sodisfatti ħafna, żidna eżempju fil-post xieraq fl-artikolu.)

Kitba ta 'programmi BPF bl-użu libbpf

Il-kitba ta 'programmi BPF bl-użu ta' kodiċijiet tal-magni tista 'tkun interessanti l-ewwel darba biss, u mbagħad ix-xaba' tidħol. F'dan il-mument trid iddawwar l-attenzjoni tiegħek llvm, li għandu backend biex jiġġenera kodiċi għall-arkitettura BPF, kif ukoll librerija libbpf, li jippermettilek tikteb in-naħa tal-utent tal-applikazzjonijiet BPF u tgħabbi l-kodiċi tal-programmi BPF iġġenerati bl-użu llvm/clang.

Fil-fatt, kif se naraw f’dan l-artikoli u dawk ta’ wara, libbpf jagħmel ħafna xogħol mingħajru (jew għodda simili - iproute2, libbcc, libbpf-go, eċċ.) huwa impossibbli li tgħix. Waħda mill-karatteristiċi qattiel tal-proġett libbpf huwa BPF CO-RE (Kompila Darba, Mexxi Kullimkien) - proġett li jippermettilek tikteb programmi BPF li jistgħu jinġarru minn għadma għal oħra, bil-kapaċità li taħdem fuq APIs differenti (per eżempju, meta l-istruttura tal-kernel tinbidel mill-verżjoni għall-verżjoni). Sabiex tkun tista 'taħdem ma' CO-RE, il-qalba tiegħek trid tkun ikkumpilata b'appoġġ BTF (niddeskrivu kif tagħmel dan fit-taqsima Għodod għall-Iżvilupp. Tista 'tiċċekkja jekk il-qalba tiegħek hijiex mibnija b'BTF jew mhux sempliċiment ħafna - bil-preżenza tal-fajl li ġej:

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

Dan il-fajl jaħżen informazzjoni dwar it-tipi kollha tad-dejta użati fil-qalba u jintuża fl-eżempji kollha tagħna bl-użu libbpf. Aħna se nitkellmu fid-dettall dwar CO-RE fl-artiklu li jmiss, iżda f'dan wieħed - biss ibni lilek innifsek għadma b' CONFIG_DEBUG_INFO_BTF.

Librerija libbpf jgħix dritt fid-direttorju tools/lib/bpf kernel u l-iżvilupp tiegħu jitwettaq permezz tal-lista tal-posta [email protected]. Madankollu, jinżamm repożitorju separat għall-bżonnijiet tal-applikazzjonijiet li jgħixu barra l-kernel https://github.com/libbpf/libbpf li fiha l-librerija tal-kernel hija riflessa għal aċċess għall-qari bejn wieħed u ieħor kif inhu.

F'din it-taqsima se nħarsu lejn kif tista 'toħloq proġett li juża libbpf, ejja niktbu diversi programmi tat-test (ftit jew inqas bla sens) u janalizzaw fid-dettall kif jaħdem kollox. Dan se jippermettilna nispjegaw aktar faċilment fit-taqsimiet li ġejjin eżattament kif il-programmi BPF jinteraġixxu ma 'mapep, helpers tal-kernel, BTF, eċċ.

Tipikament proġetti li jużaw libbpf żid repożitorju GitHub bħala submodulu git, aħna nagħmlu l-istess:

$ 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.

Sejjer libbpf sempliċi ħafna:

$ 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

Il-pjan li jmiss tagħna f'din it-taqsima huwa kif ġej: aħna se niktbu programm BPF bħal BPF_PROG_TYPE_XDP, l-istess bħal fl-eżempju ta 'qabel, iżda f'Ċ, niġbruha bl-użu clang, u ikteb programm helper li jgħabbih fil-qalba. Fis-sezzjonijiet li ġejjin se nespandu l-kapaċitajiet kemm tal-programm BPF kif ukoll tal-programm tal-assistent.

Eżempju: ħolqien ta' applikazzjoni sħiħa bl-użu ta' libbpf

Biex tibda, nużaw il-fajl /sys/kernel/btf/vmlinux, li ssemma hawn fuq, u toħloq l-ekwivalenti tagħha fil-forma ta’ fajl header:

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

Dan il-fajl se jaħżen l-istrutturi tad-dejta kollha disponibbli fil-kernel tagħna, pereżempju, dan huwa kif l-header IPv4 huwa definit fil-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;
};

Issa se niktbu l-programm BPF tagħna f'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";

Għalkemm il-programm tagħna rriżulta li kien sempliċi ħafna, xorta rridu nagħtu attenzjoni għal ħafna dettalji. L-ewwel, l-ewwel fajl header li ninkludu huwa vmlinux.h, li aħna biss ġġeneraw bl-użu bpftool btf dump - issa m'għandniex bżonn ninstallaw il-pakkett tal-kernel-headers biex insiru nafu kif jidhru l-istrutturi tal-kernel. Il-fajl header li ġej jiġi lilna mil-librerija libbpf. Issa għandna bżonnha biss biex niddefinixxu l-makro SEC, li jibgħat il-karattru fit-taqsima xierqa tal-fajl tal-oġġett ELF. Il-programm tagħna jinsab fit-taqsima xdp/simple, fejn qabel is-slash niddefinixxu t-tip ta' programm BPF - din hija l-konvenzjoni użata fi libbpf, ibbażat fuq l-isem tat-taqsima se jissostitwixxi t-tip korrett fl-istartjar bpf(2). Il-programm BPF innifsu huwa C - sempliċi ħafna u tikkonsisti f'linja waħda return XDP_PASS. Fl-aħħarnett, taqsima separata "license" fih l-isem tal-liċenzja.

Nistgħu niġbru l-programm tagħna billi tuża llvm/clang, verżjoni>= 10.0.0, jew aħjar, akbar (ara t-taqsima Għodod għall-Iżvilupp):

$ 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

Fost il-karatteristiċi interessanti: aħna nindikaw l-arkitettura fil-mira -target bpf u l-mogħdija għall-headers libbpf, li installajna dan l-aħħar. Ukoll, tinsiex dwar -O2, mingħajr din l-għażla tista' tkun għal sorpriżi fil-futur. Ejja nħarsu lejn il-kodiċi tagħna, irnexxielna niktbu l-programm li ridna?

$ 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

Iva, ħadem! Issa, għandna fajl binarju mal-programm, u rridu noħolqu applikazzjoni li tagħbijaha fil-qalba. Għal dan il-għan il-librerija libbpf toffrilna żewġ għażliet - uża API ta 'livell aktar baxx jew API ta' livell ogħla. Se mmorru t-tieni triq, peress li rridu nitgħallmu kif niktbu, tagħbija u qabbad programmi BPF bi sforz minimu għall-istudju sussegwenti tagħhom.

L-ewwel, irridu niġġeneraw l-"iskeletru" tal-programm tagħna mill-binarju tiegħu billi tuża l-istess utilità bpftool — is-sikkina Żvizzera tad-dinja tal-BPF (li tista’ tittieħed litteralment, peress li Daniel Borkman, wieħed mill-ħallieqa u l-mantenituri tal-BPF, huwa Żvizzeru):

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

Fil-fajl xdp-simple.skel.h fih il-kodiċi binarju tal-programm tagħna u l-funzjonijiet għall-ġestjoni - it-tagħbija, it-twaħħil, it-tħassir tal-oġġett tagħna. Fil-każ sempliċi tagħna dan jidher qisu overkill, iżda jaħdem ukoll fil-każ fejn il-fajl tal-oġġett ikun fih ħafna programmi u mapep BPF u biex tagħbija dan l-ELF ġgant irridu biss niġġeneraw l-iskeletru u nsejħu funzjoni waħda jew tnejn mill-applikazzjoni tad-dwana aħna qed tikteb Ejja nimxu fuq issa.

Strettament, il-programm tal-loader tagħna huwa trivjali:

#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);
}

Hawnhekk struct xdp_simple_bpf definiti fil-fajl xdp-simple.skel.h u jiddeskrivi l-fajl tal-oġġett tagħna:

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;
};

Nistgħu naraw traċċi ta 'API ta' livell baxx hawn: l-istruttura struct bpf_program *simple и struct bpf_link *simple. L-ewwel struttura tiddeskrivi speċifikament il-programm tagħna, miktub fit-taqsima xdp/simple, u t-tieni jiddeskrivi kif il-programm jgħaqqad mas-sors tal-avveniment.

Funzjoni xdp_simple_bpf__open_and_load, jiftaħ oġġett ELF, janalizzah, joħloq l-istrutturi u s-sottostrutturi kollha (minbarra l-programm, ELF fih ukoll sezzjonijiet oħra - data, data readonly, informazzjoni ta’ debugging, liċenzja, eċċ.), u mbagħad jgħabbiha fil-qalba billi tuża sistema ċempel bpf, li nistgħu niċċekkjaw billi niġbru u nħaddmu l-programm:

$ 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

Ejja issa nħarsu lejn il-programm tagħna bl-użu bpftool. Ejja nsibu l-ID tagħha:

# 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)

u dump (nużaw forma mqassra tal-kmand bpftool prog dump xlated):

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

Xi ħaġa ġdida! Il-programm stampa biċċiet tal-fajl tas-sors C tagħna. Dan sar mil-librerija libbpf, li sabet it-taqsima tad-debug fil-binarju, ikkumpilaha f'oġġett BTF, għabbiha fil-qalba bl-użu BPF_BTF_LOAD, u mbagħad speċifikat id-deskrittur tal-fajl li jirriżulta meta tgħabbi l-programm bil-kmand BPG_PROG_LOAD.

Kernel Helpers

Programmi BPF jistgħu jmexxu funzjonijiet "esterni" - helpers tal-qalba. Dawn il-funzjonijiet helper jippermettu lill-programmi BPF jaċċessaw strutturi tal-kernel, jimmaniġġjaw mapep, u jikkomunikaw ukoll mad-"dinja reali" - joħolqu avvenimenti perf, jikkontrollaw ħardwer (pereżempju, pakketti mill-ġdid), eċċ.

Eżempju: bpf_get_smp_processor_id

Fil-qafas tal-paradigma "tagħlim bl-eżempju", ejja nikkunsidraw waħda mill-funzjonijiet helper, bpf_get_smp_processor_id(), ċerti fil-fajl kernel/bpf/helpers.c. Jirritorna n-numru tal-proċessur li fuqu qed jaħdem il-programm BPF li sejjaħlu. Imma m'aħniex interessati fis-semantika tagħha daqs il-fatt li l-implimentazzjoni tagħha tieħu linja waħda:

BPF_CALL_0(bpf_get_smp_processor_id)
{
    return smp_processor_id();
}

Id-definizzjonijiet tal-funzjoni helper BPF huma simili għad-definizzjonijiet tas-sejħiet tas-sistema Linux. Hawnhekk, pereżempju, funzjoni hija definita li m'għandhiex argumenti. (Funzjoni li tieħu, ngħidu aħna, tliet argumenti hija definita bl-użu tal-makro BPF_CALL_3. In-numru massimu ta' argumenti huwa ħamsa.) Madankollu, din hija biss l-ewwel parti tad-definizzjoni. It-tieni parti hija li tiddefinixxi l-istruttura tat-tip struct bpf_func_proto, li fiha deskrizzjoni tal-funzjoni helper li l-verifikatur jifhem:

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

Reġistrar Funzjonijiet Helper

Sabiex programmi BPF ta 'tip partikolari jużaw din il-funzjoni, għandhom jirreġistrawha, pereżempju għat-tip BPF_PROG_TYPE_XDP funzjoni hija definita fil-qalba xdp_func_proto, li jiddetermina mill-ID tal-funzjoni helper jekk XDP jappoġġjax din il-funzjoni jew le. Il-funzjoni tagħna hija jappoġġja:

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;
    ...
    }
}

Tipi ġodda ta' programmi BPF huma "definiti" fil-fajl include/linux/bpf_types.h bl-użu ta' makro BPF_PROG_TYPE. Iddefinita bil-kwotazzjonijiet minħabba li hija definizzjoni loġika, u f'termini tal-lingwa Ċ id-definizzjoni ta 'sett sħiħ ta' strutturi konkreti sseħħ f'postijiet oħra. B'mod partikolari, fil-fajl kernel/bpf/verifier.c id-definizzjonijiet kollha mill-fajl bpf_types.h huma użati biex joħolqu firxa ta 'strutturi 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
};

Jiġifieri, għal kull tip ta 'programm BPF, huwa definit pointer għal struttura ta' data tat-tip struct bpf_verifier_ops, li hija inizjalizzata bil-valur _name ## _verifier_ops, jiġifieri, xdp_verifier_ops għall- xdp. Struttura xdp_verifier_ops determinat minn fil-fajl net/core/filter.c kif ġej:

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,
};

Hawnhekk naraw il-funzjoni familjari tagħna xdp_func_proto, li se jmexxi l-verifikatur kull darba li jiltaqa 'ma' sfida xi wħud funzjonijiet ġewwa programm BPF, ara verifier.c.

Ejja nħarsu lejn kif programm BPF ipotetiku juża l-funzjoni bpf_get_smp_processor_id. Biex tagħmel dan, nerġgħu niktbu l-programm mit-taqsima preċedenti tagħna kif ġej:

#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";

Simbolu bpf_get_smp_processor_id determinat minn в <bpf/bpf_helper_defs.h> libreriji libbpf kif

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

jiġifieri, bpf_get_smp_processor_id huwa punter tal-funzjoni li l-valur tiegħu huwa 8, fejn 8 huwa l-valur BPF_FUNC_get_smp_processor_id tip enum bpf_fun_id, li hija definita għalina fil-fajl vmlinux.h (fajl bpf_helper_defs.h fil-qalba hija ġġenerata minn skript, għalhekk in-numri "maġiċi" huma ok). Din il-funzjoni ma tieħu l-ebda argument u tirritorna valur tat-tip __u32. Meta nħaddmuh fil-programm tagħna, clang jiġġenera struzzjoni BPF_CALL "it-tip it-tajjeb" Ejja niġbru l-programm u nħarsu lejn it-taqsima 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

Fl-ewwel linja naraw l-istruzzjonijiet call, parametru IMM li huwa ugwali għal 8, u SRC_REG - żero. Skont il-ftehim ABI użat mill-verifikatur, din hija sejħa għall-funzjoni helper numru tmienja. Ladarba titnieda, il-loġika hija sempliċi. Valur lura mir-reġistru r0 ikkupjat lil r1 u fuq il-linji 2,3 huwa kkonvertit għat-tip u32 — it-32 bit ta' fuq huma mneħħija. Fuq il-linji 4,5,6,7 nirritornaw 2 (XDP_PASS) jew 1 (XDP_DROP) skond jekk il-funzjoni helper mil-linja 0 rritornatx valur żero jew mhux żero.

Ejja nittestjaw lilna nfusna: tagħbija l-programm u nħarsu lejn l-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, il-verifikatur sab il-kernel-helper korrett.

Eżempju: tgħaddi l-argumenti u finalment tmexxi l-programm!

Il-funzjonijiet kollha tal-helper fil-livell tal-ġirja għandhom prototip

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

Parametri għall-funzjonijiet helper huma mgħoddija fir-reġistri r1-r5, u l-valur jiġi rritornat fir-reġistru r0. M'hemm l-ebda funzjonijiet li jieħdu aktar minn ħames argumenti, u l-appoġġ għalihom mhux mistenni li jiżdied fil-futur.

Ejja nagħtu ħarsa lejn il-helper tal-kernel il-ġdid u kif BPF jgħaddi l-parametri. Ejja nikteb mill-ġdid xdp-simple.bpf.c kif ġej (il-bqija tal-linji ma nbidlux):

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

Il-programm tagħna jistampa n-numru tas-CPU li qed jaħdem fuqu. Ejja niġbruha u nħarsu lejn il-kodiċi:

$ 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

Fil-linji 0-7 niktbu s-sekwenza running on CPU%un, u mbagħad fuq il-linja 8 nħaddmu dik familjari bpf_get_smp_processor_id. Fuq il-linji 9-12 nippreparaw l-argumenti tal-helper bpf_printk - reġistri r1, r2, r3. Għaliex hemm tlieta minnhom u mhux tnejn? Għax bpf_printkdan huwa tgeżwir makro madwar l-helper reali bpf_trace_printk, li jeħtieġ li jgħaddi d-daqs tas-sekwenza tal-format.

Ejja issa żid ftit linji xdp-simple.csabiex il-programm tagħna jgħaqqad mal-interface lo u verament beda!

$ 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);
}

Hawnhekk nużaw il-funzjoni bpf_set_link_xdp_fd, li jgħaqqad programmi BPF tat-tip XDP ma 'interfaces tan-netwerk. Aħna hardcoded in-numru tal-interface lo, li huwa dejjem 1. Aħna nmexxu l-funzjoni darbtejn biex l-ewwel jinqalgħu l-programm l-antik jekk kien imwaħħal. Innota li issa m'għandniex bżonn sfida pause jew linja infinita: il-programm tal-loader tagħna se joħroġ, iżda l-programm BPF mhux se jinqatel peress li huwa konness mas-sors tal-avveniment. Wara tniżżil u konnessjoni b'suċċess, il-programm se jiġi mniedi għal kull pakkett tan-netwerk li jasal lo.

Ejja niżżlu l-programm u nħarsu lejn l-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

Il-programm li niżżilna għandu ID 669 u naraw l-istess ID fuq l-interface lo. Aħna nibagħtu ftit pakketti lil 127.0.0.1 (talba + tweġiba):

$ ping -c1 localhost

u issa ejja nħarsu lejn il-kontenut tal-fajl virtwali tad-debug /sys/kernel/debug/tracing/trace_pipe, F'liema bpf_printk jikteb il-messaġġi tiegħu:

# 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

Żewġ pakketti ġew spotted fuq lo u pproċessati fuq CPU0 - l-ewwel programm sħiħ tagħna BPF bla sens ħadem!

Ta 'min jinnota li bpf_printk Mhux ta 'xejn li jikteb fil-fajl tad-debug: dan mhuwiex l-aktar helper ta' suċċess għall-użu fil-produzzjoni, iżda l-għan tagħna kien li nuru xi ħaġa sempliċi.

Aċċess mapep minn programmi BPF

Eżempju: bl-użu ta' mappa mill-programm BPF

Fis-sezzjonijiet preċedenti tgħallimna kif noħolqu u nużaw mapep mill-ispazju tal-utent, u issa ejja nħarsu lejn il-parti tal-kernel. Nibdew, bħas-soltu, b'eżempju. Ejja nikteb mill-ġdid il-programm tagħna xdp-simple.bpf.c kif ġej:

#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";

Fil-bidu tal-programm żidna definizzjoni tal-mappa woo: Din hija firxa ta '8 elementi li taħżen valuri simili u64 (f'C aħna niddefinixxu array bħal u64 woo[8]). Fi programm "xdp/simple" nikbru n-numru tal-proċessur attwali f'varjabbli key u mbagħad tuża l-funzjoni helper bpf_map_lookup_element aħna tikseb pointer għall-entrata korrispondenti fil-firxa, li aħna nżidu b'wieħed. Tradott għar-Russu: aħna nikkalkulaw statistika dwar liema CPU pproċessa pakketti deħlin. Ejja nippruvaw inħaddmu l-programm:

$ 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

Ejja niċċekkjaw li hija mqabbda magħha lo u ibgħat xi pakketti:

$ 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

Issa ejja nħarsu lejn il-kontenut tal-firxa:

$ 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 }
]

Kważi l-proċessi kollha ġew ipproċessati fuq CPU7. Dan mhux importanti għalina, il-ħaġa prinċipali hija li l-programm jaħdem u nifhmu kif naċċessaw mapep minn programmi BPF - bl-użu хелперов bpf_mp_*.

Indiċi mistiku

Allura, nistgħu aċċess għall-mappa mill-programm BPF billi tuża sejħiet bħal

val = bpf_map_lookup_elem(&woo, &key);

fejn il-funzjoni helper tidher qisha

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

imma qed ngħaddu pointer &woo għal struttura bla isem struct { ... }...

Jekk inħarsu lejn l-assembler tal-programm, naraw li l-valur &woo mhijiex fil-fatt definita (linja 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
...

u jinsab f'rilokazzjonijiet:

$ 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

Imma jekk inħarsu lejn il-programm diġà mgħobbi, naraw pointer għall-mappa t-tajba (linja 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]
...

Għalhekk, nistgħu nikkonkludu li fil-ħin tat-tnedija tal-programm loader tagħna, il-link għal &woo ġie mibdul b’xi ħaġa b’librerija libbpf. L-ewwel se nħarsu lejn l-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

Aħna naraw li libbpf ħoloq mappa woo u mbagħad niżżilt il-programm tagħna simple. Ejja nagħtu ħarsa aktar mill-qrib lejn kif tagħbija l-programm:

  • ċempel xdp_simple_bpf__open_and_load mill-fajl xdp-simple.skel.h
  • li tikkawża xdp_simple_bpf__load mill-fajl xdp-simple.skel.h
  • li tikkawża bpf_object__load_skeleton mill-fajl libbpf/src/libbpf.c
  • li tikkawża bpf_object__load_xattr ta ' libbpf/src/libbpf.c

L-aħħar funzjoni, fost affarijiet oħra, se sejħa bpf_object__create_maps, li joħloq jew jiftaħ mapep eżistenti, u jibdilhom f'deskritturi tal-fajls. (Dan huwa fejn naraw BPF_MAP_CREATE fl-output strace.) Imbagħad il-funzjoni tissejjaħ bpf_object__relocate u hi hi li tinteressana, peress li niftakru dak li rajna woo fit-tabella tar-rilokazzjoni. Nesplorawha, eventwalment insibu ruħna fil-funzjoni bpf_program__relocate, li jittratta r-rilokazzjonijiet tal-mapep:

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

Allura nieħdu l-istruzzjonijiet tagħna

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

u ibdel ir-reġistru tas-sors fih bi BPF_PSEUDO_MAP_FD, u l-ewwel IMM għad-deskrittur tal-fajl tal-mappa tagħna u, jekk huwa ugwali għal, pereżempju, 0xdeadbeef, allura bħala riżultat aħna nirċievu l-istruzzjoni

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

Dan huwa kif l-informazzjoni tal-mapep tiġi trasferita għal programm BPF speċifiku mgħobbi. F'dan il-każ, il-mappa tista 'tinħoloq bl-użu BPF_MAP_CREATE, u miftuħa bl-użu ta 'ID BPF_MAP_GET_FD_BY_ID.

Total, meta tuża libbpf l-algoritmu huwa kif ġej:

  • waqt il-kumpilazzjoni, jinħolqu rekords fit-tabella tar-rilokazzjoni għal links għal mapep
  • libbpf jiftaħ il-ktieb tal-oġġetti ELF, isib il-mapep kollha użati u joħloq deskritturi tal-fajls għalihom
  • deskritturi tal-fajl huma mgħobbija fil-kernel bħala parti mill-istruzzjoni LD64

Kif tistgħu timmaġinaw, hemm aktar li ġejjin u se jkollna nħarsu lejn il-qalba. Fortunatament, għandna ħjiel - ktibna t-tifsira BPF_PSEUDO_MAP_FD fir-reġistru tas-sors u nistgħu nidfnuh, li jwassalna għall-qaddis tal-qaddisin kollha - kernel/bpf/verifier.c, fejn funzjoni b'isem distintiv tissostitwixxi deskrittur tal-fajl bl-indirizz ta 'struttura ta' tip 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;

(Il-kodiċi sħiħ jista 'jinstab по ссылке). Allura nistgħu nespandu l-algoritmu tagħna:

  • waqt it-tagħbija tal-programm, il-verifikatur jiċċekkja l-użu korrett tal-mappa u jikteb l-indirizz tal-istruttura korrispondenti struct bpf_map

Meta tniżżel il-binarju ELF bl-użu libbpf Hemm ħafna aktar għaddejjin, iżda aħna ser niddiskutu dan f'artikoli oħra.

Tagħbija ta' programmi u mapep mingħajr libbpf

Kif imwiegħed, hawn eżempju għall-qarrejja li jridu jkunu jafu kif joħolqu u jgħabbu programm li juża mapep, mingħajr għajnuna libbpf. Dan jista’ jkun utli meta tkun qed taħdem f’ambjent li għalih ma tistax tibni dipendenzi, jew issalva kull daqsxejn, jew tikteb programm bħal ply, li jiġġenera kodiċi binarju BPF fuq il-fly.

Biex tagħmilha aktar faċli li ssegwi l-loġika, aħna se niktbu mill-ġdid l-eżempju tagħna għal dawn l-iskopijiet xdp-simple. Il-kodiċi komplut u kemmxejn estiż tal-programm diskuss f'dan l-eżempju jista 'jinstab f'dan ħmira.

Il-loġika tal-applikazzjoni tagħna hija kif ġej:

  • toħloq mappa tat-tip BPF_MAP_TYPE_ARRAY bl-użu tal-kmand BPF_MAP_CREATE,
  • oħloq programm li juża din il-mappa,
  • qabbad il-programm mal-interface lo,

li jissarraf fil-bniedem bħala

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);
}

Hawnhekk map_create joħloq mappa bl-istess mod kif għamilna fl-ewwel eżempju dwar is-sejħa tas-sistema bpf - "kernel, jekk jogħġbok agħmel lili mappa ġdida fil-forma ta' firxa ta' 8 elementi simili __u64 u agħtini lura d-deskrittur tal-fajl":

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));
}

Il-programm huwa wkoll faċli biex tagħbija:

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));
}

Il-parti delikata prog_load hija d-definizzjoni tal-programm BPF tagħna bħala firxa ta 'strutturi struct bpf_insn insns[]. Imma peress li qed nużaw programm li għandna f'C, nistgħu nqarrqu ftit:

$ 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

B'kollox, għandna bżonn niktbu 14-il istruzzjonijiet fil-forma ta 'strutturi simili struct bpf_insn (parir: ħu l-miżbla minn fuq, aqra mill-ġdid is-sezzjoni tal-istruzzjonijiet, iftaħ linux/bpf.h и linux/bpf_common.h u tipprova tiddetermina struct bpf_insn insns[] waħdu):

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
    },
};

Eżerċizzju għal dawk li ma kitbux dan huma stess - issib map_fd.

Fadal parti oħra mhux żvelata fil-programm tagħna - xdp_attach. Sfortunatament, programmi bħal XDP ma jistgħux jiġu konnessi permezz ta 'sejħa tas-sistema bpf. In-nies li ħolqu BPF u XDP kienu mill-komunità tal-Linux online, li jfisser li użaw l-aktar waħda familjari għalihom (iżda mhux biex normali nies) interface għall-interazzjoni mal-qalba: sokits netlink, ara ukoll RFC3549. L-aktar mod sempliċi biex timplimenta xdp_attach qed tikkopja kodiċi minn libbpf, jiġifieri, mill-fajl netlink.c, li huwa dak li għamilna, qassarha ftit:

Merħba fid-dinja tas-sokits netlink

Iftaħ tip ta' socket netlink 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;
}

Naqraw minn dan is-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;
}

Fl-aħħarnett, hawnhekk hija l-funzjoni tagħna li tiftaħ socket u tibgħatlu messaġġ speċjali li jkun fih deskrittur tal-fajl:

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;
}

Allura, kollox huwa lest għall-ittestjar:

$ 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 +++

Ejja naraw jekk il-programm tagħna għandux konnessjoni ma ' 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

Ejja nibagħtu pings u nħarsu lejn il-mappa:

$ 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

Hurrah, kollox jaħdem. Innota, mill-mod, li l-mappa tagħna terġa' tintwera fil-forma ta 'bytes. Dan huwa dovut għall-fatt li, b'differenza libbpf aħna ma tagħbija informazzjoni tat-tip (BTF). Imma nitkellmu aktar dwar dan id-darba li jmiss.

Għodod għall-Iżvilupp

F'din it-taqsima, aħna ser inħarsu lejn l-għodda tal-iżviluppatur BPF minimu.

B'mod ġenerali, m'għandekx bżonn xi ħaġa speċjali biex tiżviluppa programmi BPF - BPF jaħdem fuq kwalunkwe kernel ta' distribuzzjoni deċenti, u l-programmi jinbnew bl-użu clang, li jistgħu jiġu forniti mill-pakkett. Madankollu, minħabba l-fatt li l-BPF qed jiġi żviluppat, il-qalba u l-għodod qed jinbidlu kontinwament, jekk ma tridx tikteb programmi BPF billi tuża metodi antikwati mill-2019, allura jkollok tiġbor

  • llvm/clang
  • pahole
  • qalba tagħha
  • bpftool

(Għal referenza, din it-taqsima u l-eżempji kollha fl-artiklu tħaddmu fuq Debian 10.)

llvm/clang

BPF huwa faċli ma 'LLVM u, għalkemm reċentement programmi għal BPF jistgħu jiġu kkompilati bl-użu ta' gcc, l-iżvilupp kurrenti kollu jitwettaq għal LLVM. Għalhekk, l-ewwel nett, aħna se nibnu l-verżjoni attwali clang minn 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
... много времени спустя
$

Issa nistgħu niċċekkjaw jekk kollox ġiex flimkien sewwa:

$ ./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

(Istruzzjonijiet għall-assemblaġġ clang meħuda minni minn bpf_devel_QA.)

Aħna mhux se ninstallaw il-programmi li għadna kif bnejna, iżda minflok inżiduhom magħhom PATHper eżempju:

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

(Dan jista’ jiżdied ma’ .bashrc jew f'fajl separat. Personalment, inżid affarijiet bħal dawn ~/bin/activate-llvm.sh u meta jkun hemm bżonn nagħmilha . activate-llvm.sh.)

Pahole u BTF

Utilità pahole użat meta jinbena l-qalba biex tinħoloq informazzjoni ta' debugging f'format BTF. Mhux se nidħlu fid-dettall f'dan l-artikolu dwar id-dettalji tat-teknoloġija BTF, minbarra l-fatt li huwa konvenjenti u rridu nużawha. Mela jekk se tibni l-qalba tiegħek, ibni l-ewwel pahole (mingħajr pahole ma tkunx tista' tibni l-qalba bl-għażla 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

Qlub għall-esperimentazzjoni bil-BPF

Meta nesplora l-possibbiltajiet tal-BPF, irrid niġbor il-qalba tiegħi stess. Dan, ġeneralment, mhuwiex meħtieġ, peress li inti tkun tista 'tiġbor u tgħabbi programmi BPF fuq il-qalba tad-distribuzzjoni, madankollu, li jkollok il-qalba tiegħek stess tippermettilek tuża l-aħħar karatteristiċi BPF, li se jidhru fid-distribuzzjoni tiegħek fl-aħjar xhur. , jew, bħal fil-każ ta 'xi għodod ta' debugging mhux se jiġu ppakkjati xejn fil-futur prevedibbli. Ukoll, il-qalba tagħha stess tagħmilha importanti li tesperimenta bil-kodiċi.

Sabiex tibni kernel għandek bżonn, l-ewwelnett, il-kernel innifsu, u t-tieni, fajl tal-konfigurazzjoni tal-kernel. Biex nesperimentaw bil-BPF nistgħu nużaw is-soltu vanilla qalba jew waħda mill-qalba tal-iżvilupp. Storikament, l-iżvilupp tal-BPF iseħħ fi ħdan il-komunità tan-netwerking Linux u għalhekk il-bidliet kollha illum jew għada jgħaddu minn David Miller, il-mantenitur tan-netwerking Linux. Skont in-natura tagħhom - modifiki jew karatteristiċi ġodda - il-bidliet fin-netwerk jaqgħu f'wieħed minn żewġ qlub - net jew net-next. Bidliet għal BPF huma mqassma bl-istess mod bejn bpf и bpf-next, li mbagħad jinġabru f'net u net-li jmiss, rispettivament. Għal aktar dettalji, ara bpf_devel_QA и netdev-FAQ. Allura agħżel għadma bbażata fuq it-togħma tiegħek u l-ħtiġijiet ta’ stabbiltà tas-sistema li qed tittestja fuqha (*-next il-qlub huma l-aktar instabbli minn dawk elenkati).

Huwa lil hinn mill-ambitu ta 'dan l-artikolu li titkellem dwar kif timmaniġġja l-fajls tal-konfigurazzjoni tal-kernel - huwa preżunt li jew diġà taf kif tagħmel dan, jew lest biex titgħallem waħdu. Madankollu, l-istruzzjonijiet li ġejjin għandhom ikunu ftit jew wisq biżżejjed biex jagħtuk sistema li taħdem bil-BPF.

Niżżel waħda mill-qlub ta' hawn fuq:

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

Ibni konfigurazzjoni minima tal-kernel tax-xogħol:

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

Ippermetti l-għażliet BPF fil-fajl .config tal-għażla tiegħek (x'aktarx CONFIG_BPF diġà se tkun attivata peress li systemd jużaha). Hawnhekk hawn lista ta’ għażliet mill-qalba użata għal dan l-artikolu:

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

Imbagħad nistgħu niġbru u ninstallaw faċilment il-moduli u l-qalba (mill-mod, tista 'tiġbor il-qalba billi tuża l-għadma li għadha kif ġiet immuntata clangbilli żżid CC=clang):

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

u reboot bil-kernel il-ġdid (nuża għal dan kexec mill-pakkett 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

L-utilità l-aktar użata komunement fl-artikolu se tkun l-utilità bpftool, fornut bħala parti mill-kernel tal-Linux. Huwa miktub u miżmum mill-iżviluppaturi BPF għall-iżviluppaturi BPF u jista 'jintuża biex jimmaniġġja t-tipi kollha ta' oġġetti BPF - tagħbija programmi, toħloq u editja mapep, tesplora l-ħajja tal-ekosistema BPF, eċċ. Tista' tinstab dokumentazzjoni fil-forma ta' kodiċi tas-sors għall-paġni man fil-qalba jew, diġà miġbura, fuq ix-xibka.

Fiż-żmien ta’ din il-kitba bpftool jiġi lest biss għal RHEL, Fedora u Ubuntu (ara, pereżempju, dan il-ħajt, li jirrakkonta l-istorja mhux mitmuma tal-ippakkjar bpftool f'Debian). Imma jekk diġà bnejt il-qalba tiegħek, imbagħad ibni bpftool faċli daqs torta:

$ 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  ]

$

(hawn ${linux} - dan huwa d-direttorju tal-kernel tiegħek.) Wara li tesegwixxi dawn il-kmandi bpftool se jinġabru f'direttorju ${linux}/tools/bpf/bpftool u jista 'jiżdied mal-mogħdija (l-ewwel nett lill-utent root) jew sempliċement tikkopja lil /usr/local/sbin.

Iġbor bpftool huwa aħjar li tuża l-aħħar clang, immuntat kif deskritt hawn fuq, u ċċekkja jekk huwiex immuntat b'mod korrett - billi tuża, pereżempju, il-kmand

$ 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
...

li se juri liema karatteristiċi BPF huma attivati ​​fil-qalba tiegħek.

Mill-mod, il-kmand ta 'qabel jista' jitmexxa bħala

# bpftool f p k

Dan isir b'analoġija mal-utilitajiet mill-pakkett iproute2, fejn nistgħu, pereżempju, ngħidu ip a s eth0 minflok ip addr show dev eth0.

Konklużjoni

BPF jippermettilek li żarbun briegħed biex tkejjel b'mod effettiv u fuq il-fly tibdel il-funzjonalità tal-qalba. Is-sistema rriżulta li kienet ta 'suċċess kbir, fl-aħjar tradizzjonijiet ta' UNIX: mekkaniżmu sempliċi li jippermettilek li (re)programm il-qalba ppermetta li numru kbir ta 'nies u organizzazzjonijiet jesperimentaw. U, għalkemm l-esperimenti, kif ukoll l-iżvilupp tal-infrastruttura BPF innifisha, huma 'l bogħod milli lesti, is-sistema diġà għandha ABI stabbli li jippermettilek li tibni loġika tan-negozju affidabbli, u l-aktar importanti, effettiva.

Nixtieq ninnota li, fl-opinjoni tiegħi, it-teknoloġija saret tant popolari għaliex, minn naħa, tista' biex tilgħab (l-arkitettura ta 'magna tista' tinftiehem xi ftit jew wisq f'lejla waħda), u min-naħa l-oħra, biex issolvi problemi li ma setgħux jissolvew (b'mod sabiħ) qabel id-dehra tagħha. Dawn iż-żewġ komponenti flimkien jġiegħlu lin-nies jesperimentaw u joħolmu, li jwassal għall-ħolqien ta 'soluzzjonijiet aktar u aktar innovattivi.

Dan l-artikolu, għalkemm mhux partikolarment qasir, huwa biss introduzzjoni għad-dinja tal-BPF u ma jiddeskrivix karatteristiċi "avvanzati" u partijiet importanti tal-arkitettura. Il-pjan 'il quddiem huwa xi ħaġa bħal din: l-artiklu li jmiss se jkun ħarsa ġenerali lejn it-tipi ta' programmi BPF (hemm 5.8 tip ta' programmi appoġġjati fil-kernel 30), imbagħad fl-aħħar inħarsu lejn kif tikteb applikazzjonijiet BPF reali bl-użu ta 'programmi ta' traċċar tal-kernel. bħala eżempju, allura wasal iż-żmien għal kors aktar fil-fond dwar l-arkitettura BPF, segwit minn eżempji ta 'netwerking BPF u applikazzjonijiet tas-sigurtà.

Artikli preċedenti f'din is-serje

  1. BPF għaż-żgħar, parti żero: BPF klassika

Links

  1. Gwida ta' Referenza BPF u XDP — dokumentazzjoni dwar BPF minn cilium, jew aktar preċiżament minn Daniel Borkman, wieħed mill-ħallieqa u manutenzjoni ta 'BPF. Din hija waħda mill-ewwel deskrizzjonijiet serji, li hija differenti mill-oħrajn peress li Danjel jaf eżattament dwar xiex qed jikteb u hemm ebda żball. B'mod partikolari, dan id-dokument jiddeskrivi kif taħdem ma 'programmi BPF tat-tipi XDP u TC billi tuża l-utilità magħrufa. ip mill-pakkett iproute2.

  2. Dokumentazzjoni/netwerking/filter.txt — fajl oriġinali b'dokumentazzjoni għal BPF klassika u mbagħad estiż. Qari tajjeb jekk trid tidħol fil-lingwa tal-assemblaġġ u dettalji arkitettoniċi tekniċi.

  3. Blog dwar BPF minn facebook. Huwa aġġornat rari, iżda b'mod xieraq, kif Alexei Starovoitov (awtur ta 'eBPF) u Andrii Nakryiko - (mantenitur) jiktbu hemmhekk libbpf).

  4. Sigrieti ta 'bpftool. Thread twitter divertenti minn Quentin Monnet b'eżempji u sigrieti tal-użu ta' bpftool.

  5. Adsa fil-BPF: lista ta 'materjal tal-qari. Lista ġgant (u għadha miżmuma) ta' links għad-dokumentazzjoni tal-BPF minn Quentin Monnet.

Sors: www.habr.com

Żid kumment