SÄkumÄ bija tehnoloÄ£ija, un to sauca par BPF. MÄs paskatÄ«jÄmies uz viÅu iepriekÅ”ÄjÄ, Å Ä«s sÄrijas VecÄs DerÄ«bas raksts. 2013. gadÄ ar Alekseja Starovoitova un Daniela Borkmana pÅ«lÄm tika izstrÄdÄta tÄs uzlabota versija, kas optimizÄta modernÄm 64 bitu iekÄrtÄm un iekļauta Linux kodolÄ. Å o jauno tehnoloÄ£iju Ä«si sauca par iekÅ”Äjo BPF, pÄc tam pÄrdÄvÄja par Extended BPF, un tagad, pÄc vairÄkiem gadiem, visi to vienkÄrÅ”i sauc par BPF.
Aptuveni runÄjot, BPF ļauj palaist patvaļīgu lietotÄja nodroÅ”inÄtu kodu Linux kodola telpÄ, un jaunÄ arhitektÅ«ra izrÄdÄ«jÄs tik veiksmÄ«ga, ka mums bÅ«s nepiecieÅ”ams vÄl ducis rakstu, lai aprakstÄ«tu visas tÄs lietojumprogrammas. (VienÄ«gais, ko izstrÄdÄtÄjiem neveicÄs labi, kÄ redzams tÄlÄk sniegtajÄ veiktspÄjas kodÄ, bija pienÄcÄ«ga logotipa izveide.)
Å ajÄ rakstÄ ir aprakstÄ«ta BPF virtuÄlÄs maŔīnas struktÅ«ra, kodola saskarnes darbam ar BPF, izstrÄdes rÄ«ki, kÄ arÄ« Ä«ss, ļoti Ä«ss pÄrskats par esoÅ”ajÄm iespÄjÄm, t.i. viss, kas mums nÄkotnÄ bÅ«s nepiecieÅ”ams, lai dziļÄk izpÄtÄ«tu BPF praktisko pielietojumu.
Raksta kopsavilkums
Ievads BPF arhitektÅ«rÄ. PirmkÄrt, mÄs aplÅ«kosim BPF arhitektÅ«ru no putna lidojuma un izklÄstÄ«sim galvenÄs sastÄvdaļas.
Objektu pÄrvaldÄ«ba, izmantojot bpf sistÄmas zvanu. Ar zinÄmu izpratni par sistÄmu, kas jau ir ieviesta, mÄs beidzot aplÅ«kosim, kÄ izveidot un manipulÄt ar objektiem no lietotÄja telpas, izmantojot Ä«paÅ”u sistÄmas izsaukumu. bpf(2).
ŠŠøŃŠµŠ¼ ŠæŃŠ¾Š³ŃŠ°Š¼Š¼Ń BPF Ń ŠæŠ¾Š¼Š¾ŃŃŃ libbpf. Protams, jÅ«s varat rakstÄ«t programmas, izmantojot sistÄmas zvanu. Bet tas ir grÅ«ti. ReÄlistiskÄkam scenÄrijam kodolprogrammÄtÄji izstrÄdÄja bibliotÄku libbpf. MÄs izveidosim pamata BPF lietojumprogrammas skeletu, ko izmantosim turpmÄkajos piemÄros.
Kodola palÄ«gi. Å eit mÄs uzzinÄsim, kÄ BPF programmas var piekļūt kodola palÄ«gfunkcijÄm - rÄ«kam, kas kopÄ ar kartÄm bÅ«tiski paplaÅ”ina jaunÄ BPF iespÄjas salÄ«dzinÄjumÄ ar klasisko.
Piekļuve kartÄm no BPF programmÄm. Å ajÄ brÄ«dÄ« mÄs zinÄm pietiekami daudz, lai precÄ«zi saprastu, kÄ mÄs varam izveidot programmas, kas izmanto kartes. Un pat Ätri ieskatÄ«simies lieliskajÄ un varenajÄ verificÄtÄjÄ.
IzstrÄdes rÄ«ki. PalÄ«dzÄ«bas sadaļa par to, kÄ salikt nepiecieÅ”amos utilÄ«tus un kodolu eksperimentiem.
SecinÄjums. Raksta beigÄs tie, kas izlasÄ«ja tik tÄlu, turpmÄkajos rakstos atradÄ«s motivÄjoÅ”us vÄrdus un Ä«su aprakstu par to, kas notiks. UzskaitÄ«sim arÄ« vairÄkas saites paÅ”mÄcÄ«bai tiem, kam nav ne vÄlÄÅ”anÄs, ne iespÄju gaidÄ«t turpinÄjumu.
Ievads BPF arhitektÅ«rÄ
Pirms sÄkam apsvÄrt BPF arhitektÅ«ru, mÄs pÄdÄjo reizi (ak) atsauksimies uz klasiskais BPF, kas tika izstrÄdÄta kÄ atbilde uz RISC maŔīnu parÄdÄ«Å”anos un atrisinÄja efektÄ«vas pakeÅ”u filtrÄÅ”anas problÄmu. ArhitektÅ«ra izrÄdÄ«jÄs tik veiksmÄ«ga, ka, dzimusi drudžainajos deviÅdesmitajos gados Berkeley UNIX, tÄ tika pÄrnesta uz lielÄko daļu esoÅ”o operÄtÄjsistÄmu, izdzÄ«voja trakajos divdesmitajos gados un joprojÄm atrod jaunas lietojumprogrammas.
Jaunais BPF tika izstrÄdÄts, reaÄ£Äjot uz 64 bitu maŔīnu, mÄkoÅpakalpojumu visuresamÄ«bu un pieaugoÅ”o vajadzÄ«bu pÄc rÄ«kiem SDN izveidei (SaprÄ«kots-dprecizÄts ntÄ«kloÅ”ana). Kodola tÄ«kla inženieri izstrÄdÄja kÄ uzlabotu klasiskÄ BPF aizstÄjÄju, jaunais BPF burtiski seÅ”us mÄneÅ”us vÄlÄk atrada lietojumprogrammas sarežģītajÄ Linux sistÄmu izsekoÅ”anas uzdevumÄ, un tagad, seÅ”us gadus pÄc tÄ parÄdÄ«Å”anÄs, mums bÅ«s nepiecieÅ”ams vesels nÄkamais raksts, lai. uzskaitiet dažÄdu veidu programmas.
Smieklīgas bildes
BPF pamatÄ ir smilÅ”kastes virtuÄlÄ maŔīna, kas ļauj palaist āpatvaļīguā kodu kodola telpÄ, neapdraudot droŔību. BPF programmas tiek izveidotas lietotÄja telpÄ, ielÄdÄtas kodolÄ un savienotas ar kÄdu notikumu avotu. Notikums varÄtu bÅ«t, piemÄram, paketes piegÄde uz tÄ«kla interfeisu, kÄdas kodola funkcijas palaiÅ”ana utt. Pakotnes gadÄ«jumÄ BPF programmai bÅ«s piekļuve pakotnes datiem un metadatiem (lasÄ«Å”anai un, iespÄjams, rakstÄ«Å”anai, atkarÄ«bÄ no programmas veida); kodola funkcijas palaiÅ”anas gadÄ«jumÄ argumenti funkcija, tostarp norÄdes uz kodola atmiÅu utt.
ApskatÄ«sim Å”o procesu tuvÄk. SÄkumÄ parunÄsim par pirmo atŔķirÄ«bu no klasiskÄ BPF, kuras programmas tika rakstÄ«tas montÄtÄjÄ. JaunajÄ versijÄ arhitektÅ«ra tika paplaÅ”inÄta, lai programmas varÄtu rakstÄ«t augsta lÄ«meÅa valodÄs, galvenokÄrt, protams, C. Å im nolÅ«kam tika izstrÄdÄta aizmugure priekÅ” llvm, kas ļauj Ä£enerÄt baitkodu BPF arhitektÅ«rai.
BPF arhitektÅ«ra daļÄji tika izstrÄdÄta tÄ, lai tÄ efektÄ«vi darbotos modernÄs iekÄrtÄs. Lai tas darbotos praksÄ, BPF baitkods, kad tas ir ielÄdÄts kodolÄ, tiek tulkots vietÄjÄ kodÄ, izmantojot komponentu, ko sauc par JIT kompilatoru (Just In Time). TÄlÄk, ja atceraties, klasiskajÄ BPF programma tika ielÄdÄta kodolÄ un pievienota notikuma avotam atomiski - viena sistÄmas izsaukuma kontekstÄ. JaunajÄ arhitektÅ«rÄ tas notiek divos posmos ā pirmkÄrt, kods tiek ielÄdÄts kodolÄ, izmantojot sistÄmas izsaukumu bpf(2)un vÄlÄk, izmantojot citus mehÄnismus, kas atŔķiras atkarÄ«bÄ no programmas veida, programma tiek pievienota notikuma avotam.
Å eit lasÄ«tÄjam var rasties jautÄjums: vai tas bija iespÄjams? KÄ tiek garantÄta Å”Äda koda izpildes droŔība? Izpildes droŔību mums garantÄ BPF programmu ielÄdes posms, ko sauc par verificÄtÄju (angļu valodÄ Å”o posmu sauc par verificÄtÄju, un es turpinÄÅ”u lietot angļu vÄrdu):
Verifier ir statisks analizators, kas nodroÅ”ina, ka programma netraucÄ normÄlu kodola darbÄ«bu. Tas, starp citu, nenozÄ«mÄ, ka programma nevar traucÄt sistÄmas darbÄ«bu - BPF programmas atkarÄ«bÄ no veida var lasÄ«t un pÄrrakstÄ«t kodola atmiÅas sadaļas, atgriezt funkciju vÄrtÄ«bas, apgriezt, pievienot, pÄrrakstÄ«t un pat pÄrsÅ«tÄ«t tÄ«kla paketes. Verifier garantÄ, ka BPF programmas darbÄ«bas laikÄ kodols nesabruks un programma, kurai saskaÅÄ ar noteikumiem ir rakstÄ«Å”anas piekļuve, piemÄram, izejoÅ”Äs paketes datiem, nevarÄs pÄrrakstÄ«t kodola atmiÅu Ärpus paketes. MÄs apskatÄ«sim verificÄtÄju nedaudz sÄ«kÄk attiecÄ«gajÄ sadaÄ¼Ä pÄc tam, kad bÅ«sim iepazinuÅ”ies ar visÄm pÄrÄjÄm BPF sastÄvdaļÄm.
TÄtad, ko mÄs esam iemÄcÄ«juÅ”ies lÄ«dz Å”im? LietotÄjs raksta programmu C valodÄ, ielÄdÄ to kodolÄ, izmantojot sistÄmas zvanu bpf(2), kur to pÄrbauda verificÄtÄjs un pÄrveido vietÄjÄ baitkodÄ. PÄc tam tas pats vai cits lietotÄjs savieno programmu ar notikuma avotu, un tÄ sÄk izpildÄ«t. SÄknÄÅ”anas un savienojuma atdalÄ«Å”ana ir nepiecieÅ”ama vairÄku iemeslu dÄļ. PirmkÄrt, verificÄtÄja palaiÅ”ana ir salÄ«dzinoÅ”i dÄrga, un, vairÄkas reizes lejupielÄdÄjot vienu un to paÅ”u programmu, mÄs tÄrÄjam datora laiku. OtrkÄrt, tieÅ”i tas, kÄ programma ir savienota, ir atkarÄ«gs no tÄs veida, un viens pirms gada izstrÄdÄts āuniversÄlsā interfeiss var nebÅ«t piemÄrots jauna veida programmÄm. (Lai gan tagad, kad arhitektÅ«ra kļūst arvien nobrieduÅ”Äka, ir doma unificÄt Å”o saskarni lÄ«menÄ« libbpf.)
UzmanÄ«gs lasÄ«tÄjs var pamanÄ«t, ka mÄs vÄl neesam pabeiguÅ”i ar attÄliem. PatieÅ”Äm, viss iepriekÅ” minÄtais neizskaidro, kÄpÄc BPF bÅ«tiski maina attÄlu salÄ«dzinÄjumÄ ar klasisko BPF. Divi jauninÄjumi, kas bÅ«tiski paplaÅ”ina pielietojamÄ«bas jomu, ir iespÄja izmantot koplietojamo atmiÅu un kodola palÄ«gfunkcijas. BPF koplietojamÄ atmiÅa tiek ieviesta, izmantojot tÄ sauktÄs kartes ā koplietojamÄs datu struktÅ«ras ar noteiktu API. ViÅi, iespÄjams, ieguva Å”o nosaukumu, jo pirmais kartes veids, kas parÄdÄ«jÄs, bija hash tabula. Tad parÄdÄ«jÄs masÄ«vi, lokÄlÄs (per-CPU) jaucÄj tabulas un lokÄlie masÄ«vi, meklÄÅ”anas koki, kartes, kas satur norÄdes uz BPF programmÄm un daudz kas cits. Tagad mÅ«s interesÄ tas, ka BPF programmÄm tagad ir iespÄja saglabÄt stÄvokli starp zvaniem un koplietot to ar citÄm programmÄm un lietotÄja vietu.
Maps var piekļūt no lietotÄja procesiem, izmantojot sistÄmas zvanu bpf(2), un no BPF programmÄm, kas darbojas kodolÄ, izmantojot palÄ«gfunkcijas. TurklÄt palÄ«gi pastÄv ne tikai darbam ar kartÄm, bet arÄ«, lai piekļūtu citÄm kodola iespÄjÄm. PiemÄram, BPF programmas var izmantot palÄ«gfunkcijas, lai pÄrsÅ«tÄ«tu paketes uz citÄm saskarnÄm, Ä£enerÄtu perf notikumus, piekļūtu kodola struktÅ«rÄm utt.
RezumÄjot, BPF nodroÅ”ina iespÄju kodola telpÄ ielÄdÄt patvaļīgu, t.i., pÄrbaudÄ«tÄju, lietotÄja kodu. Å is kods var saglabÄt stÄvokli starp zvaniem un apmainÄ«ties ar datiem ar lietotÄja vietu, kÄ arÄ« tam ir piekļuve kodola apakÅ”sistÄmÄm, ko atļauj Å”Äda veida programmas.
Tas jau ir lÄ«dzÄ«gs kodola moduļu sniegtajÄm iespÄjÄm, salÄ«dzinÄjumÄ ar kurÄm BPF ir dažas priekÅ”rocÄ«bas (protams, var salÄ«dzinÄt tikai lÄ«dzÄ«gas programmas, piemÄram, sistÄmas izsekoÅ”ana - ar BPF nevar uzrakstÄ«t patvaļīgu draiveri). Varat atzÄ«mÄt zemÄku ieejas slieksni (dažas utilÄ«tas, kas izmanto BPF, lietotÄjam neprasa kodola programmÄÅ”anas iemaÅas vai programmÄÅ”anas prasmes kopumÄ), izpildes droŔību (paceliet roku komentÄros tiem, kuri, rakstot, nepÄrkÄpa sistÄmu vai testÄÅ”anas moduļi), atomitÄte - pÄrlÄdÄjot moduļus, ir dÄ«kstÄves laiks, un BPF apakÅ”sistÄma nodroÅ”ina, ka neviens notikums netiek palaists garÄm (taisnÄ«bas labad jÄsaka, ka tas neattiecas uz visu veidu BPF programmÄm).
Å Ädu iespÄju klÄtbÅ«tne padara BPF par universÄlu rÄ«ku kodola paplaÅ”inÄÅ”anai, kas apstiprinÄs arÄ« praksÄ: BPF tiek pievienots arvien vairÄk jaunu programmu veidu, arvien vairÄk lielu uzÅÄmumu izmanto BPF kaujas serveros 24 Ć 7, arvien vairÄk un vairÄk jaunuzÅÄmumi veido savu biznesu uz risinÄjumiem, kuru pamatÄ ir BPF. BPF tiek izmantots visur: aizsardzÄ«bÄ pret DDoS uzbrukumiem, SDN izveidÄ (piemÄram, kubernetes tÄ«klu ievieÅ”anÄ), kÄ galveno sistÄmas izsekoÅ”anas rÄ«ku un statistikas savÄcÄju, ielauÅ”anÄs atklÄÅ”anas sistÄmÄs un smilÅ”kastes sistÄmÄs utt.
Pabeigsim Å”eit raksta pÄrskata daļu un aplÅ«kosim virtuÄlo maŔīnu un BPF ekosistÄmu sÄ«kÄk.
AtkÄpe: komunÄlie maksÄjumi
Lai varÄtu palaist piemÄrus nÄkamajÄs sadaļÄs, jums var bÅ«t nepiecieÅ”amas vairÄkas utilÄ«tas, vismaz llvm/clang ar bpf atbalstu un bpftool. SadaÄ¼Ä IzstrÄdes rÄ«ki Varat izlasÄ«t instrukcijas par utilÄ«tu komplektÄÅ”anu, kÄ arÄ« savu kodolu. Å Ä« sadaļa ir ievietota zemÄk, lai netraucÄtu mÅ«su prezentÄcijas harmoniju.
BPF virtuÄlÄs maŔīnas reÄ£istri un instrukciju sistÄma
BPF arhitektÅ«ra un komandu sistÄma tika izstrÄdÄta, Åemot vÄrÄ to, ka programmas tiks rakstÄ«tas C valodÄ un pÄc ielÄdes kodolÄ pÄrtulkotas vietÄjÄ kodÄ. TÄpÄc reÄ£istru skaits un komandu kopa tika izvÄlÄta, Åemot vÄrÄ mÅ«sdienu maŔīnu spÄju krustpunktu matemÄtiskÄ nozÄ«mÄ. TurklÄt programmÄm tika noteikti dažÄdi ierobežojumi, piemÄram, vÄl nesen nebija iespÄjams rakstÄ«t cilpas un apakÅ”programmas, un instrukciju skaits bija ierobežots lÄ«dz 4096 (tagad priviliÄ£ÄtÄs programmas var ielÄdÄt lÄ«dz pat miljonam instrukciju).
BPF ir vienpadsmit lietotÄjiem pieejami 64 bitu reÄ£istri r0SÄkot nor10 un programmu skaitÄ«tÄjs. ReÄ£istrÄties r10 satur rÄmja rÄdÄ«tÄju un ir tikai lasÄms. ProgrammÄm ir piekļuve 512 baitu steksam izpildes laikÄ un neierobežotam koplietojamÄs atmiÅas apjomam karÅ”u veidÄ.
BPF programmÄm ir atļauts palaist noteiktu programmas tipa kodola palÄ«gu komplektu un pÄdÄjÄ laikÄ arÄ« parastÄs funkcijas. Katrai izsauktajai funkcijai var bÅ«t lÄ«dz pieciem argumentiem, kas tiek nodoti reÄ£istros r1SÄkot nor5, un atgrieÅ”anas vÄrtÄ«ba tiek nodota r0. Tiek garantÄts, ka pÄc atgrieÅ”anÄs no funkcijas reÄ£istru saturs r6SÄkot nor9 NemainÄ«sies.
EfektÄ«vai programmu tulkoÅ”anai, reÄ£istri r0SÄkot nor11 visÄm atbalstÄ«tajÄm arhitektÅ«rÄm ir unikÄli kartÄtas ar reÄliem reÄ£istriem, Åemot vÄrÄ paÅ”reizÄjÄs arhitektÅ«ras ABI funkcijas. PiemÄram, priekÅ” x86_64 reÄ£istros r1SÄkot nor5, ko izmanto funkciju parametru nodoÅ”anai, tiek parÄdÄ«ti rdi, rsi, rdx, rcx, r8, ko izmanto, lai nodotu parametrus funkcijÄm x86_64. PiemÄram, kreisajÄ pusÄ esoÅ”ais kods pÄrvÄrÅ”as labajÄ pusÄ Å”Ädi:
ReÄ£istrÄties r0 izmanto arÄ«, lai atgrieztu programmas izpildes rezultÄtu, un reÄ£istrÄ r1 programmai tiek nodots rÄdÄ«tÄjs uz kontekstu ā atkarÄ«bÄ no programmas veida tÄ varÄtu bÅ«t, piemÄram, struktÅ«ra struct xdp_md (XDP) vai struktÅ«ru struct __sk_buff (dažÄdÄm tÄ«kla programmÄm) vai struktÅ«ru struct pt_regs (dažÄda veida izsekoÅ”anas programmÄm) utt.
TÄtad, mums bija reÄ£istru komplekts, kodola palÄ«gi, kaudze, konteksta rÄdÄ«tÄjs un koplietota atmiÅa karÅ”u veidÄ. Ne jau tas viss ceļojumÄ bÅ«tu absolÅ«ti nepiecieÅ”ams, bet...
TurpinÄsim aprakstu un runÄsim par komandu sistÄmu darbam ar Å”iem objektiem. Visi (GandrÄ«z visi) BPF instrukcijÄm ir fiksÄts 64 bitu izmÄrs. Ja paskatÄs uz vienu instrukciju 64 bitu Big Endian maŔīnÄ, jÅ«s redzÄsit
Å eit Code - tas ir instrukcijas kodÄjums, Dst/Src ir attiecÄ«gi uztvÄrÄja un avota kodÄjums, Off - 16 bitu paraksta atkÄpe un Imm ir 32 bitu vesels skaitlis, ko izmanto dažÄs instrukcijÄs (lÄ«dzÄ«gi cBPF konstantei K). KodÄÅ”ana Code ir viens no diviem veidiem:
Instrukciju klases 0, 1, 2, 3 nosaka komandas darbam ar atmiÅu. ViÅi tiek saukti, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, attiecÄ«gi. 4., 7. klase (BPF_ALU, BPF_ALU64) veido ALU instrukciju kopu. 5., 6. klase (BPF_JMP, BPF_JMP32) satur lÄkÅ”anas instrukcijas.
TÄlÄkais BPF instrukciju sistÄmas izpÄtes plÄns ir Å”Äds: tÄ vietÄ, lai rÅ«pÄ«gi uzskaitÄ«tu visas instrukcijas un to parametrus, mÄs Å”ajÄ sadaÄ¼Ä apskatÄ«sim pÄris piemÄrus un no tiem kļūs skaidrs, kÄ instrukcijas patiesÄ«bÄ darbojas un kÄ manuÄli izjaukt jebkuru binÄro failu BPF. Lai vÄlÄk rakstÄ konsolidÄtu materiÄlu, tiksimies arÄ« ar individuÄliem norÄdÄ«jumiem sadaļÄs par Verifier, JIT kompilatoru, klasiskÄ BPF tulkoÅ”anu, kÄ arÄ« pÄtot kartes, izsaukÅ”anas funkcijas utt.
Komandu kodi ir vienÄdi b7, 15, b7 Šø 95. Atcerieties, ka vismazÄk nozÄ«mÄ«gie trÄ«s biti ir instrukciju klase. MÅ«su gadÄ«jumÄ visu instrukciju ceturtais bits ir tukÅ”s, tÄpÄc instrukciju klases ir attiecÄ«gi vienÄdas ar 7, 5, 7, 5. 7. klase ir BPF_ALU64, un 5 ir BPF_JMP. AbÄm klasÄm norÄdÄ«jumu formÄts ir vienÄds (skat. iepriekÅ”), un mÄs varam pÄrrakstÄ«t savu programmu Å”Ädi (tajÄ paÅ”Ä laikÄ mÄs pÄrrakstÄ«sim pÄrÄjÄs kolonnas cilvÄka formÄ):
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
DarbÄ«ba b klase ALU64 -Å o BPF_MOV. Tas pieŔķir vÄrtÄ«bu galamÄrÄ·a reÄ£istram. Ja bits ir iestatÄ«ts s (avots), tad vÄrtÄ«ba tiek Åemta no avota reÄ£istra, un, ja, kÄ mÅ«su gadÄ«jumÄ, tÄ nav iestatÄ«ta, tad vÄrtÄ«ba tiek Åemta no lauka Imm. TÄtad pirmajÄ un treÅ”ajÄ instrukcijÄ mÄs veicam operÄciju r0 = Imm. TurklÄt JMP 1. klases darbÄ«ba ir BPF_JEQ (lÄkt, ja vienÄds). MÅ«su gadÄ«jumÄ kopÅ” bit S ir nulle, tas salÄ«dzina avota reÄ£istra vÄrtÄ«bu ar lauku Imm. Ja vÄrtÄ«bas sakrÄ«t, tad notiek pÄreja uz PC + OffKur PC, kÄ parasti, satur nÄkamÄs instrukcijas adresi. Visbeidzot, JMP Class 9 darbÄ«ba ir BPF_EXIT. Å Ä« instrukcija pÄrtrauc programmu, atgriežoties kodolÄ r0. Pievienosim tabulai jaunu kolonnu:
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
MÄs to varam pÄrrakstÄ«t ÄrtÄkÄ formÄ:
r0 = 1
if (r1 == 0) goto END
r0 = 2
END:
exit
Ja atceramies, kas ir reÄ£istrÄ r1 programmai no kodola un reÄ£istrÄ tiek nodots rÄdÄ«tÄjs uz kontekstu r0 kodolam tiek atgriezta vÄrtÄ«ba, tad mÄs varam redzÄt, ka, ja konteksta rÄdÄ«tÄjs ir nulle, tad mÄs atgriežam 1, bet pretÄjÄ gadÄ«jumÄ - 2. PÄrbaudÄ«sim, vai mums ir taisnÄ«ba, apskatot avotu:
JÄ, tÄ ir bezjÄdzÄ«ga programma, taÄu tÄ izpaužas tikai Äetros vienkÄrÅ”os norÄdÄ«jumos.
IzÅÄmuma piemÄrs: 16 baitu instrukcija
IepriekÅ” minÄjÄm, ka dažas instrukcijas aizÅem vairÄk nekÄ 64 bitus. Tas attiecas, piemÄram, uz instrukcijÄm lddw (Kods = 0x18 = BPF_LD | BPF_DW | BPF_IMM) ā ielÄdÄjiet reÄ£istrÄ dubultvÄrdu no laukiem Imm. Tas ir fakts Imm ir 32 lielums, un dubultvÄrds ir 64 biti, tÄpÄc 64 bitu tÅ«lÄ«tÄjas vÄrtÄ«bas ielÄde reÄ£istrÄ vienÄ 64 bitu instrukcijÄ nedarbosies. Lai to izdarÄ«tu, tiek izmantotas divas blakus esoÅ”Äs instrukcijas, lai laukÄ saglabÄtu 64 bitu vÄrtÄ«bas otro daļu Imm. PiemÄrs:
MÄs tiksimies vÄlreiz ar norÄdÄ«jumiem lddw, kad mÄs runÄjam par pÄrvietoÅ”anu un darbu ar kartÄm.
PiemÄrs: BPF izjaukÅ”ana, izmantojot standarta rÄ«kus
TÄtad, mÄs esam iemÄcÄ«juÅ”ies lasÄ«t BPF binÄros kodus un vajadzÄ«bas gadÄ«jumÄ esam gatavi parsÄt jebkuru instrukciju. TomÄr ir vÄrts teikt, ka praksÄ ir ÄrtÄk un ÄtrÄk izjaukt programmas, izmantojot standarta rÄ«kus, piemÄram:
(Es vispirms uzzinÄju dažas no Å”ajÄ apakÅ”nodaÄ¼Ä aprakstÄ«tajÄm detaļÄm no badoÅ”anÄs Aleksejs Starovoitovs iekÅ”Ä BPF emuÄrs.)
BPF objekti - programmas un kartes - tiek veidoti no lietotÄja telpas, izmantojot komandas BPF_PROG_LOAD Šø BPF_MAP_CREATE sistÄmas zvans bpf(2), mÄs runÄsim par to, kÄ tieÅ”i tas notiek nÄkamajÄ sadaļÄ. TÄdÄjÄdi tiek izveidotas kodola datu struktÅ«ras un katrai no tÄm refcount (atsauces skaits) ir iestatÄ«ts uz vienu, un lietotÄjam tiek atgriezts faila deskriptors, kas norÄda uz objektu. PÄc tam, kad rokturis ir aizvÄrts refcount objekts tiek samazinÄts par vienu, un, kad tas sasniedz nulli, objekts tiek iznÄ«cinÄts.
Ja programma izmanto kartes, tad refcount Ŕīs kartes pÄc programmas ielÄdes tiek palielinÄtas par vienu, t.i. to failu deskriptorus var aizvÄrt no lietotÄja procesa un joprojÄm refcount nekļūs par nulli:
PÄc veiksmÄ«gas programmas ielÄdes mÄs to parasti pievienojam kÄdam notikumu Ä£eneratoram. PiemÄram, mÄs varam ievietot to tÄ«kla saskarnÄ, lai apstrÄdÄtu ienÄkoÅ”Äs paketes vai savienotu to ar dažÄm tracepoint kodolÄ. Å ajÄ brÄ«dÄ« arÄ« atsauces skaitÄ«tÄjs palielinÄsies par vienu, un mÄs varÄsim aizvÄrt faila deskriptoru ielÄdes programmÄ.
Kas notiks, ja mÄs tagad izslÄgsim sÄknÄÅ”anas programmu? Tas ir atkarÄ«gs no notikumu Ä£eneratora (ÄÄ·a) veida. Visi tÄ«kla ÄÄ·i pastÄvÄs pÄc iekrÄvÄja pabeigÅ”anas, tie ir tÄ sauktie globÄlie ÄÄ·i. Un, piemÄram, izsekoÅ”anas programmas tiks izlaistas pÄc tam, kad beigsies process, kas tÄs izveidoja (un tÄpÄc tÄs tiek sauktas par vietÄjÄm, no ālokÄlÄs uz procesuā). Tehniski lokÄlajiem ÄÄ·iem lietotÄja telpÄ vienmÄr ir atbilstoÅ”s faila deskriptors, un tÄpÄc tie tiek aizvÄrti, kad process tiek aizvÄrts, bet globÄlajiem ÄÄ·iem tÄ nav. NÄkamajÄ attÄlÄ, izmantojot sarkanos krustiÅus, mÄÄ£inu parÄdÄ«t, kÄ iekrÄvÄja programmas pÄrtraukÅ”ana ietekmÄ objektu kalpoÅ”anas laiku lokÄlo un globÄlo ÄÄ·u gadÄ«jumÄ.
KÄpÄc pastÄv atŔķirÄ«ba starp vietÄjiem un globÄlajiem ÄÄ·iem? Dažu veidu tÄ«kla programmu palaiÅ”ana ir jÄga bez lietotÄja telpas, piemÄram, iedomÄjieties DDoS aizsardzÄ«bu - sÄknÄÅ”anas ielÄdÄtÄjs raksta noteikumus un savieno BPF programmu ar tÄ«kla interfeisu, pÄc kura sÄknÄÅ”anas ielÄdÄtÄjs var doties un nogalinÄt sevi. No otras puses, iedomÄjieties atkļūdoÅ”anas izsekoÅ”anas programmu, ko desmit minÅ«Å”u laikÄ uzrakstÄ«jÄt uz ceļiem ā kad tÄ bÅ«s pabeigta, jÅ«s vÄlÄtos, lai sistÄmÄ nepaliktu nekÄdi atkritumi, un vietÄjie ÄÄ·i to nodroÅ”inÄs.
No otras puses, iedomÄjieties, ka vÄlaties izveidot savienojumu ar izsekoÅ”anas punktu kodolÄ un apkopot statistiku daudzu gadu garumÄ. Å ajÄ gadÄ«jumÄ jÅ«s vÄlaties pabeigt lietotÄja daļu un laiku pa laikam atgriezties pie statistikas. Bpf failu sistÄma nodroÅ”ina Å”o iespÄju. TÄ ir tikai atmiÅÄ esoÅ”a pseido failu sistÄma, kas ļauj izveidot failus, kas atsaucas uz BPF objektiem un tÄdÄjÄdi palielina refcount objektus. PÄc tam iekrÄvÄjs var iziet, un tÄ izveidotie objekti paliks dzÄ«vi.
Failu izveide bpffs, kas atsaucas uz BPF objektiem, tiek saukta par "piesprauÅ”anu" (kÄ Å”ajÄ frÄzÄ: "process var piespraust BPF programmu vai karti"). Failu objektu izveide BPF objektiem ir jÄga ne tikai lokÄlo objektu dzÄ«ves pagarinÄÅ”anai, bet arÄ« globÄlo objektu lietojamÄ«bas dÄļ ā atgriežoties pie piemÄra ar globÄlo DDoS aizsardzÄ«bas programmu, mÄs vÄlamies, lai varÄtu nÄkt un apskatÄ«t statistiku. laiku pa laikam.
BPF failu sistÄma parasti ir iebÅ«vÄta /sys/fs/bpf, bet to var uzstÄdÄ«t arÄ« lokÄli, piemÄram, Å”Ädi:
$ mkdir bpf-mountpoint
$ sudo mount -t bpf none bpf-mountpoint
Failu sistÄmu nosaukumi tiek izveidoti, izmantojot komandu BPF_OBJ_PIN BPF sistÄmas izsaukums. Lai ilustrÄtu, paÅemsim programmu, kompilÄjiet to, augÅ”upielÄdÄsim un piespraužam bpffs. MÅ«su programma nedara neko noderÄ«gu, mÄs tikai parÄdÄm kodu, lai jÅ«s varÄtu reproducÄt piemÄru:
Tagad lejupielÄdÄsim mÅ«su programmu, izmantojot utilÄ«tu bpftool un apskatiet pievienotos sistÄmas zvanus bpf(2) (no strace izvades noÅemtas dažas neatbilstoÅ”as āārindas):
Å eit mÄs esam ielÄdÄjuÅ”i programmu, izmantojot BPF_PROG_LOAD, saÅÄma faila deskriptoru no kodola 3 un izmantojot komandu BPF_OBJ_PIN piesprauda Å”o faila deskriptoru kÄ failu "bpf-mountpoint/test". PÄc tam sÄknÄÅ”anas programma bpftool pabeidza darbu, bet mÅ«su programma palika kodolÄ, lai gan mÄs to nepievienojÄm nevienam tÄ«kla interfeisam:
$ 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
Faila objektu varam dzÄst parasti unlink(2) un pÄc tam atbilstoÅ”Ä programma tiks dzÄsta:
$ sudo rm ./bpf-mountpoint/test
$ sudo bpftool prog show id 783
Error: get by id (783): No such file or directory
Objektu dzÄÅ”ana
RunÄjot par objektu dzÄÅ”anu, jÄprecizÄ, ka pÄc tam, kad bÅ«sim atvienojuÅ”i programmu no ÄÄ·a (notikumu Ä£eneratora), neviens jauns notikums neizraisÄ«s tÄs palaiÅ”anu, taÄu visas paÅ”reizÄjÄs programmas eksemplÄri tiks pabeigti parastajÄ secÄ«bÄ. .
Daži BPF programmu veidi ļauj nomainÄ«t programmu lidojuma laikÄ, t.i. nodroÅ”inÄt secÄ«bas atomitÄti replace = detach old program, attach new program. Å ajÄ gadÄ«jumÄ visas programmas vecÄs versijas aktÄ«vÄs instances beigs savu darbu, un no jaunÄs programmas tiks izveidoti jauni notikumu apstrÄdÄtÄji, un āatomicityā Å”eit nozÄ«mÄ, ka neviens notikums netiks palaists garÄm.
Programmu pievienoŔana notikumu avotiem
Å ajÄ rakstÄ mÄs atseviŔķi neaprakstÄ«sim programmu savienoÅ”anu ar notikumu avotiem, jo āāir jÄga to pÄtÄ«t konkrÄta programmas veida kontekstÄ. Cm. piemÄrs zemÄk, kurÄ mÄs parÄdÄm, kÄ tiek savienotas tÄdas programmas kÄ XDP.
ManipulÄÅ”ana ar objektiem, izmantojot bpf sistÄmas izsaukumu
BPF programmas
Visi BPF objekti tiek izveidoti un pÄrvaldÄ«ti no lietotÄja vietas, izmantojot sistÄmas zvanu bpf, kam ir Å”Äds prototips:
#include <linux/bpf.h>
int bpf(int cmd, union bpf_attr *attr, unsigned int size);
LÅ«k, komanda cmd ir viena no tipa vÄrtÄ«bÄm enum bpf_cmd, attr ā norÄde uz parametriem konkrÄtai programmai un size ā objekta izmÄrs atbilstoÅ”i rÄdÄ«tÄjam, t.i. parasti Å”is sizeof(*attr). KodolÄ 5.8 sistÄmas izsaukums bpf atbalsta 34 dažÄdas komandas un noteiktunion bpf_attr aizÅem 200 rindas. Bet mums tas nevajadzÄtu nobiedÄt, jo mÄs iepazÄ«simies ar komandÄm un parametriem vairÄku rakstu laikÄ.
SÄksim ar komandu BPF_PROG_LOAD, kas veido BPF programmas ā paÅem BPF instrukciju kopu un ielÄdÄ to kodolÄ. IelÄdes brÄ«dÄ« tiek palaists verificÄtÄjs, un pÄc tam JIT kompilators un pÄc veiksmÄ«gas izpildes programmas faila deskriptors tiek atgriezts lietotÄjam. To, kas ar viÅu notiek tÄlÄk, mÄs redzÄjÄm iepriekÅ”ÄjÄ sadaÄ¼Ä par BPF objektu dzÄ«ves ciklu.
Tagad mÄs uzrakstÄ«sim pielÄgotu programmu, kas ielÄdÄs vienkÄrÅ”u BPF programmu, bet vispirms mums ir jÄizlemj, kÄda veida programmu mÄs vÄlamies ielÄdÄt - mums bÅ«s jÄizvÄlas Tips un Ŕī tipa ietvaros uzrakstiet programmu, kas izturÄs verificÄtÄja pÄrbaudi. TomÄr, lai nesarežģītu procesu, Å”eit ir gatavs risinÄjums: mÄs Åemsim tÄdu programmu kÄ BPF_PROG_TYPE_XDP, kas atgriezÄ«s vÄrtÄ«bu XDP_PASS (izlaist visus iepakojumus). BPF montÄtÄjÄ tas izskatÄs ļoti vienkÄrÅ”i:
r0 = 2
exit
PÄc tam, kad esam izlÄmuÅ”i ka mÄs augÅ”upielÄdÄsim, mÄs varam jums pastÄstÄ«t, kÄ mÄs to darÄ«sim:
Interesanti notikumi programmÄ sÄkas ar masÄ«va definÄ«ciju insns - mÅ«su BPF programma maŔīnkodÄ. Å ajÄ gadÄ«jumÄ katrs BPF programmas norÄdÄ«jums tiek iesaiÅots struktÅ«rÄ bpf_insn. Pirmais elements insns atbilst instrukcijÄm r0 = 2, otrais - exit.
AtkÄpties. Kodols nosaka ÄrtÄkus makro maŔīnkodu rakstÄ«Å”anai un kodola galvenes faila izmantoÅ”anai tools/include/linux/filter.h mÄs varÄtu rakstÄ«t
Bet tÄ kÄ BPF programmu rakstÄ«Å”ana vietÄjÄ kodÄ ir nepiecieÅ”ama tikai kodola testu un rakstu par BPF rakstÄ«Å”anai, Å”o makro neesamÄ«ba izstrÄdÄtÄja dzÄ«vi Ä«sti nesarežģī.
PÄc BPF programmas definÄÅ”anas mÄs pÄrejam pie tÄs ielÄdes kodolÄ. MÅ«su minimÄlisma parametru komplekts attr ietver programmas veidu, instrukciju kopu un skaitu, nepiecieÅ”amo licenci un nosaukumu "woo", ko mÄs izmantojam, lai pÄc lejupielÄdes sistÄmÄ atrastu savu programmu. Programma, kÄ solÄ«ts, tiek ielÄdÄta sistÄmÄ, izmantojot sistÄmas izsaukumu bpf.
Programmas beigÄs mÄs nonÄkam bezgalÄ«gÄ cilpÄ, kas simulÄ lietderÄ«go slodzi. Bez tÄ kodols iznÄ«cinÄs programmu, kad tiks aizvÄrts faila deskriptors, ko mums atgrieza sistÄmas izsaukums. bpf, un mÄs to neredzÄsim sistÄmÄ.
Nu, mÄs esam gatavi testÄÅ”anai. Saliksim un palaidÄ«sim programmu zem stracelai pÄrbaudÄ«tu, vai viss darbojas tÄ, kÄ vajadzÄtu:
Viss ir kÄrtÄ«bÄ, bpf(2) atdeva mums rokturi 3, un mÄs iegÄjÄm bezgalÄ«gÄ cilpÄ ar pause(). MÄÄ£inÄsim atrast mÅ«su programmu sistÄmÄ. Lai to izdarÄ«tu, mÄs pÄriesim uz citu terminÄli un izmantosim utilÄ«tu bpftool:
MÄs redzam, ka sistÄmÄ ir ielÄdÄta programma woo kura globÄlais ID ir 390 un paÅ”laik notiek simple-prog ir atvÄrts faila deskriptors, kas norÄda uz programmu (un ja simple-prog tad pabeigs darbu woo pazudÄ«s). KÄ gaidÄ«ts, programma woo aizÅem 16 baitus - divas instrukcijas - binÄro kodu BPF arhitektÅ«rÄ, bet savÄ dzimtajÄ formÄ (x86_64) tas ir jau 40 baiti. ApskatÄ«sim mÅ«su programmu tÄs sÄkotnÄjÄ formÄ:
nekÄdu pÄrsteigumu. Tagad apskatÄ«sim JIT kompilatora Ä£enerÄto kodu:
# 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
nav Ä«paÅ”i efektÄ«va priekÅ” exit(2), bet godÄ«gi sakot, mÅ«su programma ir pÄrÄk vienkÄrÅ”a, un netriviÄlÄm programmÄm, protams, ir nepiecieÅ”ams JIT kompilatora pievienotais prologs un epilogs.
kartes
BPF programmas var izmantot strukturÄtus atmiÅas apgabalus, kas ir pieejami gan citÄm BPF programmÄm, gan programmÄm lietotÄja telpÄ. Å os objektus sauc par kartÄm, un Å”ajÄ sadaÄ¼Ä mÄs parÄdÄ«sim, kÄ ar tiem manipulÄt, izmantojot sistÄmas zvanu bpf.
Uzreiz teiksim, ka karÅ”u iespÄjas neaprobežojas tikai ar piekļuvi koplietotajai atmiÅai. Ir Ä«paÅ”as nozÄ«mes kartes, kas satur, piemÄram, norÄdes uz BPF programmÄm vai norÄdes uz tÄ«kla saskarnÄm, kartes darbam ar perf notikumiem utt. Par tiem Å”eit nerunÄsim, lai nemulsinÄtu lasÄ«tÄju. Bez tam mÄs ignorÄjam sinhronizÄcijas problÄmas, jo tas nav svarÄ«gi mÅ«su piemÄros. Pilns pieejamo karÅ”u veidu saraksts ir atrodams <linux/bpf.h>, un Å”ajÄ sadaÄ¼Ä kÄ piemÄru Åemsim vÄsturiski pirmo veidu, hash tabulu BPF_MAP_TYPE_HASH.
Ja jÅ«s izveidojat hash tabulu, piemÄram, C++ valodÄ, jÅ«s teiktu unordered_map<int,long> woo, kas krievu valodÄ nozÄ«mÄ āMan vajag galdu woo neierobežots izmÄrs, kura atslÄgas ir tipa int, un vÄrtÄ«bas ir veids long" Lai izveidotu BPF hash tabulu, mums ir jÄdara tas pats, izÅemot to, ka mums ir jÄnorÄda maksimÄlais tabulas izmÄrs, un tÄ vietÄ, lai norÄdÄ«tu atslÄgu un vÄrtÄ«bu veidus, mums ir jÄnorÄda to lielums baitos . Lai izveidotu kartes, izmantojiet komandu BPF_MAP_CREATE sistÄmas zvans bpf. ApskatÄ«sim vairÄk vai mazÄk minimÄlu programmu, kas izveido karti. PÄc iepriekÅ”ÄjÄs programmas, kas ielÄdÄ BPF programmas, Ŕī jums Ŕķiet vienkÄrÅ”a:
Å eit mÄs definÄjam parametru kopu attr, kurÄ sakÄm: āMan ir vajadzÄ«ga jaucÄj tabula ar taustiÅiem un lieluma vÄrtÄ«bÄm sizeof(int), kurÄ es varu ievietot ne vairÄk kÄ Äetrus elementus." Veidojot BPF kartes, var norÄdÄ«t citus parametrus, piemÄram, tÄpat kÄ piemÄrÄ ar programmu, objekta nosaukumu norÄdÄ«jÄm kÄ "woo".
Å eit ir sistÄmas izsaukums bpf(2) atgrieza mums deskriptora kartes numuru 3 un pÄc tam programma, kÄ paredzÄts, gaida turpmÄkus norÄdÄ«jumus sistÄmas izsaukumÄ pause(2).
Tagad nosÅ«tÄ«sim savu programmu uz fonu vai atveram citu terminÄli un apskatÄ«sim mÅ«su objektu, izmantojot utilÄ«tu bpftool (mÄs varam atŔķirt savu karti no citÄm pÄc tÄs nosaukuma):
$ sudo bpftool map
...
114: hash name woo flags 0x0
key 4B value 4B max_entries 4 memlock 4096B
...
Skaitlis 114 ir mÅ«su objekta globÄlais ID. Jebkura sistÄmas programma var izmantot Å”o ID, lai atvÄrtu esoÅ”u karti, izmantojot komandu BPF_MAP_GET_FD_BY_ID sistÄmas zvans bpf.
Tagad mÄs varam spÄlÄt ar mÅ«su hash tabulu. ApskatÄ«sim tÄ saturu:
$ sudo bpftool map dump id 114
Found 0 elements
TukÅ”s. Ieliksim tajÄ vÄrtÄ«bu hash[1] = 1:
$ sudo bpftool map update id 114 key 1 0 0 0 value 1 0 0 0
ApskatÄ«sim tabulu vÄlreiz:
$ sudo bpftool map dump id 114
key: 01 00 00 00 value: 01 00 00 00
Found 1 element
UrrÄ! Mums izdevÄs pievienot vienu elementu. Å emiet vÄrÄ, ka mums ir jÄstrÄdÄ baitu lÄ«menÄ«, lai to izdarÄ«tu, kopÅ” bptftool nezina, kÄda veida vÄrtÄ«bas ir hash tabulÄ. (Å Ä«s zinÄÅ”anas viÅai var nodot, izmantojot BTF, bet vairÄk par to tagad.)
KÄ tieÅ”i bpftool nolasa un pievieno elementus? PaskatÄ«simies zem pÄrsega:
Vispirms mÄs atvÄrÄm karti pÄc tÄs globÄlÄ ID, izmantojot komandu BPF_MAP_GET_FD_BY_ID Šø bpf(2) atgrieza mums deskriptoru 3. TÄlÄk izmantojot komandu BPF_MAP_GET_NEXT_KEY pirmo atslÄgu tabulÄ atradÄm garÄmejot NULL kÄ rÄdÄ«tÄjs uz "iepriekÅ”Äjo" taustiÅu. Ja mums ir atslÄga, mÄs varam darÄ«t BPF_MAP_LOOKUP_ELEMkas atgriež rÄdÄ«tÄjam vÄrtÄ«bu value. NÄkamais solis ir mÄÄ£inÄt atrast nÄkamo elementu, nododot rÄdÄ«tÄju uz paÅ”reizÄjo atslÄgu, bet mÅ«su tabulÄ ir tikai viens elements un komanda BPF_MAP_GET_NEXT_KEY atgriežas ENOENT.
Labi, mainÄ«sim vÄrtÄ«bu ar 1. atslÄgu. PieÅemsim, ka mÅ«su biznesa loÄ£ika prasa reÄ£istrÄciju hash[1] = 2:
KÄ gaidÄ«ts, tas ir ļoti vienkÄrÅ”i: komanda BPF_MAP_GET_FD_BY_ID atver mÅ«su karti pÄc ID un komandas BPF_MAP_UPDATE_ELEM pÄrraksta elementu.
TÄtad, izveidojot hash tabulu no vienas programmas, mÄs varam lasÄ«t un rakstÄ«t tÄs saturu no citas. Å emiet vÄrÄ: ja mÄs to varÄjÄm izdarÄ«t no komandrindas, tad to var izdarÄ«t jebkura cita sistÄmas programma. Papildus iepriekÅ” aprakstÄ«tajÄm komandÄm darbam ar kartÄm no lietotÄja vietas, Å”Ädi:
BPF_MAP_LOOKUP_ELEM: atrast vÄrtÄ«bu pÄc atslÄgas
BPF_MAP_GET_NEXT_KEY: atrodiet nÄkamo (vai pirmo) taustiÅu
BPF_MAP_GET_NEXT_ID: ļauj pÄrlÅ«kot visas esoÅ”Äs kartes, tÄ tas darbojas bpftool map
BPF_MAP_GET_FD_BY_ID: atver esoÅ”u karti pÄc tÄs globÄlÄ ID
BPF_MAP_LOOKUP_AND_DELETE_ELEM: atomiski atjauninÄt objekta vÄrtÄ«bu un atgriezt veco
BPF_MAP_FREEZE: padarÄ«t karti nemainÄ«gu no lietotÄja telpas (Å”o darbÄ«bu nevar atsaukt)
BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, BPF_MAP_UPDATE_BATCH, BPF_MAP_DELETE_BATCH: masu operÄcijas. PiemÄram, BPF_MAP_LOOKUP_AND_DELETE_BATCH - tas ir vienÄ«gais uzticamais veids, kÄ nolasÄ«t un atiestatÄ«t visas vÄrtÄ«bas no kartes
Ne visas Ŕīs komandas darbojas visiem karÅ”u veidiem, taÄu kopumÄ darbs ar cita veida kartÄm no lietotÄja vietas izskatÄs tieÅ”i tÄds pats kÄ darbs ar jaucÄj tabulÄm.
$ sudo bpftool map update id 114 key 5 0 0 0 value 1 0 0 0
Error: update failed: Argument list too long
KÄ jau gaidÄ«ts, mums neizdevÄs. ApskatÄ«sim kļūdu sÄ«kÄk:
$ 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 +++
Viss ir kÄrtÄ«bÄ: kÄ gaidÄ«ts, komanda BPF_MAP_UPDATE_ELEM mÄÄ£ina izveidot jaunu, piekto, atslÄgu, bet avarÄ E2BIG.
TÄtad, mÄs varam izveidot un ielÄdÄt BPF programmas, kÄ arÄ« izveidot un pÄrvaldÄ«t kartes no lietotÄja vietas. Tagad ir loÄ£iski aplÅ«kot, kÄ mÄs varam izmantot kartes no paÅ”Äm BPF programmÄm. MÄs par to varÄtu runÄt grÅ«ti lasÄmu programmu valodÄ maŔīnu makro kodos, bet patiesÄ«bÄ ir pienÄcis laiks parÄdÄ«t, kÄ patiesÄ«bÄ tiek rakstÄ«tas un uzturÄtas BPF programmas - izmantojot libbpf.
(LasÄ«tÄjiem, kuri nav apmierinÄti ar zema lÄ«meÅa piemÄra trÅ«kumu: mÄs detalizÄti analizÄsim programmas, kas izmanto kartes un palÄ«gfunkcijas, kas izveidotas, izmantojot libbpf un pastÄstÄ«t, kas notiek instrukciju lÄ«menÄ«. NeapmierinÄtajiem lasÄ«tÄjiem ļoti daudz, mÄs pievienojÄm piemÄrs attiecÄ«gajÄ raksta vietÄ.)
BPF programmu rakstīŔana, izmantojot libbpf
BPF programmu rakstÄ«Å”ana, izmantojot maŔīnas kodus, var bÅ«t interesanta tikai pirmajÄ reizÄ, un tad iestÄjas sÄta sajÅ«ta. Å ajÄ brÄ«dÄ« jums jÄpievÄrÅ” uzmanÄ«ba llvm, kam ir aizmugursistÄma koda Ä£enerÄÅ”anai BPF arhitektÅ«rai, kÄ arÄ« bibliotÄka libbpf, kas ļauj rakstÄ«t BPF lietojumprogrammu lietotÄja pusi un ielÄdÄt BPF programmu kodu, kas Ä£enerÄts, izmantojot llvm/clang.
Faktiski, kÄ mÄs redzÄsim Å”ajÄ un turpmÄkajos rakstos, libbpf diezgan daudz strÄdÄ bez tÄ (vai lÄ«dzÄ«giem rÄ«kiem - iproute2, libbcc, libbpf-gou.c.) dzÄ«vot nav iespÄjams. Viena no projekta galvenajÄm iezÄ«mÄm libbpf ir BPF CO-RE (Compile Once, Run Everywhere) - projekts, kas ļauj rakstÄ«t BPF programmas, kas ir pÄrnÄsÄjamas no viena kodola uz otru, ar iespÄju darboties dažÄdÄs API (piemÄram, mainoties kodola struktÅ«rai no versijas uz versiju). Lai varÄtu strÄdÄt ar CO-RE, jÅ«su kodolam jÄbÅ«t kompilÄtam ar BTF atbalstu (kÄ to izdarÄ«t, mÄs aprakstÄm sadaÄ¼Ä IzstrÄdes rÄ«ki. JÅ«s varat pÄrbaudÄ«t, vai jÅ«su kodols ir veidots ar BTF vai ne ļoti vienkÄrÅ”i - izmantojot Å”Ädu failu:
Å ajÄ failÄ tiek glabÄta informÄcija par visiem kodolÄ izmantotajiem datu tipiem, un tas tiek izmantots visos mÅ«su piemÄros, izmantojot libbpf. SÄ«kÄk par CO-RE mÄs runÄsim nÄkamajÄ rakstÄ, bet Å”ajÄ - vienkÄrÅ”i izveidojiet sev kodolu CONFIG_DEBUG_INFO_BTF.
BibliotÄka libbpf dzÄ«vo tieÅ”i direktorijÄ tools/lib/bpf kodols un tÄ izstrÄde tiek veikta, izmantojot adresÄtu sarakstu [email protected]. TomÄr Ärpus kodola dzÄ«vojoÅ”o lietojumprogrammu vajadzÄ«bÄm tiek uzturÄta atseviŔķa repozitorija https://github.com/libbpf/libbpf kurÄ kodola bibliotÄka tiek atspoguļota lasÄ«Å”anas piekļuvei vairÄk vai mazÄk tÄda, kÄda tÄ ir.
Å ajÄ sadaÄ¼Ä apskatÄ«sim, kÄ varat izveidot projektu, kas izmanto libbpf, uzrakstÄ«sim vairÄkas (vairÄk vai mazÄk bezjÄdzÄ«gas) testa programmas un detalizÄti analizÄsim, kÄ tas viss darbojas. Tas ļaus mums turpmÄkajÄs sadaļÄs vienkÄrÅ”Äk izskaidrot, kÄ BPF programmas mijiedarbojas ar kartÄm, kodola palÄ«giem, BTF utt.
Parasti projektos izmanto libbpf pievienojiet GitHub repozitoriju kÄ git apakÅ”moduli, mÄs darÄ«sim to paÅ”u:
MÅ«su nÄkamais plÄns Å”ajÄ sadaÄ¼Ä ir Å”Äds: mÄs uzrakstÄ«sim tÄdu BPF programmu kÄ BPF_PROG_TYPE_XDP, tÄpat kÄ iepriekÅ”ÄjÄ piemÄrÄ, bet C, mÄs to apkopojam, izmantojot clang, un uzrakstiet palÄ«gprogrammu, kas to ielÄdÄs kodolÄ. NÄkamajÄs sadaļÄs mÄs paplaÅ”inÄsim gan BPF programmas, gan asistentu programmas iespÄjas.
PiemÄrs: pilnvÄrtÄ«gas lietojumprogrammas izveide, izmantojot libbpf
SÄkumÄ mÄs izmantojam failu /sys/kernel/btf/vmlinux, kas tika minÄts iepriekÅ”, un izveidojiet tÄ ekvivalentu galvenes faila formÄ:
$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
Å ajÄ failÄ tiks saglabÄtas visas mÅ«su kodolÄ pieejamÄs datu struktÅ«ras, piemÄram, Å”Ädi kodolÄ tiek definÄta IPv4 galvene:
Lai gan mÅ«su programma izrÄdÄ«jÄs ļoti vienkÄrÅ”a, mums joprojÄm ir jÄpievÄrÅ” uzmanÄ«ba daudzÄm detaļÄm. PirmkÄrt, pirmais iekļautais galvenes fails ir vmlinux.h, kuru mÄs tikko Ä£enerÄjÄm, izmantojot bpftool btf dump - tagad mums nav jÄinstalÄ kodola galvenes pakotne, lai uzzinÄtu, kÄ izskatÄs kodola struktÅ«ras. TÄlÄk norÄdÄ«tais galvenes fails tiek saÅemts no bibliotÄkas libbpf. Tagad mums tas ir nepiecieÅ”ams tikai makro definÄÅ”anai SEC, kas nosÅ«ta rakstzÄ«mi uz attiecÄ«go ELF objekta faila sadaļu. MÅ«su programma ir ietverta sadaÄ¼Ä xdp/simple, kur pirms slÄ«psvÄ«tras mÄs definÄjam programmas veidu BPF - tÄ ir izmantota vienoÅ”anÄs libbpf, pamatojoties uz sadaļas nosaukumu, startÄÅ”anas laikÄ tas aizstÄs pareizo veidu bpf(2). BPF programma pati par sevi ir C - ļoti vienkÄrÅ”s un sastÄv no vienas rindas return XDP_PASS. Visbeidzot, atseviŔķa sadaļa "license" satur licences nosaukumu.
MÄs varam kompilÄt savu programmu, izmantojot llvm/clang, versija >= 10.0.0 vai, vÄl labÄk, jaunÄka (skatiet sadaļu IzstrÄdes rÄ«ki):
Starp interesantajÄm iezÄ«mÄm: mÄs norÄdÄm mÄrÄ·a arhitektÅ«ru -target bpf un ceļŔ uz galvenÄm libbpf, kuru mÄs nesen instalÄjÄm. TÄpat neaizmirstiet par -O2, bez Ŕīs iespÄjas nÄkotnÄ jÅ«s varÄtu sagaidÄ«t pÄrsteigumi. ApskatÄ«sim mÅ«su kodu, vai mums izdevÄs uzrakstÄ«t programmu, kuru gribÄjÄm?
JÄ, izdevÄs! Tagad mums ir binÄrs fails ar programmu, un mÄs vÄlamies izveidot lietojumprogrammu, kas to ielÄdÄs kodolÄ. Å im nolÅ«kam bibliotÄka libbpf piedÄvÄ mums divas iespÄjas - izmantot zemÄka lÄ«meÅa API vai augstÄka lÄ«meÅa API. MÄs iesim otro ceļu, jo mÄs vÄlamies iemÄcÄ«ties rakstÄ«t, ielÄdÄt un savienot BPF programmas ar minimÄlu piepÅ«li to turpmÄkajai izpÄtei.
PirmkÄrt, mums ir jÄÄ£enerÄ mÅ«su programmas āskeletsā no tÄs binÄrÄ faila, izmantojot to paÅ”u utilÄ«tu bpftool ā BPF pasaules Å veices nazis (ko var uztvert burtiski, jo Daniels Borkmans, viens no BPF radÄ«tÄjiem un uzturÄtÄjiem, ir Å”veicietis):
$ bpftool gen skeleton xdp-simple.bpf.o > xdp-simple.skel.h
FailÄ xdp-simple.skel.h satur mÅ«su programmas binÄro kodu un funkcijas mÅ«su objekta pÄrvaldÄ«Å”anai - ielÄdei, pievienoÅ”anai, dzÄÅ”anai. MÅ«su vienkÄrÅ”ajÄ gadÄ«jumÄ tas izskatÄs kÄ pÄrspÄ«lÄjums, taÄu tas darbojas arÄ« tad, ja objekta failÄ ir daudz BPF programmu un karÅ”u, un, lai ielÄdÄtu Å”o milzÄ«go ELF, mums vienkÄrÅ”i jÄÄ£enerÄ skelets un jÄizsauc viena vai divas funkcijas no pielÄgotÄs lietojumprogrammas. raksta. TÅ«lÄ«t turpinÄsim.
Stingri sakot, mÅ«su iekrÄvÄja programma ir triviÄla:
#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);
}
Å eit struct xdp_simple_bpf definÄts failÄ xdp-simple.skel.h un apraksta mÅ«su objekta failu:
Å eit mÄs varam redzÄt zema lÄ«meÅa API pÄdas: struktÅ«ra struct bpf_program *simple Šø struct bpf_link *simple. PirmÄ struktÅ«ra Ä«paÅ”i apraksta mÅ«su programmu, kas rakstÄ«ta sadaÄ¼Ä xdp/simple, bet otrajÄ ir aprakstÄ«ts, kÄ programma izveido savienojumu ar notikuma avotu.
Funkcija xdp_simple_bpf__open_and_load, atver ELF objektu, parsÄ to, izveido visas struktÅ«ras un apakÅ”struktÅ«ras (bez programmas ELF satur arÄ« citas sadaļas - dati, tikai lasÄmie dati, atkļūdoÅ”anas informÄcija, licence utt.), un pÄc tam, izmantojot sistÄmu, ielÄdÄ to kodolÄ. zvanu bpf, ko varam pÄrbaudÄ«t, apkopojot un palaižot programmu:
Tagad apskatÄ«sim mÅ«su programmu, izmantojot bpftool. AtradÄ«sim viÅas ID:
# bpftool p | grep -A4 simple
463: xdp name simple tag 3b185187f1855c4c gpl
loaded_at 2020-08-01T01:59:49+0000 uid 0
xlated 16B jited 40B memlock 4096B
btf_id 185
pids xdp-simple(16498)
un dump (mÄs izmantojam saÄ«sinÄtu komandas formu bpftool prog dump xlated):
# bpftool p d x id 463
int simple(void *ctx):
; return XDP_PASS;
0: (b7) r0 = 2
1: (95) exit
Kaut kas jauns! Programma izdrukÄja mÅ«su C avota faila gabalus. To izdarÄ«ja bibliotÄka libbpf, kas atrada atkļūdoÅ”anas sadaļu binÄrajÄ failÄ, kompilÄja to BTF objektÄ, ielÄdÄja kodolÄ, izmantojot BPF_BTF_LOAD, un pÄc tam, ielÄdÄjot programmu ar komandu, norÄdÄ«ja iegÅ«to faila deskriptoru BPG_PROG_LOAD.
Kodola palīgi
BPF programmas var palaist āÄrÄjasā funkcijas - kodola palÄ«gus. Å Ä«s palÄ«gfunkcijas ļauj BPF programmÄm piekļūt kodola struktÅ«rÄm, pÄrvaldÄ«t kartes un arÄ« sazinÄties ar āreÄlo pasauliā - izveidot perfektus notikumus, kontrolÄt aparatÅ«ru (piemÄram, novirzÄ«Å”anas paketes) utt.
PiemÄrs: bpf_get_smp_processor_id
Paradigmas āmÄcÄ«Å”anÄs pÄc piemÄraā ietvaros aplÅ«kosim vienu no palÄ«gfunkcijÄm, bpf_get_smp_processor_id(), zinÄms failÄ kernel/bpf/helpers.c. Tas atgriež tÄ procesora numuru, kurÄ darbojas BPF programma, kas to izsauca. Bet mÅ«s neinteresÄ tÄ semantika kÄ fakts, ka tÄ Ä«stenoÅ”ana aizÅem vienu lÄ«niju:
BPF palÄ«gfunkciju definÄ«cijas ir lÄ«dzÄ«gas Linux sistÄmas izsaukuma definÄ«cijÄm. Å eit, piemÄram, ir definÄta funkcija, kurai nav argumentu. (Funkcija, kas izmanto, piemÄram, trÄ«s argumentus, tiek definÄta, izmantojot makro BPF_CALL_3. MaksimÄlais argumentu skaits ir pieci.) TomÄr Ŕī ir tikai definÄ«cijas pirmÄ daļa. OtrajÄ daÄ¼Ä ir jÄdefinÄ tipa struktÅ«ra struct bpf_func_proto, kurÄ ir verificÄtÄjam saprotamÄs palÄ«gfunkcijas apraksts:
Lai noteikta veida BPF programmas varÄtu izmantot Å”o funkciju, tÄm tÄ ir jÄreÄ£istrÄ, piemÄram, tipam BPF_PROG_TYPE_XDP funkcija ir definÄta kodolÄ xdp_func_proto, kas no palÄ«gfunkcijas ID nosaka, vai XDP atbalsta Å”o funkciju vai ne. MÅ«su funkcija ir atbalsta:
Jaunie BPF programmu veidi ir "definÄti" failÄ include/linux/bpf_types.h izmantojot makro BPF_PROG_TYPE. DefinÄts pÄdiÅÄs, jo tÄ ir loÄ£iska definÄ«cija, un C valodas terminos citÄs vietÄs sastopama vesela betona konstrukciju kopuma definÄ«cija. Jo Ä«paÅ”i failÄ kernel/bpf/verifier.c visas definÄ«cijas no faila bpf_types.h tiek izmantoti, lai izveidotu struktÅ«ru masÄ«vu bpf_verifier_ops[]:
Tas nozÄ«mÄ, ka katram BPF programmas veidam ir definÄts rÄdÄ«tÄjs uz Å”Äda veida datu struktÅ«ru struct bpf_verifier_ops, kas tiek inicializÄts ar vÄrtÄ«bu _name ## _verifier_ops, t.i., xdp_verifier_ops par xdp. StruktÅ«ra xdp_verifier_opsnosaka failÄ net/core/filter.c Å”Ädi:
Å eit mÄs redzam mÅ«su pazÄ«stamo funkciju xdp_func_proto, kas palaiž verificÄtÄju katru reizi, kad saskarsies ar izaicinÄjumu kaut kÄda veida funkcijas BPF programmÄ, sk verifier.c.
ApskatÄ«sim, kÄ hipotÄtiskÄ BPF programma izmanto Å”o funkciju bpf_get_smp_processor_id. Lai to izdarÄ«tu, mÄs pÄrrakstÄm programmu no mÅ«su iepriekÅ”ÄjÄs sadaļas Å”Ädi:
tas ir, bpf_get_smp_processor_id ir funkcijas rÄdÄ«tÄjs, kura vÄrtÄ«ba ir 8, kur 8 ir vÄrtÄ«ba BPF_FUNC_get_smp_processor_id tips enum bpf_fun_id, kas mums ir definÄts failÄ vmlinux.h (fails bpf_helper_defs.h kodolÄ tiek Ä£enerÄts ar skriptu, tÄpÄc "burvju" skaitļi ir labi). Å Ä« funkcija neizmanto argumentus un atgriež tipa vÄrtÄ«bu __u32. Kad mÄs to palaižam savÄ programmÄ, clang Ä£enerÄ instrukciju BPF_CALL "pareizais veids" SastÄdÄ«sim programmu un apskatÄ«sim sadaļu xdp/simple:
PirmajÄ rindÄ mÄs redzam instrukcijas call, parametrs IMM kas ir vienÄds ar 8, un SRC_REG - nulle. SaskaÅÄ ar verificÄtÄja izmantoto ABI lÄ«gumu Å”is ir izsaukums uz palÄ«gfunkciju Nr. XNUMX. Kad tas ir palaists, loÄ£ika ir vienkÄrÅ”a. AtgrieÅ”anas vÄrtÄ«ba no reÄ£istra r0 kopÄts uz r1 un 2,3. rindÄ tas tiek pÄrveidots par tipu u32 ā tiek notÄ«rÄ«ti augÅ”Äjie 32 biti. 4,5,6,7 rindÄ mÄs atgriežam 2 (XDP_PASS) vai 1 (XDP_DROP) atkarÄ«bÄ no tÄ, vai palÄ«gfunkcija no 0. rindas atgrieza nulles vai nulles vÄrtÄ«bu.
PÄrbaudÄ«sim sevi: ielÄdÄjam programmu un apskatÄ«sim izvadi 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
Labi, pÄrbaudÄ«tÄjs atrada pareizo kodola palÄ«gu.
PiemÄrs: argumentu nodoÅ”ana un visbeidzot programmas palaiÅ”ana!
VisÄm izpildes lÄ«meÅa palÄ«gfunkcijÄm ir prototips
u64 fn(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
Parametri palÄ«gfunkcijÄm tiek nodoti reÄ£istros r1SÄkot nor5, un vÄrtÄ«ba tiek atgriezta reÄ£istrÄ r0. Nav tÄdu funkciju, kurÄm bÅ«tu nepiecieÅ”ami vairÄk nekÄ pieci argumenti, un to atbalsts nav paredzÄts nÄkotnÄ.
ApskatÄ«sim jauno kodola palÄ«gu un to, kÄ BPF nodod parametrus. PÄrrakstÄ«sim xdp-simple.bpf.c Å”Ädi (pÄrÄjÄs rindas nav mainÄ«tas):
SEC("xdp/simple")
int simple(void *ctx)
{
bpf_printk("running on CPU%un", bpf_get_smp_processor_id());
return XDP_PASS;
}
MÅ«su programma izdrukÄ tÄ CPU numuru, kurÄ tÄ darbojas. Apkoposim to un apskatÄ«sim kodu:
0-7 rindÄ mÄs rakstÄm virkni running on CPU%un, un tad 8. rindÄ mÄs palaižam pazÄ«stamo bpf_get_smp_processor_id. 9.-12.rindÄ sagatavojam palÄ«ga argumentus bpf_printk - reÄ£istri r1, r2, r3. KÄpÄc viÅi ir trÄ«s, nevis divi? Jo bpf_printk SÄkot no Å”is ir makro iesaiÅojums ap Ä«sto palÄ«gu bpf_trace_printk, kam jÄnodod formÄta virknes izmÄrs.
Tagad pievienosim pÄris rindiÅas xdp-simple.clai mÅ«su programma izveidotu savienojumu ar saskarni lo un tieÅ”Äm sÄkÄs!
Å eit mÄs izmantojam funkciju bpf_set_link_xdp_fd, kas savieno XDP tipa BPF programmas ar tÄ«kla saskarnÄm. MÄs iekodÄjÄm saskarnes numuru lo, kas vienmÄr ir 1. MÄs palaižam funkciju divas reizes, lai vispirms atvienotu veco programmu, ja tÄ bija pievienota. IevÄrojiet, ka tagad mums nav nepiecieÅ”ams izaicinÄjums pause vai bezgalÄ«ga cilpa: mÅ«su ielÄdes programma tiks aizvÄrta, bet BPF programma netiks iznÄ«cinÄta, jo tÄ ir savienota ar notikuma avotu. PÄc veiksmÄ«gas lejupielÄdes un savienojuma izveides programma tiks palaista katrai tÄ«kla paketei, kas nonÄk pie lo.
LejupielÄdÄsim programmu un apskatÄ«sim interfeisu 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
LejupielÄdÄtajai programmai ir ID 669, un mÄs redzam to paÅ”u ID interfeisÄ lo. NosÅ«tÄ«sim pÄris pakas uz 127.0.0.1 (pieprasÄ«jums + atbilde):
$ ping -c1 localhost
un tagad apskatÄ«sim atkļūdoÅ”anas virtuÄlÄ faila saturu /sys/kernel/debug/tracing/trace_pipe, kurÄ bpf_printk raksta savus ziÅojumus:
# 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
Tika pamanÄ«ti divi iepakojumi lo un apstrÄdÄts uz CPU0 - mÅ«su pirmÄ pilnvÄrtÄ«gÄ bezjÄdzÄ«gÄ BPF programma strÄdÄja!
Ir vÄrts atzÄ«mÄt, ka bpf_printk Ne velti tas raksta atkļūdoÅ”anas failÄ: Å”is nav veiksmÄ«gÄkais palÄ«gs izmantoÅ”anai ražoÅ”anÄ, taÄu mÅ«su mÄrÄ·is bija parÄdÄ«t kaut ko vienkÄrÅ”u.
Piekļuve kartÄm no BPF programmÄm
PiemÄrs: izmantojot karti no BPF programmas
IepriekÅ”ÄjÄs sadaļÄs mÄs uzzinÄjÄm, kÄ izveidot un izmantot kartes no lietotÄja vietas, un tagad apskatÄ«sim kodola daļu. SÄksim, kÄ parasti, ar piemÄru. PÄrrakstÄ«sim savu programmu xdp-simple.bpf.c Å”Ädi:
Programmas sÄkumÄ pievienojÄm kartes definÄ«ciju woo: Å is ir 8 elementu masÄ«vs, kurÄ tiek saglabÄtas tÄdas vÄrtÄ«bas kÄ u64 (C valodÄ mÄs definÄtu Å”Ädu masÄ«vu kÄ u64 woo[8]). ProgrammÄ "xdp/simple" mÄs iegÅ«stam paÅ”reizÄjo procesora numuru mainÄ«gajÄ key un pÄc tam izmantojot palÄ«ga funkciju bpf_map_lookup_element iegÅ«stam rÄdÄ«tÄju uz atbilstoÅ”o ierakstu masÄ«vÄ, kuru palielinÄm par vienu. Tulkots krievu valodÄ: mÄs aprÄÄ·inÄm statistiku par to, kurÅ” CPU apstrÄdÄja ienÄkoÅ”Äs paketes. MÄÄ£inÄsim palaist programmu:
PÄrbaudÄ«sim, vai viÅa ir pieÄ·Ärusies lo un nosÅ«tiet dažas paketes:
$ 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
GandrÄ«z visi procesi tika apstrÄdÄti CPU7. Tas mums nav svarÄ«gi, galvenais, lai programma strÄdÄ un mÄs saprotam, kÄ piekļūt kartÄm no BPF programmÄm - izmantojot Ń ŠµŠ»ŠæŠµŃŠ¾Š² bpf_mp_*.
Mistisks rÄdÄ«tÄjs
TÄtad, mÄs varam piekļūt kartei no BPF programmas, izmantojot tÄdus zvanus kÄ
$ 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
Bet, ja mÄs skatÄmies uz jau ielÄdÄtu programmu, mÄs redzam rÄdÄ«tÄju uz pareizo karti (4. rindiÅa):
TÄdÄjÄdi mÄs varam secinÄt, ka mÅ«su iekrÄvÄja programmas palaiÅ”anas laikÄ saite uz &woo tika aizstÄts ar kaut ko ar bibliotÄku libbpf. Vispirms apskatÄ«sim izvadi strace:
MÄs to redzam libbpf izveidoja karti woo un pÄc tam lejupielÄdÄjÄm mÅ«su programmu simple. SÄ«kÄk apskatÄ«sim, kÄ mÄs ielÄdÄjam programmu:
zvanu xdp_simple_bpf__open_and_load no faila xdp-simple.skel.h
kas izraisa xdp_simple_bpf__load no faila xdp-simple.skel.h
kas izraisa bpf_object__load_skeleton no faila libbpf/src/libbpf.c
kas izraisa bpf_object__load_xattr no libbpf/src/libbpf.c
Cita starpÄ tiks izsaukta pÄdÄjÄ funkcija bpf_object__create_maps, kas izveido vai atver esoÅ”Äs kartes, pÄrvÄrÅ”ot tÄs par failu deskriptoriem. (Å eit mÄs redzam BPF_MAP_CREATE izejÄ strace.) TÄlÄk tiek izsaukta funkcija bpf_object__relocate un tieÅ”i viÅa mÅ«s interesÄ, jo mÄs atceramies redzÄto woo pÄrvietoÅ”anas tabulÄ. IzpÄtot to, mÄs galu galÄ atrodamies funkcijÄ bpf_program__relocate, kas nodarbojas ar karÅ”u pÄrvietoÅ”anu:
case RELO_LD64:
insn[0].src_reg = BPF_PSEUDO_MAP_FD;
insn[0].imm = obj->maps[relo->map_idx].fd;
break;
un aizstÄt avota reÄ£istru tajÄ ar BPF_PSEUDO_MAP_FD, un pirmais IMM mÅ«su kartes faila deskriptoram un, ja tas ir vienÄds ar, piemÄram, 0xdeadbeef, tad rezultÄtÄ saÅemsim instrukciju
18 11 00 00 ef eb ad de 00 00 00 00 00 00 00 00 r1 = 0 ll
TÄdÄ veidÄ kartes informÄcija tiek pÄrsÅ«tÄ«ta uz konkrÄtu ielÄdÄtu BPF programmu. Å ajÄ gadÄ«jumÄ karti var izveidot, izmantojot BPF_MAP_CREATEun atvÄrts ar ID, izmantojot BPF_MAP_GET_FD_BY_ID.
KopÄ, lietojot libbpf algoritms ir Å”Äds:
kompilÄcijas laikÄ pÄrvietoÅ”anas tabulÄ tiek izveidoti ieraksti saitÄm uz kartÄm
libbpf atver ELF objektu grÄmatu, atrod visas izmantotÄs kartes un izveido tÄm failu deskriptorus
failu deskriptori tiek ielÄdÄti kodolÄ kÄ daļa no instrukcijas LD64
KÄ jÅ«s varat iedomÄties, priekÅ”Ä ir vÄl vairÄk, un mums bÅ«s jÄizpÄta kodols. Par laimi, mums ir nojausma ā esam pierakstÄ«juÅ”i nozÄ«mi BPF_PSEUDO_MAP_FD avota reÄ£istrÄ un mÄs varam to apglabÄt, kas mÅ«s aizvedÄ«s uz visu svÄto svÄto vietu - kernel/bpf/verifier.c, kur funkcija ar atŔķirÄ«gu nosaukumu aizstÄj faila deskriptoru ar tipa struktÅ«ras adresi struct bpf_map:
LejupielÄdÄjot ELF binÄro failu, izmantojot libbpf Notiek daudz vairÄk, bet mÄs to apspriedÄ«sim citos rakstos.
Programmu un karÅ”u ielÄde bez libbpf
KÄ solÄ«ts, Å”eit ir piemÄrs lasÄ«tÄjiem, kuri vÄlas uzzinÄt, kÄ bez palÄ«dzÄ«bas izveidot un ielÄdÄt programmu, kas izmanto kartes libbpf. Tas var bÅ«t noderÄ«gi, ja strÄdÄjat vidÄ, kurÄ nevarat izveidot atkarÄ«bas vai saglabÄjat katru bitu, vai rakstÄt tÄdu programmu kÄ ply, kas lidojumÄ Ä£enerÄ BPF binÄro kodu.
Lai bÅ«tu vieglÄk ievÄrot loÄ£iku, mÄs Å”iem nolÅ«kiem pÄrrakstÄ«sim savu piemÄru xdp-simple. Pilns un nedaudz paplaÅ”inÄts Å”ajÄ piemÄrÄ aplÅ«kotÄs programmas kods ir atrodams Å”ajÄ bÅ«tÄ«ba.
MÅ«su lietojumprogrammas loÄ£ika ir Å”Äda:
izveidot tipa karti BPF_MAP_TYPE_ARRAY izmantojot komandu BPF_MAP_CREATE,
izveidot programmu, kas izmanto Ŕo karti,
savienojiet programmu ar interfeisu lo,
kas tulkojumÄ nozÄ«mÄ cilvÄku kÄ
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);
}
Å eit map_create izveido karti tÄdÄ paÅ”Ä veidÄ, kÄ mÄs to darÄ«jÄm pirmajÄ piemÄrÄ par sistÄmas zvanu bpf - ākodolu, lÅ«dzu, izveidojiet man jaunu karti 8 elementu masÄ«va veidÄ, piemÄram __u64 un atdodiet man faila deskriptoru":
SarežģītÄ daļa prog_load ir mÅ«su BPF programmas definÄ«cija kÄ struktÅ«ru masÄ«vs struct bpf_insn insns[]. Bet, tÄ kÄ mÄs izmantojam programmu, kas mums ir C, mÄs varam nedaudz krÄpties:
VingrinÄjums tiem, kuri paÅ”i to nav rakstÄ«juÅ”i - atrodiet map_fd.
MÅ«su programmÄ ir palikusi vÄl viena neatklÄta daļa - xdp_attach. DiemžÄl tÄdas programmas kÄ XDP nevar savienot, izmantojot sistÄmas zvanu bpf. CilvÄki, kas izveidoja BPF un XDP, bija no tieÅ”saistes Linux kopienas, kas nozÄ«mÄ, ka viÅi izmantoja sev vispazÄ«stamÄko (bet ne normÄli cilvÄki) saskarne mijiedarbÄ«bai ar kodolu: netlink ligzdas, SkatÄ«t arÄ« RFC3549. VienkÄrÅ”Äkais Ä«stenoÅ”anas veids xdp_attach kopÄ kodu no libbpf, proti, no faila netlink.c, ko mÄs arÄ« izdarÄ«jÄm, nedaudz saÄ«sinot:
Laipni lÅ«dzam netlink ligzdu pasaulÄ
Atveriet tīkla saites ligzdas veidu 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;
}
MÄs lasÄm no Ŕīs ligzdas:
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;
}
Visbeidzot, Å”eit ir mÅ«su funkcija, kas atver ligzdu un nosÅ«ta tai Ä«paÅ”u ziÅojumu, kurÄ ir faila deskriptors:
Apskatīsim, vai mūsu programma ir savienota ar 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
UrÄ, viss darbojas. Starp citu, Åemiet vÄrÄ, ka mÅ«su karte atkal tiek parÄdÄ«ta baitu veidÄ. Tas ir saistÄ«ts ar faktu, ka atŔķirÄ«bÄ no libbpf mÄs neielÄdÄjÄm tipa informÄciju (BTF). Bet par to vairÄk parunÄsim nÄkamreiz.
IzstrÄdes rÄ«ki
Å ajÄ sadaÄ¼Ä mÄs apskatÄ«sim minimÄlo BPF izstrÄdÄtÄja rÄ«ku komplektu.
VispÄrÄ«gi runÄjot, jums nav nepiecieÅ”ams nekas Ä«paÅ”s, lai izstrÄdÄtu BPF programmas ā BPF darbojas uz jebkura pienÄcÄ«ga izplatÄ«Å”anas kodola, un programmas tiek veidotas, izmantojot clang, ko var piegÄdÄt no iepakojuma. TaÄu sakarÄ ar to, ka BPF ir izstrÄdes stadijÄ, kodols un rÄ«ki nemitÄ«gi mainÄs, ja nevÄlaties rakstÄ«t BPF programmas ar vecmodÄ«gÄm metodÄm no 2019. gada, tad nÄksies kompilÄt
llvm/clang
pahole
tÄs kodols
bpftool
(UzziÅai Ŕī sadaļa un visi rakstÄ minÄtie piemÄri tika palaisti Debian 10.)
llvm/clang
BPF ir draudzÄ«gs ar LLVM un, lai gan pÄdÄjÄ laikÄ BPF programmas var kompilÄt, izmantojot gcc, visa paÅ”reizÄjÄ izstrÄde tiek veikta LLVM. TÄpÄc, pirmkÄrt, mÄs veidosim paÅ”reizÄjo versiju clang no git:
(To var pievienot .bashrc vai uz atseviŔķu failu. PersonÄ«gi es pievienoju Å”Ädas lietas ~/bin/activate-llvm.sh un kad vajag, es to daru . activate-llvm.sh.)
Pahole un BTF
LietderÄ«ba pahole izmanto, veidojot kodolu, lai izveidotu atkļūdoÅ”anas informÄciju BTF formÄtÄ. Å ajÄ rakstÄ mÄs nerunÄsim par BTF tehnoloÄ£ijas detaļÄm, izÅemot to, ka tÄ ir Ärta un mÄs vÄlamies to izmantot. TÄtad, ja jÅ«s gatavojaties izveidot savu kodolu, vispirms izveidojiet pahole (bez pahole jÅ«s nevarÄsit izveidot kodolu ar opciju 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
Kodoli eksperimentiem ar BPF
IzpÄtot BPF iespÄjas, es vÄlos samontÄt savu kodolu. VispÄrÄ«gi runÄjot, tas nav nepiecieÅ”ams, jo jÅ«s varÄsiet kompilÄt un ielÄdÄt BPF programmas izplatÄ«Å”anas kodolÄ, taÄu, ja jums ir savs kodols, varat izmantot jaunÄkÄs BPF funkcijas, kas labÄkajÄ gadÄ«jumÄ parÄdÄ«sies jÅ«su izplatÄ«Å”anÄ pÄc mÄneÅ”iem. , vai, tÄpat kÄ dažu atkļūdoÅ”anas rÄ«ku gadÄ«jumÄ, pÄrskatÄmÄ nÄkotnÄ netiks iepakoti vispÄr. TurklÄt tÄ kodols liek justies svarÄ«giem eksperimentÄt ar kodu.
Lai izveidotu kodolu, jums ir nepiecieÅ”ams, pirmkÄrt, pats kodols un, otrkÄrt, kodola konfigurÄcijas fails. Lai eksperimentÄtu ar BPF, mÄs varam izmantot parasto vaniļa kodolu vai kÄdu no izstrÄdes kodoliem. VÄsturiski BPF izstrÄde notiek Linux tÄ«klu kopienÄ, un tÄpÄc visas izmaiÅas agrÄk vai vÄlÄk notiek ar Deivida Millera, Linux tÄ«kla uzturÄtÄja, starpniecÄ«bu. AtkarÄ«bÄ no to rakstura ā labojumi vai jaunas funkcijas ā tÄ«kla izmaiÅas ietilpst vienÄ no diviem kodoliem. net vai net-next. BPF izmaiÅas tiek sadalÄ«tas tÄdÄ paÅ”Ä veidÄ starp bpf Šø bpf-next, kas pÄc tam tiek apvienoti attiecÄ«gi neto un neto-next. SÄ«kÄku informÄciju skatiet bpf_devel_QA Šø netdev-FAQ. TÄpÄc izvÄlieties kodolu, pamatojoties uz savu gaumi un testÄjamÄs sistÄmas stabilitÄtes vajadzÄ«bÄm (*-next kodoli ir nestabilÄkie no uzskaitÄ«tajiem).
Å is raksts neietilpst runÄt par kodola konfigurÄcijas failu pÄrvaldÄ«bu ā tiek pieÅemts, ka jÅ«s jau zinÄt, kÄ to izdarÄ«t, vai gatavs mÄcÄ«ties paÅ”a spÄkiem. TomÄr ar Å”iem norÄdÄ«jumiem vajadzÄtu bÅ«t vairÄk vai mazÄk pietiekamiem, lai nodroÅ”inÄtu funkcionÄjoÅ”u sistÄmu ar iespÄjotu BPF.
LejupielÄdÄjiet vienu no iepriekÅ” minÄtajiem kodoliem:
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
$ cd bpf-next
Izveidojiet minimÄlu strÄdÄjoÅ”u kodola konfigurÄciju:
$ cp /boot/config-`uname -r` .config
$ make localmodconfig
IespÄjot failÄ BPF opcijas .config pÄc jÅ«su izvÄles (visticamÄk CONFIG_BPF jau bÅ«s iespÄjots, jo systemd to izmanto). Å eit ir Å”ajÄ rakstÄ izmantotÄ kodola opciju saraksts:
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
PÄc tam mÄs varam viegli salikt un instalÄt moduļus un kodolu (starp citu, jÅ«s varat salikt kodolu, izmantojot tikko salikto clangpievienojot CC=clang):
$ make -s -j $(getconf _NPROCESSORS_ONLN)
$ sudo make modules_install
$ sudo make install
un restartÄjiet ar jauno kodolu (es izmantoju Å”im nolÅ«kam kexec no iepakojuma kexec-tools):
RakstÄ visbiežÄk izmantotÄ utilÄ«ta bÅ«s lietderÄ«ba bpftool, kas tiek piegÄdÄts kÄ daļa no Linux kodola. To ir rakstÄ«juÅ”i un uzturÄjuÅ”i BPF izstrÄdÄtÄji BPF izstrÄdÄtÄjiem, un to var izmantot visu veidu BPF objektu pÄrvaldÄ«Å”anai ā programmu ielÄdei, karÅ”u izveidei un rediÄ£ÄÅ”anai, BPF ekosistÄmas dzÄ«ves izpÄtei utt. Var atrast dokumentÄciju rokasgrÄmatu avota kodu veidÄ kodolÄ vai jau apkopots, tÄ«klÄ.
Å Ä«s rakstÄ«Å”anas laikÄ bpftool ir gatavs tikai RHEL, Fedora un Ubuntu (skatiet, piemÄram, Å”is pavediens, kas stÄsta par nepabeigto iepakojuma stÄstu bpftool programmÄ Debian). Bet, ja jau esat izveidojis savu kodolu, tad izveidojiet bpftool tik vienkÄrÅ”i kÄ pÄ«rÄgs:
$ 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 ]
$
(Å”eit ${linux} - tas ir jÅ«su kodola direktorijs.) PÄc Å”o komandu izpildes bpftool tiks apkopoti direktorijÄ ${linux}/tools/bpf/bpftool un to var pievienot ceļam (vispirms lietotÄjam root) vai vienkÄrÅ”i kopÄjiet uz /usr/local/sbin.
SavÄkt bpftool vislabÄk ir izmantot pÄdÄjo clang, samontÄts, kÄ aprakstÄ«ts iepriekÅ”, un pÄrbaudiet, vai tas ir pareizi salikts - izmantojot, piemÄram, komandu
$ 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
...
kas parÄdÄ«s, kuras BPF funkcijas ir iespÄjotas jÅ«su kodolÄ.
Starp citu, iepriekÅ”Äjo komandu var palaist kÄ
# bpftool f p k
Tas tiek darÄ«ts pÄc analoÄ£ijas ar komunÄlajiem pakalpojumiem no iepakojuma iproute2, kur mÄs varam, piemÄram, teikt ip a s eth0 nevis ip addr show dev eth0.
SecinÄjums
BPF ļauj jums apavu blusu, lai efektÄ«vi izmÄrÄ«tu un lidojuma laikÄ mainÄ«tu kodola funkcionalitÄti. SistÄma izrÄdÄ«jÄs ļoti veiksmÄ«ga atbilstoÅ”i labÄkajÄm UNIX tradÄ«cijÄm: vienkÄrÅ”s mehÄnisms, kas ļauj (pÄr)programmÄt kodolu, ļÄva eksperimentÄt ļoti daudziem cilvÄkiem un organizÄcijÄm. Un, lai gan eksperimenti, kÄ arÄ« paÅ”as BPF infrastruktÅ«ras attÄ«stÄ«ba vÄl nebÅ«t nav pabeigta, sistÄmai jau ir stabils ABI, kas ļauj izveidot uzticamu un, pats galvenais, efektÄ«vu biznesa loÄ£iku.
Es vÄlos atzÄ«mÄt, ka, manuprÄt, tehnoloÄ£ija ir kļuvusi tik populÄra, jo, no vienas puses, tÄ var spÄlÄt (maŔīnas arhitektÅ«ru var saprast vairÄk vai mazÄk vienÄ vakarÄ), un no otras puses, lai atrisinÄtu problÄmas, kuras nevarÄja atrisinÄt (skaisti) pirms tÄs parÄdÄ«Å”anÄs. Å Ä«s divas sastÄvdaļas kopÄ liek cilvÄkiem eksperimentÄt un sapÅot, kas noved pie arvien inovatÄ«vÄku risinÄjumu raÅ”anÄs.
Å is raksts, lai gan tas nav Ä«paÅ”i Ä«ss, ir tikai ievads BPF pasaulÄ un neapraksta āuzlabotasā funkcijas un svarÄ«gas arhitektÅ«ras daļas. TurpmÄkais plÄns ir apmÄram Å”Äds: nÄkamais raksts bÅ«s BPF programmu veidu pÄrskats (5.8 kodolÄ tiek atbalstÄ«ti 30 programmu veidi), tad beidzot apskatÄ«sim, kÄ rakstÄ«t Ä«stas BPF lietojumprogrammas, izmantojot kodola izsekoÅ”anas programmas. PiemÄram, ir pienÄcis laiks padziļinÄtam kursam par BPF arhitektÅ«ru, kam seko BPF tÄ«klu un droŔības lietojumprogrammu piemÄri.
BPF un XDP uzziÅu rokasgrÄmata ā dokumentÄcija par BPF no cilium vai precÄ«zÄk no Daniela Borkmana, viena no BPF radÄ«tÄjiem un uzturÄtÄjiem. Å is ir viens no pirmajiem nopietnajiem aprakstiem, kas no pÄrÄjiem atŔķiras ar to, ka Daniels precÄ«zi zina par ko raksta un tur nav nekÄdu kļūdu. Jo Ä«paÅ”i Å”ajÄ dokumentÄ ir aprakstÄ«ts, kÄ strÄdÄt ar XDP un TC tipa BPF programmÄm, izmantojot labi zinÄmo utilÄ«tu. ip no iepakojuma iproute2.
DokumentÄcija/tÄ«kls/filter.txt ā oriÄ£inÄlais fails ar dokumentÄciju klasiskajam un pÄc tam paplaÅ”inÄtajam BPF. Laba lasÄmviela, ja vÄlaties iedziļinÄties montÄžas valodÄ un tehniskajÄs arhitektÅ«ras detaļÄs.
EmuÄrs par BPF no Facebook. Tas tiek atjauninÄts reti, bet trÄpÄ«gi, kÄ tur raksta Aleksejs Starovoitovs (eBPF autors) un Andrii Nakryiko - (apkopÄjs) libbpf).
Bpftool noslÄpumi. IzklaidÄjoÅ”s Twitter pavediens no Quentin Monnet ar bpftool izmantoÅ”anas piemÄriem un noslÄpumiem.