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.
Ġ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.
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):
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ċċ.
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:
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
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:
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ċċ.
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:
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:
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:
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:
Ċ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:
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.
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.
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:
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):
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:
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
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:
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:
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:
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:
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".
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:
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:
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
$ 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:
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:
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:
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):
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?
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);
}
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:
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:
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:
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:
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[]:
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_opsdeterminat minn fil-fajl net/core/filter.c kif ġej:
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:
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:
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:
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_printk - dan 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!
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:
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:
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
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
$ 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):
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:
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;
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:
(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.
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":
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:
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):
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:
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
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:
(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à.
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.
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.
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).
Sigrieti ta 'bpftool. Thread twitter divertenti minn Quentin Monnet b'eżempji u sigrieti tal-użu ta' bpftool.