I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Ekuqaleni kwakunobuchwepheshe futhi babubizwa nge-BPF. Sambuka okwedlule, isihloko seTestamente Elidala salolu chungechunge. Ngo-2013, ngemizamo ka-Alexei Starovoitov noDaniel Borkman, inguqulo yayo ethuthukisiwe, elungiselelwe imishini yesimanje engu-64-bit, yathuthukiswa futhi yafakwa ku-Linux kernel. Lobu buchwepheshe obusha babizwa kafushane ngokuthi i-BPF Yangaphakathi, yabe isiqanjwa kabusha ngokuthi i-Extended BPF, futhi manje, ngemva kweminyaka eminingana, wonke umuntu uvele ayibize nge-BPF.

Uma sikhuluma nje, i-BPF ikuvumela ukuthi usebenzise ikhodi ehlinzekwe ngabasebenzisi ngokungafanele endaweni ye-Linux kernel, futhi ukwakheka okusha kuphumelele kangangokuthi sizodinga izindatshana eziyishumi nambili ukuchaza zonke izinhlelo zokusebenza. (Okuwukuphela kwento onjiniyela abangayenzanga kahle, njengoba ubona kukhodi yokusebenza engezansi, bekuwukwenza ilogo ehloniphekile.)

Lesi sihloko sichaza isakhiwo somshini we-BPF virtual, i-kernel interfaces yokusebenza ne-BPF, amathuluzi okuthuthukisa, kanye nombono omfushane, omfushane kakhulu wamakhono akhona, i.e. yonke into esizoyidinga esikhathini esizayo ukuze sicwaninge ngokujulile ukusetshenziswa okusebenzayo kwe-BPF.
I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Isifinyezo se-athikili

Isingeniso se-BPF Architecture. Okokuqala, sizobheka iso lenyoni ngesakhiwo se-BPF futhi siveze izingxenye eziyinhloko.

Amarejista kanye nohlelo lomyalo lomshini obonakalayo we-BPF. Njengoba sesinombono wezakhiwo sezizonke, sizochaza ukwakheka komshini obonakalayo we-BPF.

Umjikelezo wokuphila wezinto ze-BPF, uhlelo lwefayela le-bpffs. Kulesi sigaba, sizobhekisisa umjikelezo wempilo wezinto ze-BPF - izinhlelo namamephu.

Ukuphatha izinto usebenzisa ikholi yesistimu ye-bpf. Ngokuqonda okuthile kohlelo oseluvele lukhona, ekugcineni sizobheka ukuthi zingakha kanjani futhi zilawule izinto endaweni yomsebenzisi kusetshenziswa ucingo olukhethekile lwesistimu βˆ’ bpf(2).

ПишСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ libbpf. Yebo, ungabhala izinhlelo usebenzisa ikholi yesistimu. Kodwa kunzima. Ukuze uthole isimo esingokoqobo, abahleli bezinhlelo zenuzi bakha umtapo wolwazi libbpf. Sizodala uhlaka lwamathambo oluyisisekelo lwe-BPF esizolusebenzisa ezibonelweni ezilandelayo.

Abasizi beKernel. Lapha sizofunda ukuthi izinhlelo ze-BPF zingafinyelela kanjani kumisebenzi yomsizi we-kernel - ithuluzi, kanye namamephu, elikhulisa ngokuyisisekelo amakhono e-BPF entsha uma kuqhathaniswa neyakudala.

Ukufinyelela kumamephu kusuka ezinhlelweni ze-BPF. Ngalesi sikhathi, sizokwazi ngokwanele ukuqonda kahle ukuthi singadala kanjani izinhlelo ezisebenzisa amamephu. Futhi ake sibheke ngokushesha isiqinisekisi esikhulu nesinamandla.

Amathuluzi okuthuthukisa. Isigaba sosizo sendlela yokuhlanganisa izinsiza ezidingekayo kanye ne-kernel yokuhlolwa.

Isiphetho. Ekupheleni kwalesi sihloko, labo abafunda kuze kube manje bazothola amazwi ashukumisayo nencazelo emfushane yalokho okuzokwenzeka ezihlokweni ezilandelayo. Sizophinda sibhale izixhumanisi ezimbalwa zokuzifundela kulabo abangenaso isifiso noma amandla okulinda ukuqhubeka.

Isingeniso se-BPF Architecture

Ngaphambi kokuthi siqale ukucabangela ukwakheka kwe-BPF, sizobhekisela okokugcina (oh) kuyo I-BPF yakudala, eyasungulwa njengempendulo ekufikeni kwemishini ye-RISC futhi yaxazulula inkinga yokuhlunga iphakethe eliphumelelayo. Izakhiwo zavela zaba yimpumelelo kangangokuthi, njengoba yazalwa eminyakeni yamashumi ayisishiyagalolunye e-Berkeley UNIX, yathunyelwa kumasistimu asebenzayo amaningi, yasinda phakathi namashumi amabili eminyaka futhi isathola izinhlelo zokusebenza ezintsha.

I-BPF entsha yathuthukiswa njengempendulo ekutholakaleni kwemishini engama-64-bit, izinsizakalo zamafu kanye nesidingo esikhulayo samathuluzi wokudala i-SDN (Si-offware-defined nukusebenza). Ithuthukiswe onjiniyela benethiwekhi ye-kernel njengendlela ethuthukisiwe esikhundleni se-BPF yakudala, i-BPF entsha ezinyangeni eziyisithupha kamuva yathola izinhlelo zokusebenza emsebenzini onzima wokulandela izinhlelo ze-Linux, futhi manje, eminyakeni eyisithupha ngemuva kokuvela kwayo, sizodinga indatshana elandelayo bhala izinhlobo ezahlukene zezinhlelo.

Izithombe ezihlekisayo

Emgogodleni wayo, i-BPF ingumshini obonakalayo we-sandbox okuvumela ukuthi usebenzise ikhodi β€œengenasizathu” esikhaleni se-kernel ngaphandle kokubeka engcupheni ukuphepha. Izinhlelo ze-BPF zenziwa endaweni yomsebenzisi, zilayishwe ku-kernel, futhi zixhunywe komunye umthombo womcimbi. Umcimbi ungaba, isibonelo, ukulethwa kwephakethe kusixhumi esibonakalayo senethiwekhi, ukwethulwa komsebenzi othile we-kernel, njll. Endabeni yephakheji, uhlelo lwe-BPF luzokwazi ukufinyelela idatha kanye nemethadatha yephakheji (yokufunda futhi, ngokunokwenzeka, ukubhala, kuye ngohlobo lohlelo); esimweni sokuqalisa umsebenzi we-kernel, izimpikiswano ze umsebenzi, okuhlanganisa izikhombisi zenkumbulo ye-kernel, njll.

Ake siyibhekisise le nqubo. Okokuqala, ake sikhulume ngomehluko wokuqala we-BPF yakudala, izinhlelo zazo ezibhalwe ku-assembler. Kule nguqulo entsha, ukwakhiwa kwandiswa ukuze izinhlelo zibhalwe ngezilimi ezisezingeni eliphezulu, ngokuyinhloko, ngokuqinisekile, ku-C. Ngenxa yalokhu, i-backend ye-llvm yathuthukiswa, okuvumela ukuthi ukhiqize i-bytecode ye-architecture ye-BPF.

I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Isakhiwo se-BPF saklanywa, ngokwengxenye, ukuze sisebenze kahle emishinini yesimanje. Ukwenza lokhu kusebenze, i-BPF bytecode, uma isilayishiwe ku-kernel, ihunyushelwa kukhodi yomdabu kusetshenziswa ingxenye ebizwa ngokuthi i-JIT compiler (Ju In Time). Okulandelayo, uma ukhumbula, ku-BPF yakudala uhlelo lwalayishwa ku-kernel futhi lwanamathiselwa kumthombo womcimbi nge-athomu - kumongo wocingo olulodwa lwesistimu. Ekwakhiweni okusha, lokhu kwenzeka ngezigaba ezimbili - okokuqala, ikhodi ilayishwa ku-kernel kusetshenziswa ucingo lwesistimu. bpf(2)bese, kamuva, ngezinye izindlela ezihluka ngokuya ngohlobo lohlelo, uhlelo lunamathisele kumthombo womcimbi.

Lapha umfundi angase abe nombuzo: kwakungenzeka yini? Kuqinisekiswa kanjani ukuphepha kokusetshenziswa kwekhodi enjalo? Ukuphepha kokubulawa kuqinisekisiwe kithi esigabeni sokulayisha izinhlelo ze-BPF ezibizwa ngokuthi i-verifier (ngesiNgisi lesi sigaba sibizwa ngokuthi i-verifier futhi ngizoqhubeka nokusebenzisa igama lesiNgisi):

I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Isiqinisekisi siyisihlaziyi esimile esiqinisekisa ukuthi uhlelo aluphazamisi ukusebenza okuvamile kwe-kernel. Lokhu, ngendlela, akusho ukuthi uhlelo alukwazi ukuphazamisa ukusebenza kohlelo - izinhlelo ze-BPF, kuye ngokuthi hlobo luni, zingakwazi ukufunda futhi zibhale kabusha izingxenye zememori ye-kernel, ukubuyisela amanani emisebenzi, ukunquma, ukufaka, ukubhala kabusha. ngisho namaphakethe enethiwekhi. Isiqinisekisi siqinisekisa ukuthi ukuqalisa uhlelo lwe-BPF ngeke kuphahlazeke i-kernel nokuthi uhlelo, ngokwemithetho, olunokufinyelela kokubhala, isibonelo, idatha yephakethe eliphumayo, ngeke lukwazi ukubhala phezu kwememori ye-kernel ngaphandle kwephakethe. Sizobheka isiqinisekisi ngokuningiliziwe okwengeziwe esigabeni esihambelanayo, ngemva kokujwayelana nazo zonke ezinye izingxenye ze-BPF.

Manje yini esiyifundile kuze kube manje? Umsebenzisi ubhala uhlelo ngo-C, alulayishe ku-kernel esebenzisa ikholi yesistimu bpf(2), lapho ihlolwa yisiqinisekisi bese ihunyushelwa ku-bytecode yomdabu. Bese lowo msebenzisi noma omunye uxhuma uhlelo emthonjeni womcimbi futhi luqala ukuqalisa. Ukuhlukanisa i-boot nokuxhumeka kuyadingeka ngenxa yezizathu eziningana. Okokuqala, ukusebenzisa isiqinisekisi kubiza kakhulu futhi ngokulanda uhlelo olufanayo izikhathi ezimbalwa sichitha isikhathi sekhompyutha. Okwesibili, ukuthi uhlelo luxhunywe kanjani kuncike ohlotsheni lwalo, futhi isikhombimsebenzisi esisodwa β€œsendawo yonke” esakhiwe ngonyaka odlule singase singalungeli izinhlobo ezintsha zezinhlelo. (Nakuba manje i-architecture ikhula kakhulu, kunombono wokuhlanganisa lesi sikhombimsebenzisi ezingeni libbpf.)

Umfundi olalelayo angase aqaphele ukuthi asikaqedi ngezithombe. Impela, konke lokhu okungenhla akuchazi ukuthi kungani i-BPF ishintsha ngokuyisisekelo isithombe uma siqhathaniswa ne-BPF yakudala. Okusha okubili okunweba kakhulu ububanzi bokusebenza yikhono lokusebenzisa inkumbulo eyabiwe nemisebenzi yomsizi we-kernel. Ku-BPF, inkumbulo eyabiwe isetshenziswa kusetshenziswa okuthiwa amamephu - izakhiwo zedatha ezabiwe nge-API ethile. Cishe bathole leli gama ngoba uhlobo lokuqala lwemephu oluzovela kwakuyithebula le-hash. Kwabe sekuvela ama-arrays, amathebula e-hashi wendawo (i-CPU ngayinye) nezinhlu zendawo, izihlahla zokusesha, amamephu aqukethe izinkomba zezinhlelo ze-BPF nokunye okuningi. Okusijabulisayo manje ukuthi izinhlelo ze-BPF manje zinamandla okuphikelela phakathi kwezingcingo futhi sabelane ngazo nezinye izinhlelo kanye nesikhala somsebenzisi.

Amamephu afinyelelwa ezinqubweni zomsebenzisi kusetshenziswa ikholi yesistimu bpf(2), futhi kusukela ezinhlelweni ze-BPF ezisebenza ku-kernel zisebenzisa imisebenzi yomsizi. Ngaphezu kwalokho, abasizi abakhona nje kuphela ukusebenza ngamamephu, kodwa futhi nokufinyelela amanye amakhono e-kernel. Isibonelo, izinhlelo ze-BPF zingasebenzisa imisebenzi yomsizi ukuze udlulisele amaphakethe kwezinye izixhumanisi, ukukhiqiza imicimbi ye-perf, ukufinyelela izakhiwo ze-kernel, njalonjalo.

I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Kafushane, i-BPF inikeza amandla okulayisha ngokunganaki, okungukuthi, ukuhlolwa kokuqinisekisa, ikhodi yomsebenzisi endaweni ye-kernel. Le khodi ingalondoloza isimo phakathi kwamakholi kanye nedatha yokushintshisana ngesikhala somsebenzisi, futhi inokufinyelela kumasistimu angaphansi kwe-kernel avunyelwe yilolu hlobo lohlelo.

Lokhu sekuvele kufana namakhono anikezwe amamojula we-kernel, uma kuqhathaniswa ne-BPF enezinzuzo ezithile (yebo, ungaqhathanisa kuphela izinhlelo zokusebenza ezifanayo, isibonelo, ukulandelela uhlelo - awukwazi ukubhala umshayeli ongekho emthethweni nge-BPF). Ungaqaphela umkhawulo wokungena ophansi (ezinye izinsiza ezisebenzisa i-BPF azidingi ukuthi umsebenzisi abe namakhono okuhlela i-kernel, noma amakhono okuhlela ngokuvamile), ukuphepha kwesikhathi sokusebenza (phakamisa isandla sakho kumazwana walabo abangazange baphule isistimu lapho bebhala noma amamojula okuhlola), i-athomu - kunesikhathi sokuphumula lapho ulayisha kabusha amamojula, futhi isistimu engaphansi ye-BPF iqinisekisa ukuthi azikho izehlakalo ezigejiwe (ukuba ukulunga, lokhu akulona iqiniso kuzo zonke izinhlobo zezinhlelo ze-BPF).

Ukuba khona kwamakhono anjalo kwenza i-BPF ibe yithuluzi lomhlaba wonke lokwandisa i-kernel, eqinisekiswa ekusebenzeni: izinhlobo eziningi zezinhlelo zengezwa ku-BPF, izinkampani ezinkulu kakhulu zisebenzisa i-BPF kumaseva wokulwa 24 Γ— 7, nokuningi nangaphezulu. abaqalayo bakha amabhizinisi abo ezisombululweni ezisuselwe ku-BPF. I-BPF isetshenziswa yonke indawo: ekuvikeleni ekuhlaselweni kwe-DDoS, ukudala i-SDN (isibonelo, ukusebenzisa amanethiwekhi e-kubernetes), njengethuluzi eliyinhloko lokulandelela isistimu kanye nomqoqi wezibalo, kumasistimu okuthola ukungena kokungena kanye nezinhlelo ze-sandbox, njll.

Ake siqedele ukubuka konke kwengxenye yendatshana lapha futhi sibheke umshini obonakalayo kanye ne-ecosystem ye-BPF ngemininingwane eyengeziwe.

Ukwehla: izinsiza

Ukuze ukwazi ukusebenzisa izibonelo ezigabeni ezilandelayo, ungase udinge inani lezinsiza, okungenani llvm/clang ngokusekelwa kwe-bpf kanye bpftool. Esigabeni Amathuluzi Okuthuthukisa Ungafunda imiyalelo yokuhlanganisa izinsiza, kanye ne-kernel yakho. Le ngxenye ibekwe ngezansi ukuze ingaphazamisi ukuvumelana kwesethulo sethu.

Amarejista omshini we-BPF Virtual kanye nohlelo lwemiyalo

I-architecture kanye nohlelo lomyalo lwe-BPF lwathuthukiswa kucatshangelwa iqiniso lokuthi izinhlelo zizobhalwa ngolimi C futhi, ngemva kokulayisha ku-kernel, zihunyushwe kukhodi yomdabu. Ngakho-ke, inani lamarejista kanye nesethi yemiyalo yakhethwa ngeso lokuhlangana, ngomqondo wezibalo, wamakhono emishini yesimanje. Ngaphezu kwalokho, imikhawulo ehlukahlukene yabekwa ezinhlelweni, ngokwesibonelo, kuze kube muva nje kwakungenakwenzeka ukubhala izihibe nama-subroutines, futhi inani lemiyalo lalinqunyelwe ku-4096 (manje izinhlelo ezinelungelo zingalayisha imiyalelo efinyelela kwesigidi).

I-BPF inamarejista angama-64-bit afinyelelekayo ayishumi nanye r0-r10 kanye nekhawunta yohlelo. Bhalisa r10 iqukethe isikhombi sozimele futhi ifundwa kuphela. Izinhlelo zinokufinyelela kusitaki esingu-512-byte ngesikhathi sokusebenza kanye nenani elingenamkhawulo lememori eyabiwe ngendlela yamamephu.

Izinhlelo ze-BPF zivunyelwe ukusebenzisa isethi ethile yabasizi be-kernel yohlelo futhi, kamuva nje, imisebenzi evamile. Umsebenzi ngamunye obizwayo ungathatha izimpikiswano ezinhlanu, eziphasiswe kumarejista r1-r5, futhi inani lokubuyisela lidluliselwe kulo r0. Kuqinisekisiwe ukuthi ngemva kokubuya emsebenzini, okuqukethwe kwamarejista r6-r9 Ngeke kushintshe.

Ukuze uthole ukuhumusha kahle kohlelo, amarejista r0-r11 kuzo zonke izakhiwo ezisekelwayo zidwetshwe ngokuhlukile kumarejista angempela, kucatshangelwa izici ze-ABI zezakhiwo zamanje. Ngokwesibonelo, for x86_64 amarejista r1-r5, esetshenziswa ukudlulisa amapharamitha omsebenzi, ayavezwa rdi, rsi, rdx, rcx, r8, ezisetshenziselwa ukudlulisa amapharamitha ekusebenzeni kwawo x86_64. Isibonelo, ikhodi engakwesokunxele ihumushela kukhodi engakwesokudla kanje:

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

Bhalisa r0 iphinde isetshenziselwe ukubuyisela umphumela wokwenziwa kohlelo, nakurejista r1 uhlelo ludluliswa i-pointer kumongo - kuye ngohlobo lohlelo, lokhu kungaba, isibonelo, isakhiwo struct xdp_md (ye-XDP) noma isakhiwo struct __sk_buff (kwezinhlelo zenethiwekhi ezahlukene) noma isakhiwo struct pt_regs (ngezinhlobo ezahlukene zezinhlelo zokulandelela), njll.

Ngakho-ke, sibe nesethi yamarejista, abasizi be-kernel, isitaki, isikhombisi somongo kanye nenkumbulo eyabiwe ngendlela yamamephu. Akukhona ukuthi konke lokhu kuyadingeka ngempela ohambweni, kodwa...

Masiqhubeke nencazelo futhi sikhulume ngohlelo lomyalo lokusebenza ngalezi zinto. Konke (Cishe bonke) Imiyalo ye-BPF inosayizi omisiwe wamabhithi angu-64. Uma ubheka umyalo owodwa emshinini we-64-bit Big Endian uzobona

I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

kuyinto Code - lokhu ukubhalwa ngekhodi komyalelo, Dst/Src kungumbhalo wekhodi womamukeli nomthombo, ngokulandelana, Off - 16-bit ukuhlehlisa esayiniwe, kanye Imm iyinombolo esayiniwe engamabhithi angu-32 esetshenziswa kweminye imiyalelo (efana ne-cBPF engaguquki K). Ukufaka ikhodi Code inolunye lwezinhlobo ezimbili:

I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Amakilasi eziyalezo 0, 1, 2, 3 achaza imiyalo yokusebenza ngenkumbulo. Bona bayabizwa, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, ngokulandelana. Amakilasi 4, 7 (BPF_ALU, BPF_ALU64) bakha isethi yemiyalelo ye-ALU. Amakilasi 5, 6 (BPF_JMP, BPF_JMP32) aqukethe imiyalelo ye-jump.

Uhlelo olwengeziwe lokufunda uhlelo lwemiyalo ye-BPF lumi kanje: esikhundleni sokubhala ngokucophelela yonke imiyalelo nemingcele yayo, sizobheka izibonelo ezimbalwa kulesi sigaba futhi kuzo kuzocaca ukuthi imiyalelo isebenza kanjani ngempela nokuthi kwenziwa kanjani. qaqa ngesandla noma yiliphi ifayela kanambambili le-BPF. Ukuze sihlanganise okuqukethwe kamuva esihlokweni, sizophinde sihlangane nemiyalelo ngayinye ezigabeni ezimayelana ne-Verifier, i-JIT compiler, ukuhumusha kwe-BPF yakudala, kanye nalapho ufunda amamephu, imisebenzi yokushaya ucingo, njll.

Uma sikhuluma ngemiyalelo ngayinye, sizobhekisela kumafayela ayisisekelo bpf.h ΠΈ bpf_common.h, echaza amakhodi ezinombolo eziyalezo ze-BPF. Lapho ufunda i-architecture uwedwa kanye/noma uhlaziya okubili, ungathola ama-semantics emithonjeni elandelayo, ehlelwe ngokulandelana kobunzima: Imininingwane ye-eBPF engekho emthethweni, I-BPF kanye ne-XDP Reference Guide, Isethi Yeziqondiso, Documentation/networking/filter.txt futhi, vele, kukhodi yomthombo we-Linux - isiqinisekisi, i-JIT, umhumushi we-BPF.

Isibonelo: ukuqaqa i-BPF ekhanda lakho

Ake sibheke isibonelo lapho sihlanganisa khona uhlelo readelf-example.c futhi sibheke kanambambili umphumela. Sizodalula okuqukethwe kwasekuqaleni readelf-example.c ngezansi, ngemva kokubuyisela ingqondo yayo kumakhodi kanambambili:

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

Ikholomu yokuqala kokuphumayo readelf i-indent futhi uhlelo lwethu luqukethe imiyalo emine:

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

Amakhodi womyalo ayalingana b7, 15, b7 ΠΈ 95. Khumbula ukuthi izingcezu ezintathu ezibaluleke kakhulu yisigaba sokufundisa. Esimweni sethu, ingxenye yesine yayo yonke imiyalelo ayinalutho, ngakho-ke amakilasi okufundisa alingana no-7, 5, 7, 5 ngokulandelana. Ikilasi lesi-7 BPF_ALU64, futhi u5 BPF_JMP. Kuwo womabili amakilasi, ifomethi yemiyalelo iyafana (bona ngenhla) futhi singalubhala kabusha uhlelo lwethu kanje (ngasikhathi sinye sizophinda sibhale amakholomu asele ngesimo somuntu):

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

Ukusebenza b class ALU64 Ingabe BPF_MOV. Inikeza inani kurejista yendawo. Uma ibhithi isethiwe s (umthombo), khona-ke inani lithathwa kurejista yomthombo, futhi uma, njengakithi, lingasethiwe, inani lithathwa ensimini. Imm. Ngakho emiyalweni yokuqala neyesithathu senza umsebenzi r0 = Imm. Ngaphezu kwalokho, ukusebenza kwe-JMP class 1 kuyinto BPF_JEQ (gxuma uma ulingana). Esimweni sethu, kusukela kancane S inguziro, iqhathanisa inani lerejista yomthombo nenkambu Imm. Uma amanani ehlangana, khona-ke ukuguquka kwenzeka PC + Offkuphi PC, njengokujwayelekile, iqukethe ikheli lomyalelo olandelayo. Ekugcineni, i-JMP Class 9 Operation is BPF_EXIT. Lo myalelo uvala uhlelo, ubuyela ku-kernel r0. Ake sengeze ikholomu entsha etafuleni lethu:

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

Singakubhala kabusha lokhu ngendlela elula kakhulu:

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

Uma sikhumbula okuserejista r1 uhlelo ludluliswa isikhombi kumongo kusuka ku-kernel, nakurejista r0 inani libuyiselwa ku-kernel, khona-ke singabona ukuthi uma i-pointer yengqikithi inguziro, bese sibuyisela u-1, futhi ngaphandle kwalokho - 2. Ake sihlole ukuthi siqinisile ngokubheka umthombo:

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

Yebo, wuhlelo olungasho lutho, kodwa luhumushela emiyalweni emine nje elula.

Isibonelo esihlukile: imiyalo ye-16-byte

Sishilo ekuqaleni ukuthi eminye imiyalelo ithatha amabhithi angaphezu kuka-64. Lokhu kusebenza, isibonelo, emiyalweni lddw (Ikhodi = 0x18 = BPF_LD | BPF_DW | BPF_IMM) β€” layisha igama eliphindwe kabili elisuka ezindaweni ulifake kurejista Imm. Iqiniso liwukuthi Imm inosayizi ongu-32, futhi igama eliphindwe kabili lingamabhithi angu-64, ngakho ukulayisha inani elisheshayo le-64-bit kurejista kumyalelo owodwa we-64-bit ngeke kusebenze. Ukwenza lokhu, imiyalo emibili eseduze isetshenziswa ukugcina ingxenye yesibili yenani le-64-bit ensimini. Imm. Isibonelo:

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

Kuneziqondiso ezimbili kuphela kuhlelo olunambambili:

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

Sizophinde sihlangane neziyalezo lddw, uma sikhuluma ngokuthuthwa kanye nokusebenza ngamamephu.

Isibonelo: ukuqaqa i-BPF usebenzisa amathuluzi ajwayelekile

Ngakho-ke, sifunde ukufunda amakhodi kanambambili we-BPF futhi silungele ukuncozulula noma yimuphi umyalo uma kunesidingo. Kodwa-ke, kufanelekile ukusho ukuthi ekusebenzeni kulula futhi kuyashesha ukuqaqa izinhlelo usebenzisa amathuluzi ajwayelekile, isibonelo:

$ llvm-objdump -d x64.o

Disassembly of section .text:

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

Umjikelezo wempilo wezinto ze-BPF, uhlelo lwefayela le-bpffs

(Ngiqale ngafunda eminye yemininingwane echazwe kulesi sigatshana okuthunyelwe U-Alexei Starovoitov Ibhulogi ye-BPF.)

Izinto ze-BPF - izinhlelo namamephu - zidalwe endaweni yomsebenzisi kusetshenziswa imiyalo BPF_PROG_LOAD ΠΈ BPF_MAP_CREATE ikholi yesistimu bpf(2), sizokhuluma ngendlela lokhu okwenzeka ngayo esigabeni esilandelayo. Lokhu kudala izakhiwo zedatha ye-kernel futhi ngayinye yazo refcount (isibalo sereferensi) isethelwe kokukodwa, futhi isichazi sefayela esikhomba entweni sibuyiselwa kumsebenzisi. Ngemva kokuba isibambo sivaliwe refcount into iyancipha ngokukodwa, futhi lapho ifinyelela ku-zero, into iyabhujiswa.

Uma uhlelo lusebenzisa amamephu, ke refcount lawa mamephu akhuphuka ngelinye ngemuva kokulayisha uhlelo, i.e. izichazi zefayela zabo zingavalwa kusukela kunqubo yomsebenzisi futhi kumile refcount ngeke ibe nguziro:

I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Ngemva kokulayisha ngempumelelo uhlelo, ngokuvamile silunamathisela ohlotsheni oluthile lwejeneretha yomcimbi. Isibonelo, singayibeka kunethiwekhi yokuxhumana ukuze sicubungule amaphakethe angenayo noma siyixhume kwamanye tracepoint emnyombeni. Kuleli qophelo, ikhawunta yereferensi nayo izokhuphuka ngokukodwa futhi sizokwazi ukuvala isichazi sefayela kuhlelo lwesilayishi.

Kwenzekani uma manje sivala i-bootloader? Kuya ngohlobo lwejeneretha yomcimbi (hook). Zonke izingwegwe zenethiwekhi zizoba khona ngemuva kokuthi isilayishi sesiqediwe, lawa abizwa ngokuthi ama-hook global. Futhi, ngokwesibonelo, izinhlelo zokulandela umkhondo zizokhishwa ngemuva kokuthi inqubo ezakhiwe inqanyuliwe (ngakho-ke zibizwa ngokuthi zendawo, kusukela "kwendawo kuya enqubweni"). Ngobuchwepheshe, izingwegwe zendawo zihlala zinezichazi zefayela ezihambisanayo endaweni yomsebenzisi futhi ngenxa yalokho ziyavala lapho inqubo ivaliwe, kodwa izingwegwe zomhlaba wonke azinawo. Emfanekisweni olandelayo, ngisebenzisa iziphambano ezibomvu, ngizama ukukhombisa ukuthi ukuqedwa kohlelo lwe-loader kuthinta kanjani isikhathi sokuphila sezinto esimweni sezingwegwe zendawo nezomhlaba jikelele.

I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Kungani kunomehluko phakathi kwamahhuku asekhaya nawomhlaba? Ukugijima ezinye izinhlobo zezinhlelo zenethiwekhi kunengqondo ngaphandle kwendawo yomsebenzisi, isibonelo, cabanga ukuvikelwa kwe-DDoS - i-bootloader ibhala imithetho futhi ixhuma uhlelo lwe-BPF ku-interface yenethiwekhi, emva kwalokho i-bootloader ingahamba futhi izibulale. Ngakolunye uhlangothi, cabanga ngohlelo lokulandelela lokususa iphutha olubhale emadolweni akho emizuzwini eyishumi - uma seluqediwe, ungathanda kungabikho udoti osele ohlelweni, futhi izingwegwe zendawo zizoqinisekisa lokho.

Ngakolunye uhlangothi, cabanga ukuthi ufuna ukuxhuma ku-tracepoint ku-kernel futhi uqoqe izibalo eminyakeni eminingi. Kulesi simo, ungafuna ukuqedela ingxenye yomsebenzisi bese ubuyela kuzibalo ngezikhathi ezithile. Isistimu yefayela ye-bpf inikeza leli thuba. Kuwuhlelo lwefayela mbumbulu lwenkumbulo kuphela oluvumela ukwakhiwa kwamafayela abhekisela ezintweni ze-BPF futhi ngaleyo ndlela ande. refcount izinto. Ngemuva kwalokhu, isilayishi singaphuma, futhi izinto ezizidalile zizohlala ziphila.

I-BPF yabancane, ingxenye yokuqala: i-BPF enwetshiwe

Ukudala amafayela ngama-bpff abhekisela kuzinto ze-BPF kubizwa ngokuthi "ukuphina" (njengasemshweni olandelayo: "inqubo ingaphina uhlelo lwe-BPF noma imephu"). Ukudala izinto zefayela lezinto ze-BPF kunengqondo hhayi kuphela ekwandiseni impilo yezinto zasendaweni, kodwa futhi nokusebenziseka kwezinto zomhlaba - sibuyela esibonelweni ngohlelo lokuvikela lwe-DDoS lomhlaba wonke, sifuna ukukwazi ukuza futhi sibheke izibalo. ngezikhathi ezithile.

Isistimu yefayela ye-BPF ivamise ukufakwa phakathi /sys/fs/bpf, kodwa ingafakwa futhi endaweni, isibonelo, kanje:

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

Amagama esistimu yefayela akhiwa kusetshenziswa umyalo BPF_OBJ_PIN Ucingo lwesistimu ye-BPF. Ukufanekisa, ake sithathe uhlelo, siluhlanganise, silulayishe, bese siphinela kulo bpffs. Uhlelo lwethu alwenzi lutho oluwusizo, sethula kuphela ikhodi ukuze ukwazi ukukhiqiza kabusha isibonelo:

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

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

Masihlanganise lolu hlelo futhi sakhe ikhophi yendawo yesistimu yefayela bpffs:

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

Manje ake silande uhlelo lwethu sisebenzisa insiza bpftool bese ubheka izingcingo zesistimu ezihambisana naso bpf(2) (eminye imigqa engabalulekile isusiwe ekuphumeni kwe-strace):

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

Lapha silayishe uhlelo sisebenzisa BPF_PROG_LOAD, ithole isichazi sefayela ku-kernel 3 nokusebenzisa umyalo BPF_OBJ_PIN uphine lesi sichazi sefayela njengefayela "bpf-mountpoint/test". Ngemva kwalokhu uhlelo lwe-bootloader bpftool siqedile ukusebenza, kodwa uhlelo lwethu lwahlala ku-kernel, nakuba singazange silinamathisele kunoma iyiphi i-interface yenethiwekhi:

$ 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

Singasusa into yefayela ngokujwayelekile unlink(2) futhi ngemva kwalokho uhlelo oluhambisanayo luzosuswa:

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

Isusa izinto

Ekhuluma ngokususa izinto, kuyadingeka ukucacisa ukuthi ngemuva kokunqamula uhlelo ku-hook (ijeneretha yomcimbi), akukho nowodwa umcimbi omusha ozoqala ukwethulwa, noma kunjalo, zonke izimo zamanje zohlelo zizoqedwa ngendlela evamile. .

Ezinye izinhlobo zezinhlelo ze-BPF zikuvumela ukuthi umiselele uhlelo ngokuphazima kweso, i.e. hlinzeka nge-athomu yokulandelana replace = detach old program, attach new program. Kulokhu, zonke izenzakalo ezisebenzayo zenguqulo endala yohlelo zizoqeda umsebenzi wazo, futhi izibambi zomcimbi ezintsha zizodalwa kusukela kuhlelo olusha, futhi β€œi-atomicity” lapha isho ukuthi awukho umcimbi ozogejwa.

Ukunamathisela izinhlelo emithonjeni yomcimbi

Kulesi sihloko, ngeke sichaze ngokuhlukana izinhlelo zokuxhuma emithonjeni yomcimbi, ngoba kunengqondo ukufunda lokhu kumongo wohlobo oluthile lohlelo. Cm. isibonelo ngezansi, lapho sibonisa khona ukuthi izinhlelo ezifana ne-XDP zixhumeke kanjani.

Ukuphatha Izinto Ngokusebenzisa Ucingo Lwesistimu lwe-bpf

Izinhlelo ze-BPF

Zonke izinto ze-BPF zidalwa futhi ziphathwa endaweni yomsebenzisi kusetshenziswa ikholi yesistimu bpf, enale prototype elandelayo:

#include <linux/bpf.h>

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

Nali iqembu cmd ingenye yamanani ohlobo enum bpf_cmd, attr β€” i-pointer kumapharamitha wohlelo oluthile kanye size - usayizi wento ngokwesikhombi, i.e. ngokuvamile lokhu sizeof(*attr). Ku-kernel 5.8 ikholi yesistimu bpf isekela imiyalo ehlukene engama-34, futhi nencazelo union bpf_attr ithatha imigqa engama-200. Kodwa akufanele kusatshiswe yilokhu, ngoba sizobe sizijwayeza imiyalo nemingcele phakathi nezihloko ezimbalwa.

Ake siqale ngeqembu BPF_PROG_LOAD, edala izinhlelo ze-BPF - ithatha isethi yemiyalelo ye-BPF futhi ilayishe ku-kernel. Ngesikhathi sokulayisha, isiqinisekisi siyethulwa, bese kuba i-JIT compiler futhi, ngemva kokwenza ngempumelelo, isichazi sefayela lohlelo sibuyiselwa kumsebenzisi. Sibonile ukuthi kwenzekani kuye ngokulandelayo esigabeni esandulele mayelana nomjikelezo wempilo yezinto ze-BPF.

Manje sizobhala uhlelo lwangokwezifiso oluzolayisha uhlelo olulula lwe-BPF, kodwa okokuqala sidinga ukunquma ukuthi hlobo luni lohlelo esifuna ukululayisha - kuzodingeka sikhethe thayipha futhi ngaphakathi kohlaka lwalolu hlobo, bhala uhlelo oluzophumelela ukuhlolwa kwesiqinisekisi. Kodwa-ke, ukuze kungabi nzima inqubo, nasi isisombululo esenziwe ngomumo: sizothatha uhlelo olufana nalo BPF_PROG_TYPE_XDP, okuzobuyisela inani XDP_PASS (yeqa wonke amaphakheji). Ku-assembler ye-BPF kubonakala kulula kakhulu:

r0 = 2
exit

Ngemva kokuba sesinqumile lokho sizolayisha, singakutshela ukuthi sizokwenza kanjani:

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

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

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

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

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

    for ( ;; )
        pause();
}

Imicimbi ethokozisayo kuhlelo iqala ngencazelo yamalungu afanayo insns - Uhlelo lwethu lwe-BPF ngekhodi yomshini. Kulokhu, imiyalelo ngayinye yohlelo lwe-BPF igcwele esakhiweni bpf_insn. Isici sokuqala insns ihambisana nemiyalelo r0 = 2, owesibili - exit.

Hlehla. I-kernel ichaza ama-macros alula kakhulu wokubhala amakhodi omshini, nokusebenzisa ifayela lesihloko se-kernel tools/include/linux/filter.h singabhala

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

Kodwa njengoba ukubhala izinhlelo ze-BPF ngekhodi yomdabu kudingekile kuphela ekubhaleni izivivinyo ku-kernel nezindatshana ezimayelana ne-BPF, ukungabi khona kwala ma-macro akubeki inkimbinkimbi ngempela impilo yonjiniyela.

Ngemva kokuchaza uhlelo lwe-BPF, siqhubekela phambili ekulayisheni ku-kernel. Isethi yethu yamapharamitha amancane attr ihlanganisa uhlobo lohlelo, isethi nenombolo yemiyalelo, ilayisense edingekayo, negama "woo", esiyisebenzisayo ukuthola uhlelo lwethu ohlelweni ngemva kokulanda. Uhlelo, njengoba luthenjisiwe, lulayishwa ohlelweni kusetshenziswa ikholi yesistimu bpf.

Ekupheleni kohlelo sigcina sesiku-loop engapheli elingisa ukukhokhelwa. Ngaphandle kwalo, uhlelo luzobulawa i-kernel lapho isichazi sefayela esibuyiselwe ucingo lwesistimu kithi sivaliwe. bpf, futhi ngeke sikubone ohlelweni.

Hhayi-ke, sesilungele ukuhlolwa. Asihlanganise futhi siqhube uhlelo ngaphansi straceukuhlola ukuthi yonke into isebenza ngendlela okufanele:

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

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

Konke kuhamba kahle, bpf(2) wabuyisela isibambo esingu-3 kithi futhi sangena ku-loop engapheli nge pause(). Ake sizame ukuthola uhlelo lwethu ohlelweni. Ukuze senze lokhu sizoya kwenye i-terminal futhi sisebenzise insiza bpftool:

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

Siyabona ukuthi kunohlelo olulayishiwe ohlelweni woo I-ID yakhe yomhlaba wonke ingu-390 futhi isaqhubeka simple-prog kukhona isichazi sefayela esivulekile esikhomba uhlelo (futhi uma simple-prog uzoqeda umsebenzi ke woo izonyamalala). Njengoba bekulindelekile, uhlelo woo ithatha amabhayithi angu-16 - imiyalelo emibili - yamakhodi kanambambili ekwakhiweni kwe-BPF, kodwa ngesimo sayo somdabu (x86_64) isivele ingamabhayithi angu-40. Ake sibheke uhlelo lwethu ngendlela yalo yokuqala:

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

akukho okumangalisayo. Manje ake sibheke ikhodi ekhiqizwe i-JIT compiler:

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

ayisebenzi kahle kakhulu exit(2), kodwa ngokungenzeleli, uhlelo lwethu lulula kakhulu, futhi ezinhlelweni ezingasho lutho isandulela kanye nesiqephu esengezwe umdidiyeli we-JIT, yiqiniso, siyadingeka.

Amamephu

Izinhlelo ze-BPF zingasebenzisa izindawo zememori ezihlelekile ezifinyeleleka kokubili kwezinye izinhlelo ze-BPF nasezinhlelweni ezisesikhaleni somsebenzisi. Lezi zinto zibizwa ngokuthi amamephu futhi kulesi sigaba sizobonisa ukuthi ziphathwa kanjani kusetshenziswa ucingo lwesistimu bpf.

Masithi khona manjalo amandla wamamephu awagcini nje ngokufinyelela kumemori eyabiwe. Kunamamephu anezinjongo ezikhethekile aqukethe, ngokwesibonelo, izikhombi zezinhlelo ze-BPF noma izikhombi eziya endaweni yokusebenzelana yenethiwekhi, amamephu okusebenza ngemicimbi ye-perf, njll. Ngeke sikhulume ngazo lapha, ukuze singaphambanisi umfundi. Ngaphandle kwalokhu, siziba izindaba zokuvumelanisa, njengoba lokhu akubalulekile ezibonelweni zethu. Uhlu oluphelele lwezinhlobo zemephu ezitholakalayo lungatholakala ku <linux/bpf.h>, futhi kulesi sigaba sizothatha njengesibonelo uhlobo lokuqala ngokomlando, ithebula le-hashi BPF_MAP_TYPE_HASH.

Uma udala ithebula le-hash phakathi, ithi, C++, ungasho unordered_map<int,long> woo, okusho ukuthi ngesiRashiya β€œNgidinga itafula woo usayizi ongenamkhawulo, okhiye bayo bawuhlobo int, futhi amanani awuhlobo long" Ukuze sakhe ithebula le-BPF hashi, sidinga ukwenza into efanayo, ngaphandle kokuthi kufanele sicacise usayizi omkhulu wetafula, futhi esikhundleni sokucacisa izinhlobo zokhiye namanani, sidinga ukucacisa osayizi babo ngamabhayithi. . Ukwakha amamephu sebenzisa umyalo BPF_MAP_CREATE ikholi yesistimu bpf. Ake sibheke uhlelo oluncane kakhulu noma oluncane olwakha imephu. Ngemuva kohlelo lwangaphambilini olulayisha izinhlelo ze-BPF, lolu kufanele lubonakale lulula kuwe:

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

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

    for ( ;; )
        pause();
}

Lapha sichaza isethi yamapharamitha attr, lapho sithi β€œNgidinga ithebula le-hashi elinokhiye namanani kasayizi sizeof(int), lapho ngingafaka khona ubuningi bezakhi ezine." Lapho udala amamephu e-BPF, ungacacisa amanye amapharamitha, ngokwesibonelo, ngendlela efanayo naleyo esibonelweni sohlelo, sicacise igama lento njenge "woo".

Masihlanganise futhi siqalise uhlelo:

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

Nansi ikholi yesistimu bpf(2) usibuyisele inombolo yemephu esichazayo 3 bese uhlelo, njengoba kulindelekile, lulinde eminye imiyalelo ocingweni lwesistimu pause(2).

Manje ake sithumele uhlelo lwethu ngemuva noma sivule enye i-terminal futhi sibheke into yethu sisebenzisa insiza bpftool (singahlukanisa imephu yethu kwamanye ngamagama ayo):

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

Inombolo 114 iyi-ID yomhlaba wonke yento yethu. Noma yiluphi uhlelo kusistimu lungasebenzisa le ID ukuvula imephu ekhona kusetshenziswa umyalo BPF_MAP_GET_FD_BY_ID ikholi yesistimu bpf.

Manje singadlala ngetafula lethu le-hash. Ake sibheke ekuqukethe:

$ sudo bpftool map dump id 114
Found 0 elements

Akunalutho. Ake sibeke inani kuyo hash[1] = 1:

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

Ake sibheke itafula futhi:

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

Hooray! Sikwazile ukwengeza isici esisodwa. Qaphela ukuthi kufanele sisebenze ku-byte level ukwenza lokhu, kusukela bptftool awazi ukuthi hlobo luni amanani kuthebula le-hashi. (Lolu lwazi lungadluliselwa kuye kusetshenziswa i-BTF, kodwa okwengeziwe ngalokho manje.)

Ngabe i-bpftool ifunda futhi yengeza kanjani izakhi? Ake sibheke ngaphansi kwe-hood:

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

Okokuqala sivule imephu nge-ID yayo yomhlaba wonke sisebenzisa umyalo BPF_MAP_GET_FD_BY_ID ΠΈ bpf(2) ibuyisele isichazi 3 kithi. Ngokuqhubeka nokusebenzisa umyalo BPF_MAP_GET_NEXT_KEY sithole ukhiye wokuqala etafuleni ngokudlula NULL njengesikhombi kukhiye "odlule". Uma sinokhiye singenza BPF_MAP_LOOKUP_ELEMokubuyisela inani kusikhombisi value. Isinyathelo esilandelayo sizama ukuthola isici esilandelayo ngokudlulisela i-pointer kukhiye wamanje, kodwa ithebula lethu liqukethe into eyodwa kanye nomyalo. BPF_MAP_GET_NEXT_KEY izimbuyiselo ENOENT.

Kulungile, asiguqule inani ngokhiye 1, ake sithi ukucabanga kwebhizinisi lethu kudinga ukubhaliswa hash[1] = 2:

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

Njengoba kulindelekile, kulula kakhulu: umyalo BPF_MAP_GET_FD_BY_ID ivula imephu yethu nge-ID, kanye nomyalo BPF_MAP_UPDATE_ELEM ibhala phezu kwesici.

Ngakho-ke, ngemva kokudala ithebula le-hash ohlelweni olulodwa, singakwazi ukufunda nokubhala okuqukethwe kulo kusuka kwenye. Qaphela ukuthi uma sikwazile ukwenza lokhu kusukela kulayini womyalo, khona-ke noma yiluphi olunye uhlelo ohlelweni lungakwenza. Ngaphezu kwemiyalelo echazwe ngenhla, yokusebenza ngamamephu avela endaweni yomsebenzisi, okulandelayo:

  • BPF_MAP_LOOKUP_ELEM: thola inani ngokhiye
  • BPF_MAP_UPDATE_ELEM: buyekeza/dala inani
  • BPF_MAP_DELETE_ELEM: khipha ukhiye
  • BPF_MAP_GET_NEXT_KEY: thola ukhiye olandelayo (noma wokuqala).
  • BPF_MAP_GET_NEXT_ID: ikuvumela ukuthi udlule kuwo wonke amamephu akhona, yindlela esebenza ngayo bpftool map
  • BPF_MAP_GET_FD_BY_ID: vula imephu ekhona nge-ID yayo yomhlaba wonke
  • BPF_MAP_LOOKUP_AND_DELETE_ELEM: buyekeza nge-athomu inani lento bese ubuyisela endala
  • BPF_MAP_FREEZE: yenza imephu ingaguquleki endaweni yomsebenzisi (lo msebenzi awukwazi ukuhlehliswa)
  • BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, BPF_MAP_UPDATE_BATCH, BPF_MAP_DELETE_BATCH: imisebenzi eminingi. Ngokwesibonelo, BPF_MAP_LOOKUP_AND_DELETE_BATCH - lena ukuphela kwendlela ethembekile yokufunda nokusetha kabusha wonke amanani asuka kumephu

Akuyona yonke le miyalo esebenza kuzo zonke izinhlobo zamamephu, kodwa ngokuvamile ukusebenza nezinye izinhlobo zamamephu avela endaweni yomsebenzisi kubukeka kufana ncamashi nokusebenza ngamathebula e-hashi.

Ngenxa yokuhleleka, masiqedele ukuhlolwa kwethu kwetafula le-hashi. Khumbula ukuthi sidale ithebula elingaqukatha okhiye abane? Ake sengeze ezinye izici ezimbalwa:

$ 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

Kuze kube manje kuhle kakhulu:

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

Ake sizame ukwengeza eyodwa futhi:

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

Njengoba bekulindelekile, asiphumelelanga. Ake sibheke iphutha ngokuningiliziwe:

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

Konke kuhamba kahle: njengoba bekulindelekile, iqembu BPF_MAP_UPDATE_ELEM izama ukudala ukhiye omusha, wesihlanu, kodwa iyaphahlazeka E2BIG.

Ngakho-ke, singakha futhi silayishe izinhlelo ze-BPF, futhi sidale futhi siphathe amamephu sisendaweni yomsebenzisi. Manje kunengqondo ukubheka ukuthi singasebenzisa kanjani amamephu avela ezinhlelweni ze-BPF ngokwazo. Singakhuluma ngalokhu ngolimi lwezinhlelo okunzima ukuzifunda kumakhodi amakhulu emishini, kodwa empeleni isikhathi sesifikile sokukhombisa ukuthi izinhlelo ze-BPF zibhalwa futhi zigcinwe kanjani - kusetshenziswa. libbpf.

(Kubafundi abanganelisekile ngokuntuleka kwesibonelo esisezingeni eliphansi: sizohlaziya ngokuningiliziwe izinhlelo ezisebenzisa amamephu nemisebenzi yomsizi edalwe kusetshenziswa. libbpf futhi ngikutshele ukuthi kwenzekani ezingeni lemiyalo. Kubafundi abanganelisekile kakhulu, sengeze isibonelo endaweni efanele esihlokweni.)

Ukubhala izinhlelo ze-BPF usebenzisa i-libbpf

Ukubhala izinhlelo ze-BPF usebenzisa amakhodi omshini kungathakazelisa okokuqala ngqa, bese kungena ukusutha. Kulo mzuzu udinga ukunaka kwakho llvm, ene-backend yokukhiqiza ikhodi yezakhiwo ze-BPF, kanye nomtapo wolwazi libbpf, okukuvumela ukuthi ubhale uhlangothi lomsebenzisi lwezinhlelo zokusebenza ze-BPF futhi ulayishe ikhodi yezinhlelo ze-BPF ezikhiqizwe kusetshenziswa llvm/clang.

Eqinisweni, njengoba sizobona kulesi sihloko nakwelandelayo, libbpf yenza umsebenzi omningi ngaphandle kwayo (noma amathuluzi afanayo - iproute2, libbcc, libbpf-go, njll.) akunakwenzeka ukuphila. Esinye sezici ezibulalayo zephrojekthi libbpf yi-BPF CO-RE (Compile Kanye, Run Everywhere) - iphrojekthi ekuvumela ukuthi ubhale izinhlelo ze-BPF eziphathwayo kusuka ku-kernel eyodwa kuya kwenye, ezinekhono lokusebenzisa ama-API ahlukene (isibonelo, lapho ukwakheka kwe-kernel kushintsha kusuka enguqulweni kuya kunguqulo). Ukuze ukwazi ukusebenza ne-CO-RE, i-kernel yakho kufanele ihlanganiswe nokusekelwa kwe-BTF (sichaza ukuthi ungakwenza kanjani lokhu esigabeni Amathuluzi Okuthuthukisa. Ungahlola ukuthi i-kernel yakho yakhiwe nge-BTF noma cha kalula - ngokuba khona kwefayela elilandelayo:

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

Leli fayela ligcina ulwazi olumayelana nazo zonke izinhlobo zedatha ezisetshenziswa ku-kernel futhi lisetshenziswa kuzo zonke izibonelo zethu kusetshenziswa libbpf. Sizokhuluma ngokuningiliziwe mayelana ne-CO-RE esihlokweni esilandelayo, kodwa kulesi - vele uzakhele i-kernel CONFIG_DEBUG_INFO_BTF.

umtapo libbpf uhlala ngqo ohlwini lwemibhalo tools/lib/bpf I-kernel kanye nokuthuthukiswa kwayo kwenziwa ngohlu lwamakheli [email protected]. Kodwa-ke, indawo yokugcina ehlukile iyagcinwa ngezidingo zezicelo ezihlala ngaphandle kwe-kernel https://github.com/libbpf/libbpf lapho umtapo wezincwadi we-kernel ufanekiswa khona ukuze ufinyelele ukufunda okuningi noma ngaphansi njengoba kunjalo.

Kulesi sigaba sizobheka ukuthi ungakha kanjani iphrojekthi esebenzisa libbpf, ake sibhale izinhlelo zokuhlola ezimbalwa (eziningi noma ezingasho lutho) futhi sihlaziye ngokuningiliziwe ukuthi konke kusebenza kanjani. Lokhu kuzosivumela ukuthi sichaze kalula ezigabeni ezilandelayo ukuthi izinhlelo ze-BPF zisebenzisana kanjani namamephu, abasizi be-kernel, i-BTF, njll.

Ngokujwayelekile amaphrojekthi asetshenziswa libbpf engeza inqolobane ye-GitHub njenge-submodule ye-git, sizokwenza okufanayo:

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

Iya ku libbpf silula:

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

Uhlelo lwethu olulandelayo kulesi sigaba lumi kanje: sizobhala uhlelo lwe-BPF njenge BPF_PROG_TYPE_XDP, okufanayo nakwesibonelo sangaphambilini, kodwa ku-C, siyihlanganisa sisebenzisa clang, bese ubhala uhlelo lomsizi oluzoyilayisha ku-kernel. Ezigabeni ezilandelayo sizonweba amandla akho kokubili uhlelo lwe-BPF kanye nohlelo lomsizi.

Isibonelo: ukudala uhlelo lokusebenza olugcwele usebenzisa i-libbpf

Ukuqala, sisebenzisa ifayela /sys/kernel/btf/vmlinux, okukhulunywe ngakho ngenhla, futhi adale okulingana nayo ngendlela yefayela elingasekhanda:

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

Leli fayela lizogcina zonke izakhiwo zedatha ezitholakala ku-kernel yethu, isibonelo, le yindlela unhlokweni we-IPv4 ochazwa ngayo ku-kernel:

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

Manje sizobhala uhlelo lwethu lwe-BPF ngo-C:

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

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

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

Nakuba uhlelo lwethu lube lula kakhulu, sisadinga ukunaka imininingwane eminingi. Okokuqala, ifayela lokuqala likanhlokweni esilifakayo lithi vmlinux.h, esisanda kuyenza sisebenzisa bpftool btf dump - manje asidingi ukufaka iphakheji ye-kernel-headers ukuze sithole ukuthi izakhiwo ze-kernel zibukeka kanjani. Ifayela elingunhlokweni elilandelayo liza kithi livela kulabhulali libbpf. Manje siyidinga kuphela ukuchaza i-macro SEC, okuthumela uhlamvu esigabeni esifanele sefayela lento ye-ELF. Uhlelo lwethu luqukethwe esigabeni xdp/simple, lapho ngaphambi kwe-slash sichaza uhlobo lohlelo lwe-BPF - lena yingqungquthela esetshenziswa ku libbpf, ngokusekelwe egameni lesigaba izoshintsha uhlobo olulungile ekuqaleni bpf(2). Uhlelo lwe-BPF ngokwalo C - ilula kakhulu futhi iqukethe umugqa owodwa return XDP_PASS. Ekugcineni, isigaba esihlukile "license" iqukethe igama lelayisensi.

Singahlanganisa uhlelo lwethu sisebenzisa i-llvm/clang, inguqulo >= 10.0.0, noma okungcono nokho, okukhulu nakakhulu (bona isigaba Amathuluzi Okuthuthukisa):

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

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

Phakathi kwezici ezithakazelisayo: sibonisa isakhiwo esihlosiwe -target bpf kanye nendlela eya kumaheda libbpf, esisanda kuyifaka. Futhi, ungakhohlwa mayelana -O2, ngaphandle kwale nketho ungase ube nezimanga esikhathini esizayo. Ake sibheke ikhodi yethu, sikwazile ukubhala uhlelo ebesilufuna?

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

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

Disassembly of section xdp/simple:

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

Yebo, kwasebenza! Manje, sinefayela kanambambili nohlelo, futhi sifuna ukwakha uhlelo lokusebenza oluzoyilayisha ku-kernel. Ngale njongo umtapo wolwazi libbpf isinika izinketho ezimbili - sebenzisa i-API yezinga eliphansi noma i-API yezinga eliphezulu. Sizohamba ngendlela yesibili, njengoba sifuna ukufunda ukubhala, ukulayisha nokuxhuma izinhlelo ze-BPF ngomzamo omncane wokufunda kwazo okwalandela.

Okokuqala, sidinga ukukhiqiza "uhlaka lwamathambo" lohlelo lwethu kusuka kanambambili walo sisebenzisa insiza efanayo bpftool - ummese waseSwitzerland womhlaba we-BPF (ongathathwa njengoba unjalo, njengoba uDaniel Borkman, omunye wabadali nabanakekeli be-BPF, engumSwitzerland):

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

Kufayela xdp-simple.skel.h iqukethe ikhodi kanambambili yohlelo lwethu nemisebenzi yokuphatha - ukulayisha, ukunamathisela, ukususa into yethu. Esimeni sethu esilula lokhu kubukeka njengokweqile, kodwa futhi kusebenza esimweni lapho ifayela lezinto liqukethe izinhlelo eziningi ze-BPF namamephu futhi ukulayisha le ELF enkulu sidinga nje ukukhiqiza uhlaka lwamathambo futhi sibize umsebenzi owodwa noma emibili kusuka kuhlelo lokusebenza lwangokwezifiso esinalo. bayabhala Asiqhubeke manje.

Uma sikhuluma nje, uhlelo lwethu lokulayishwa luyinto encane:

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

kuyinto struct xdp_simple_bpf kuchazwe kufayela xdp-simple.skel.h futhi ichaza ifayela lethu lezinto:

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

Singabona ukulandelana kwe-API yezinga eliphansi lapha: isakhiwo struct bpf_program *simple ΠΈ struct bpf_link *simple. Isakhiwo sokuqala sichaza ngokuqondile uhlelo lwethu, olubhalwe esigabeni xdp/simple, bese eyesibili ichaza ukuthi uhlelo luxhumeka kanjani kumthombo womcimbi.

Umsebenzi xdp_simple_bpf__open_and_load, ivula into ye-ELF, iyihlukanise, idale zonke izakhiwo nezigatshana (ngaphandle kohlelo, i-ELF iqukethe nezinye izigaba - idatha, idatha yokufunda kuphela, ulwazi lokulungisa iphutha, ilayisensi, njll.), bese ilayisha ku-kernel usebenzisa uhlelo. shayela bpf, esingakuhlola ngokuhlanganisa nokusebenzisa uhlelo:

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

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

Manje ake sibheke uhlelo lwethu sisebenzisa bpftool. Masithole i-ID yakhe:

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

futhi silahle (sisebenzisa ifomu elifushanisiwe lomyalo bpftool prog dump xlated):

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

Okuthile okusha! Uhlelo luphrinte izingcezu zefayela lethu elingumthombo C. Lokhu kwenziwa umtapo wolwazi libbpf, ethole isigaba sokususa iphutha kukhombambili, yasihlanganisa entweni ye-BTF, yasilayisha ku-kernel isebenzisa BPF_BTF_LOAD, bese icacisa isichazi sefayela esiwumphumela lapho silayisha uhlelo ngomyalo BPG_PROG_LOAD.

Abasizi beKernel

Izinhlelo ze-BPF zingasebenzisa imisebenzi β€œyangaphandle” - abasizi be-kernel. Le misebenzi yomsizi ivumela izinhlelo ze-BPF ukuthi zifinyelele izakhiwo ze-kernel, zilawule amamephu, futhi zixhumane "nomhlaba wangempela" - dala imicimbi ye-perf, lawula izingxenyekazi zekhompuyutha (isibonelo, ukuqondisa kabusha amaphakethe), njll.

Isibonelo: bpf_get_smp_processor_id

Ngaphakathi kohlaka lwepharadigm "yokufunda ngesibonelo", ake sicabangele omunye wemisebenzi yomsizi, bpf_get_smp_processor_id(), ezithile kufayela kernel/bpf/helpers.c. Ibuyisela inombolo yephrosesa lapho uhlelo lwe-BPF oluyibizile lusebenza khona. Kepha asinantshisekelo kuma-semantics ayo njengaseqinisweni lokuthi ukusetshenziswa kwayo kuthatha umugqa owodwa:

BPF_CALL_0(bpf_get_smp_processor_id)
{
    return smp_processor_id();
}

Izincazelo zomsebenzi womsizi we-BPF ziyefana nezincazelo zekholi yesistimu ye-Linux. Lapha, isibonelo, umsebenzi uchazwa ongenakho ukuphikisana. (Umsebenzi othatha, uthi, izimpikiswano ezintathu zichazwa kusetshenziswa i-macro BPF_CALL_3. Inombolo enkulu yezimpikiswano ezinhlanu.) Nokho, lena ingxenye yokuqala kuphela yencazelo. Ingxenye yesibili iwukuchaza uhlobo lwesakhiwo struct bpf_func_proto, equkethe incazelo yomsebenzi womsizi oqondwa isiqinisekisi:

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

Ukubhalisa Imisebenzi Yomsizi

Ukuze izinhlelo ze-BPF zohlobo oluthile zisebenzise lo msebenzi, kufanele ziwubhalise, isibonelo ngohlobo BPF_PROG_TYPE_XDP umsebenzi uchazwa ku-kernel xdp_func_proto, enquma kusukela ku-ID yomsebenzi womsizi ukuthi i-XDP iyawusekela yini lo msebenzi noma cha. Umsebenzi wethu isekela:

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

Izinhlobo zohlelo olusha lwe-BPF "ziyachazwa" kufayela include/linux/bpf_types.h usebenzisa i-macro BPF_PROG_TYPE. Ichazwa ngezingcaphuno ngenxa yokuthi iyincazelo enengqondo, futhi ngolimi C incazelo yeqoqo lonke lezakhiwo eziphathekayo yenzeka kwezinye izindawo. Ikakhulukazi, kufayela kernel/bpf/verifier.c zonke izincazelo ezivela kufayela bpf_types.h zisetshenziselwa ukwakha uxhaxha lwezakhiwo bpf_verifier_ops[]:

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

Okusho ukuthi, kuhlobo ngalunye lohlelo lwe-BPF, kuchazwa isikhombi esakhiweni sedatha sohlobo struct bpf_verifier_ops, eqaliswa ngevelu _name ## _verifier_ops, i.e., xdp_verifier_ops ngoba xdp. Isakhiwo xdp_verifier_ops ezimisele kufayela net/core/filter.c kanje:

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

Lapha sibona umsebenzi wethu esiwujwayele xdp_func_proto, ezosebenzisa isiqinisekisi njalo lapho ihlangabezana nenselelo abanye isebenza ngaphakathi kohlelo lwe-BPF, bheka verifier.c.

Ake sibheke ukuthi uhlelo lwe-BPF lokucabanga lusebenzisa kanjani umsebenzi bpf_get_smp_processor_id. Ukwenza lokhu, sibhala kabusha uhlelo kusuka esigabeni sethu sangaphambilini ngendlela elandelayo:

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

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

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

Π‘ΠΈΠΌΠ²ΠΎΠ» bpf_get_smp_processor_id ezimisele Π² <bpf/bpf_helper_defs.h> imitapo yolwazi libbpf kanjani

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

leyo, bpf_get_smp_processor_id iyisikhombi somsebenzi esinani laso lingu-8, lapho u-8 eyinani BPF_FUNC_get_smp_processor_id thayipha enum bpf_fun_id, esichazelwe thina kufayela vmlinux.h (ifayela bpf_helper_defs.h ku-kernel kukhiqizwa umbhalo, ngakho izinombolo "zomlingo" zilungile). Lo msebenzi awuzithathi izimpikiswano futhi ubuyisela inani lohlobo __u32. Uma siyiqhuba ohlelweni lwethu, clang yakha umyalelo BPF_CALL "uhlobo olulungile" Ake sihlanganise uhlelo futhi sibheke ingxenye xdp/simple:

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

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

Disassembly of section xdp/simple:

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

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

Emgqeni wokuqala sibona imiyalelo call, ipharamitha IMM elilingana no-8, futhi SRC_REG -ziro. Ngokwesivumelwano se-ABI esisetshenziswa isiqinisekisi, lolu wucingo oluya kunombolo yesishiyagalombili yomsebenzi womsizi. Uma seyethuliwe, i-logic ilula. Buyisela inani elivela kurejista r0 ikopishelwe ku r1 futhi emigqeni 2,3 iguqulwa ibe uhlobo u32 - amabhithi aphezulu angama-32 asuliwe. Elayini 4,5,6,7 sibuyisela 2 (XDP_PASS) noma 1 (XDP_DROP) kuye ngokuthi umsebenzi womsizi osuka kulayini 0 ubuyise inani elinguziro noma elingelona uziro.

Ake sizihlole: layisha uhlelo futhi sibheke okukhiphayo 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

Kulungile, isiqinisekisi sithole umsizi we-kernel olungile.

Isibonelo: ukudlulisa izimpikiswano futhi ekugcineni uqhuba uhlelo!

Yonke imisebenzi yomsizi weleveli yokuqalisa ine-prototype

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

Amapharamitha emisebenzi yomsizi adluliswa kumarejista r1-r5, futhi inani libuyiselwa kurejista r0. Ayikho imisebenzi ethatha ama-agumenti angaphezu kwesihlanu, futhi ukusekelwa kwawo akulindelekile ukuthi kwengezwe ngokuzayo.

Ake sibheke umsizi omusha we-kernel nokuthi i-BPF idlula kanjani amapharamitha. Masibhale kabusha xdp-simple.bpf.c kanje (eminye imigqa ayishintshile):

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

Uhlelo lwethu luphrinta inombolo ye-CPU olusebenza kuyo. Masiyihlanganise futhi sibheke ikhodi:

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

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

Emgqeni 0-7 sibhala intambo running on CPU%un, bese kuthi emgqeni wesi-8 sisebenzise esijwayelekile bpf_get_smp_processor_id. Emgqeni 9-12 silungiselela izimpikiswano zomsizi bpf_printk - amarejista r1, r2, r3. Kungani bebathathu hhayi ababili? Ngoba bpf_printklokhu kuyi-macro wrapper ezungeze umsizi wangempela bpf_trace_printk, okudingeka kudlule usayizi weyunithi yezinhlamvu yefomethi.

Manje ake sengeze imigqa embalwa kuyo xdp-simple.cukuze uhlelo lwethu luxhume esibonakalayo lo futhi ngempela waqala!

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

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

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

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

cleanup:
    xdp_simple_bpf__destroy(obj);
}

Lapha sisebenzisa umsebenzi bpf_set_link_xdp_fd, exhuma izinhlelo ze-BPF zohlobo lwe-XDP kuzixhumi zenethiwekhi. Sifake ikhodi yesixhumi esibonakalayo lo, okuhlala kungu-1. Sisebenzisa umsebenzi kabili ukuze siqale sikhiphe uhlelo oludala uma lunamathiselwe. Qaphela ukuthi manje asiyidingi inselelo pause noma iluphu engapheli: uhlelo lwethu lokulayishwa luzophuma, kodwa uhlelo lwe-BPF ngeke lubulawe njengoba luxhunywe kumthombo womcimbi. Ngemuva kokulanda ngempumelelo nokuxhumeka, uhlelo luzokwethulwa kuphakethe lenethiwekhi ngalinye elifika kulo lo.

Ake silande uhlelo futhi sibheke esibonakalayo 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

Uhlelo esiludawunilodayo luno-ID 669 futhi sibona i-ID efanayo kusixhumi esibonakalayo lo. Sizothumela amaphakheji ambalwa kuwo 127.0.0.1 (cela + phendula):

$ ping -c1 localhost

futhi manje ake sibheke okuqukethwe kwefayela elibonakalayo lokususa iphutha /sys/kernel/debug/tracing/trace_pipe, lapho bpf_printk ubhala imiyalezo yakhe:

# 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

Amaphakheji amabili abonwe lo futhi yacutshungulwa ku-CPU0 - uhlelo lwethu lokuqala olugcwele oluphelele lwe-BPF lusebenzile!

Kumele uqaphele lokho bpf_printk Akuyona ize ukuthi ibhalela ifayela lokususa iphutha: lokhu akuyena umsizi ophumelele kakhulu wokusetshenziswa ekukhiqizeni, kodwa umgomo wethu kwakuwukukhombisa into elula.

Ukufinyelela amamephu kusukela ezinhlelweni ze-BPF

Isibonelo: ukusebenzisa imephu yohlelo lwe-BPF

Ezigabeni ezedlule sifunde ukudala nokusebenzisa amamephu endaweni yomsebenzisi, futhi manje ake sibheke ingxenye ye-kernel. Ake siqale, njengenjwayelo, ngesibonelo. Asibhale kabusha uhlelo lwethu xdp-simple.bpf.c kanje:

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

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

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

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

    *val += 1;

    return XDP_PASS;
}

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

Ekuqaleni kohlelo sengeze incazelo yemephu woo: Lona uhlu lwezinto ezingu-8 ezigcina amanani afana u64 (ku-C singachaza uhlu olunjalo ngokuthi u64 woo[8]). Ohlelweni "xdp/simple" sithola inombolo yephrosesa yamanje ibe okuguquguqukayo key bese usebenzisa umsebenzi womsizi bpf_map_lookup_element sithola i-pointer ekungeneni okuhambisanayo ohlwini, esikwandisa ngakunye. Kuhunyushelwe kusi-Russian: sibala izibalo lapho i-CPU icubungule amaphakethe angenayo. Ake sizame ukuqalisa uhlelo:

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

Ake sihlole ukuthi uxhumene naye lo futhi uthumele amaphakethe athile:

$ 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

Manje ake sibheke okuqukethwe kwamalungu afanayo:

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

Cishe zonke izinqubo zacutshungulwa ku-CPU7. Lokhu akubalulekile kithi, into esemqoka ukuthi uhlelo lusebenza futhi siyaqonda ukuthi ungafinyelela kanjani amamephu kusuka ezinhlelweni ze-BPF - usebenzisa Ρ…Π΅Π»ΠΏΠ΅Ρ€ΠΎΠ² bpf_mp_*.

Inkomba yemfihlakalo

Ngakho-ke, singakwazi ukufinyelela imephu kusuka kuhlelo lwe-BPF sisebenzisa izingcingo ezifana

val = bpf_map_lookup_elem(&woo, &key);

lapho umsebenzi womsizi ubukeka kanjani

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

kodwa sidlula inkomba &woo esakhiweni esingashiwongo struct { ... }...

Uma sibheka umhlanganisi wohlelo, sibona ukuthi inani &woo empeleni akuchazwanga (umugqa wesi-4):

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

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

Disassembly of section xdp/simple:

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

futhi iqukethwe ekuthuthweni:

$ 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

Kodwa uma sibheka uhlelo oseluvele lulayishiwe, sibona isikhombi semephu efanele (umugqa wesi-4):

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

Ngakho-ke, singaphetha ngokuthi ngesikhathi sethula uhlelo lwethu lokulayisha, isixhumanisi esiya &woo kwathathelwa indawo okuthile ngomtapo wolwazi libbpf. Okokuqala sizobheka okukhiphayo strace:

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

Siyakubona lokho libbpf udale imephu woo bese ulanda uhlelo lwethu simple. Ake sibhekisise ukuthi silayisha kanjani uhlelo:

  • shayela xdp_simple_bpf__open_and_load kusuka kufayela xdp-simple.skel.h
  • okuyimbangela xdp_simple_bpf__load kusuka kufayela xdp-simple.skel.h
  • okuyimbangela bpf_object__load_skeleton kusuka kufayela libbpf/src/libbpf.c
  • okuyimbangela bpf_object__load_xattr kusuka ku libbpf/src/libbpf.c

Umsebenzi wokugcina, phakathi kwezinye izinto, uzobiza bpf_object__create_maps, edala noma evula amamephu akhona, iwaguqule abe izichazi zefayela. (Kulapho sibona khona BPF_MAP_CREATE kokuphumayo strace.) Okulandelayo umsebenzi ubizwa bpf_object__relocate futhi nguye osithakazelayo, njengoba sikhumbula esikubonile woo etafuleni lokuthutha. Ukuyihlola, ekugcineni sizithola sisemsebenzini bpf_program__relocate, okuthi iphathelene nokuthuthwa kwemephu:

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

Ngakho sithatha imiyalelo yethu

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

bese ufaka esikhundleni serejista yomthombo kuyo BPF_PSEUDO_MAP_FD, kanye ne-IMM yokuqala kusichazi sefayela lemephu yethu futhi, uma ilingana, ngokwesibonelo, 0xdeadbeef, khona-ke ngenxa yalokho siyothola isiyalo

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

Lena yindlela ulwazi lwemephu oludluliselwa ngayo kuhlelo oluthile olulayishiwe lwe-BPF. Kulokhu, imephu ingadalwa kusetshenziswa BPF_MAP_CREATE, futhi ivulwe nge-ID kusetshenziswa BPF_MAP_GET_FD_BY_ID.

Ingqikithi, uma usebenzisa libbpf i-algorithm imi kanje:

  • ngesikhathi sokuhlanganiswa, amarekhodi adalwa kuthebula lokuthutha ukuze axhumane namamephu
  • libbpf ivula incwadi yento ye-ELF, ithola wonke amamephu asetshenzisiwe bese iwadalela izichazi zefayela
  • izichazi zefayela zilayishwa ku-kernel njengengxenye yomyalelo LD64

Njengoba ungacabanga, kuningi okuzayo futhi kuzodingeka sibheke umnyombo. Ngenhlanhla, sinawo umkhondo - siyibhale phansi incazelo BPF_PSEUDO_MAP_FD kurejista yomthombo futhi singayingcwaba, ezosiholela engcweleni yabo bonke abangcwele - kernel/bpf/verifier.c, lapho umsebenzi onegama elihlukile uthatha indawo yesichazi sefayela ngekheli lesakhiwo sohlobo struct bpf_map:

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

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

(ikhodi egcwele ingatholakala isixhumanisi). Ngakho-ke singanweba i-algorithm yethu:

  • ngenkathi ilayisha uhlelo, isiqinisekisi sihlola ukusetshenziswa okufanele kwemephu futhi sibhale ikheli lesakhiwo esihambisanayo struct bpf_map

Uma ulanda kanambambili we-ELF usebenzisa libbpf Kuningi okuqhubekayo, kodwa sizoxoxa ngakho kwezinye izihloko.

Ilayisha izinhlelo namamephu ngaphandle kwe-libbpf

Njengoba kuthenjisiwe, nasi isibonelo sabafundi abafuna ukwazi ukuthi bangakha futhi balayishe kanjani uhlelo olusebenzisa amamephu, ngaphandle kosizo. libbpf. Lokhu kungaba wusizo uma usebenza endaweni ongakwazi ukwakha kuyo ukuncika, noma ukonga yonke ingxenye, noma ubhala uhlelo olufana nelo. ply, ekhiqiza ikhodi kanambambili ye-BPF ekuhambeni.

Ukwenza kube lula ukulandela ingqondo, sizobhala kabusha isibonelo sethu ngalezi zinhloso xdp-simple. Ikhodi ephelele nenwetshiwe kancane yohlelo okuxoxwe ngalo kulesi sibonelo ingatholakala kulokhu Ingqikithi.

I-logic yesicelo sethu imi kanje:

  • dala uhlobo lwemephu BPF_MAP_TYPE_ARRAY usebenzisa umyalo BPF_MAP_CREATE,
  • dala uhlelo olusebenzisa le mephu,
  • xhuma uhlelo kusixhumi esibonakalayo lo,

elihumusha kumuntu ngokuthi

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

kuyinto map_create idala imephu ngendlela efanayo naleyo esenzile esibonelweni sokuqala mayelana nekholi yesistimu bpf - β€œkernel, ngicela ungenzele imephu entsha ngendlela yohlu lwama-elementi angu-8 afana __u64 bese ungibuyisela isichazi sefayela":

static int map_create()
{
    union bpf_attr attr;

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

Uhlelo futhi kulula ukulayisha:

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

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

Ingxenye ekhohlisayo prog_load incazelo yohlelo lwethu lwe-BPF njengoxhaxha lwezakhiwo struct bpf_insn insns[]. Kodwa njengoba sisebenzisa uhlelo esinalo ku-C, singakopela kancane:

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

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

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

Sekukonke, sidinga ukubhala imiyalelo eyi-14 ngendlela yezakhiwo ezifana struct bpf_insn (iseluleko: thatha indawo yokulahla phezulu, phinda ufunde isigaba semiyalelo, vula linux/bpf.h ΠΈ linux/bpf_common.h bese uzama ukunquma struct bpf_insn insns[] yedwa):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ukuzivocavoca kulabo abangazange babhale lokhu ngokwabo - thola map_fd.

Kunengxenye eyodwa engadalulwanga esele ohlelweni lwethu - xdp_attach. Ngeshwa, izinhlelo ezifana ne-XDP azikwazi ukuxhunywa kusetshenziswa ikholi yesistimu bpf. Abantu abadale i-BPF ne-XDP babevela emphakathini we-Linux eku-inthanethi, okusho ukuthi basebenzise lowo abazijwayele kakhulu (kodwa hhayi evamile people) isikhombimsebenzisi sokusebenzelana ne-kernel: amasokhethi e-netlink, bhekafuthi I-RFC3549. Indlela elula yokuqalisa xdp_attach ikopisha ikhodi ku libbpf, okungukuthi, kusukela kufayela netlink.c, yilokho esikwenzile, ukufinyeza kancane:

Siyakwamukela emhlabeni wamasokhethi e-netlink

Vula uhlobo lwesokhethi ye-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;
}

Sifunda kulesi sokhethi:

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

Ekugcineni, nansi umsebenzi wethu ovula isokhethi bese uthumela umlayezo okhethekile kuyo oqukethe isichazi sefayela:

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

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

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

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

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

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

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

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

cleanup:
    close(sock);
    return ret;
}

Ngakho, yonke into isilungele ukuhlolwa:

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

Ake sibone ukuthi uhlelo lwethu luxhumekile yini 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

Masithumele ama-pings futhi sibheke imephu:

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

Hurray, konke kuyasebenza. Qaphela, ngendlela, ukuthi imephu yethu iphinda ikhonjiswe ngendlela yamabhayithi. Lokhu kungenxa yokuthi, ngokungafani libbpf asizange silayishe ulwazi lohlobo (BTF). Kodwa sizokhuluma kabanzi ngalokhu ngokuzayo.

Amathuluzi Okuthuthukisa

Kulesi sigaba, sizobheka ikhithi yamathuluzi kanjiniyela ye-BPF encane.

Ngokuvamile, awudingi lutho olukhethekile ukuze uthuthukise izinhlelo ze-BPF - i-BPF isebenza kunoma iyiphi i-kernel yokusabalalisa ehloniphekile, futhi izinhlelo zakhiwa kusetshenziswa. clang, enganikezwa kusukela kuphakheji. Kodwa-ke, ngenxa yokuthi i-BPF ingaphansi kokuthuthukiswa, i-kernel namathuluzi ahlala eshintsha, uma ungafuni ukubhala izinhlelo ze-BPF usebenzisa izindlela zakudala kusukela ngo-2019, kuzodingeka uhlanganise.

  • llvm/clang
  • pahole
  • umgogodla wayo
  • bpftool

(Ukuze uthole ireferensi, lesi sigaba kanye nazo zonke izibonelo eziku-athikili zisetshenziswe ku-Debian 10.)

llvm/clang

I-BPF inobungani ne-LLVM futhi, nakuba izinhlelo zakamuva ze-BPF zingahlanganiswa kusetshenziswa i-gcc, konke ukuthuthukiswa kwamanje kwenzelwa i-LLVM. Ngakho-ke, okokuqala, sizokwakha inguqulo yamanje clang kusuka ku-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
... ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ спустя
$

Manje singakwazi ukuhlola ukuthi konke kuhlangane kahle yini:

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

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

(Iziqondiso zomhlangano clang othathwe yimi kusuka bpf_devel_QA.)

Ngeke sizifake izinhlelo esisanda kuzakha, kodwa esikhundleni salokho sizozengeza kuzo PATHisibonelo:

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

(Lokhu kungangezwa ku .bashrc noma kufayela elihlukile. Ngokwami, ngengeza izinto ezinjengalezi ~/bin/activate-llvm.sh futhi uma kunesidingo ngiyakwenza . activate-llvm.sh.)

I-Pahole ne-BTF

Okusetshenziswayo pahole esetshenziswa lapho kwakhiwa i-kernel ukudala ulwazi lokususa iphutha ngefomethi ye-BTF. Ngeke singene ngokuningiliziwe kulesi sihloko mayelana nemininingwane yobuchwepheshe be-BTF, ngaphandle kokuthi ilula futhi sifuna ukuyisebenzisa. Ngakho-ke uma uzokwakha i-kernel yakho, yakha kuqala pahole (ngaphandle kwe- pahole ngeke ukwazi ukwakha i-kernel ngenketho 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

Izinhlamvu zokuhlola i-BPF

Lapho ngihlola amathuba e-BPF, ngifuna ukuhlanganisa owami umongo. Lokhu, ngokujwayelekile, akudingekile, ngoba uzokwazi ukuhlanganisa nokulayisha izinhlelo ze-BPF ku-kernel yokusabalalisa, noma kunjalo, ukuba ne-kernel yakho kukuvumela ukuthi usebenzise izici zakamuva ze-BPF, ezizovela ekusabalaliseni kwakho ezinyangeni ezingcono kakhulu. , noma, njengasendabeni yamanye amathuluzi okulungisa amaphutha ngeke apakishwe nhlobo esikhathini esizayo esibonakalayo. Futhi, ingqikithi yayo ikwenza kuzizwe kubalulekile ukuzama ikhodi.

Ukuze wakhe i-kernel udinga, okokuqala, i-kernel ngokwayo, futhi okwesibili, ifayela lokumisa i-kernel. Ukuhlola i-BPF singasebenzisa okujwayelekile i-vanilla i-kernel noma enye yezinhlamvu zokuthuthuka. Ngokomlando, ukuthuthukiswa kwe-BPF kwenzeka phakathi komphakathi wenethiwekhi ye-Linux ngakho-ke zonke izinguquko ngokushesha noma kamuva zidlula kuDavid Miller, umnakekeli wenethiwekhi ye-Linux. Kuya ngobunjalo bazo - ukuhlela noma izici ezintsha - izinguquko zenethiwekhi ziwela kowodwa wamacores amabili - net noma net-next. Izinguquko ze-BPF zisatshalaliswa ngendlela efanayo phakathi bpf ΠΈ bpf-next, ezibe sezihlanganiswa zibe inetha bese zilandelana, ngokulandelana. Ukuze uthole imininingwane eyengeziwe, bheka bpf_devel_QA ΠΈ I-netdev-FAQ. Ngakho-ke khetha i-kernel ngokusekelwe kokuthandayo kanye nezidingo zokuzinza zesistimu ohlola kuyo (*-next ama-kernels yiwona angazinzi kakhulu kulawo asohlwini).

Kungaphezu kobubanzi balesi sihloko ukukhuluma ngendlela yokuphatha amafayela wokumisa i-kernel - kucatshangwa ukuthi kungenzeka ukuthi usuvele wazi ukuthi ungakwenza kanjani lokhu, noma ukulungele ukufunda yedwa. Kodwa-ke, le miyalo elandelayo kufanele ibe ngaphezulu noma ngaphansi ngokwanele ukuze ikunikeze uhlelo olusebenzayo olusebenzisa i-BPF.

Landa enye yalezi zinhlamvu ezingenhla:

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

Yakha ukucushwa kwe-kernel encane yokusebenza:

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

Nika amandla izinketho ze-BPF kufayela .config ngokukhetha kwakho (okungenzeka CONFIG_BPF izovele inikwe amandla njengoba i-systemd iyisebenzisa). Nalu uhlu lwezinketho ezivela ku-kernel esetshenziselwa lesi sihloko:

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

Ngemuva kwalokho singakwazi ukuhlanganisa kalula futhi sifake amamojula kanye ne-kernel (ngendlela, ungakwazi ukuhlanganisa i-kernel usebenzisa okusanda kuhlanganiswa. clangngokungeza CC=clang):

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

bese uqalisa kabusha nge-kernel entsha (ngiyisebenzisela lokhu kexec kusuka kuphakheji 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

Isisetshenziswa esisetshenziswa kakhulu esihlokweni kuzoba insiza bpftool, ehlinzekwa njengengxenye ye-Linux kernel. Ibhalwa futhi inakekelwe abathuthukisi be-BPF yonjiniyela be-BPF futhi ingasetshenziswa ukuphatha zonke izinhlobo zezinto ze-BPF - layisha izinhlelo, udale futhi uhlele amamephu, uhlole impilo ye-ecosystem ye-BPF, njll. Amadokhumenti asesimweni samakhodi omthombo wamakhasi omuntu angatholakala emnyombeni noma, sekuhlanganisiwe, ku-inthanethi.

Ngesikhathi sokuloba bpftool ifika isilungele kuphela i-RHEL, i-Fedora ne-Ubuntu (bheka, isibonelo, lolu chungechunge, esitshela indaba engaqediwe yokupakisha bpftool ngeDebian). Kodwa uma usuyakhile i-kernel yakho, bese yakha bpftool lula njengophaya:

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

$

(lapha ${linux} - lena yinkomba yakho ye-kernel.) Ngemva kokwenza le miyalo bpftool izoqoqwa ohlwini lwemibhalo ${linux}/tools/bpf/bpftool futhi ingangezwa endleleni (okokuqala kumsebenzisi root) noma vele ukopishe ku /usr/local/sbin.

Qoqa bpftool kungcono ukusebenzisa yokugcina clang, ihlanganiswe njengoba kuchazwe ngenhla, futhi uhlole ukuthi ihlanganiswe kahle - usebenzisa, isibonelo, umyalo

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

ezobonisa ukuthi yiziphi izici ze-BPF ezinikwe amandla ku-kernel yakho.

Ngendlela, umyalo wangaphambilini ungaqhutshwa njenge

# bpftool f p k

Lokhu kwenziwa ngokufanisa nezinsiza ezivela kuphakheji iproute2, lapho esingasho khona, ngokwesibonelo, ukusho ip a s eth0 esikhundleni salokho ip addr show dev eth0.

isiphetho

I-BPF ikuvumela ukuthi ufake isicathulo inzeze ukuze ulinganise kahle futhi lapho undiza ushintshe ukusebenza komgogodla. Uhlelo luphumelele kakhulu, emasikweni angcono kakhulu e-UNIX: indlela elula evumela ukuthi (uphinde) uhlele i-kernel ivumele inani elikhulu labantu nezinhlangano ukuthi zivivinye. Futhi, nakuba ukuhlolwa, kanye nokuthuthukiswa kwengqalasizinda ye-BPF ngokwayo, kusekude nokuqedwa, uhlelo seluvele lunayo i-ABI ezinzile evumela ukuthi wakhe i-logic yebhizinisi ethembekile, futhi okubaluleke kakhulu, ephumelelayo.

Ngithanda ukuqaphela ukuthi, ngokubona kwami, ubuchwepheshe buye buthandwa kakhulu ngoba, ngakolunye uhlangothi, bungakwazi ukudlala (isakhiwo somshini singaqondwa kancane noma ngaphansi ngobusuku obubodwa), futhi ngakolunye uhlangothi, ukuxazulula izinkinga ezingenakuxazululwa (kakuhle) ngaphambi kokubonakala kwayo. Lezi zingxenye ezimbili zihlangene ziphoqa abantu ukuthi bazame futhi baphuphe, okuholela ekuveleni kwezixazululo eziningi ezintsha.

Lesi sihloko, nakuba singesifushane kakhulu, siyisingeniso kuphela emhlabeni we-BPF futhi asichazi izici "ezithuthukisiwe" nezingxenye ezibalulekile zezakhiwo. Uhlelo oluya phambili lungokufana nalokhu: isihloko esilandelayo sizoba isifinyezo sezinhlobo zohlelo lwe-BPF (kunezinhlobo zezinhlelo ezingu-5.8 ezisekelwa ku-30 kernel), bese ekugcineni sibheka ukuthi zibhalwa kanjani izinhlelo zokusebenza ze-BPF zangempela zisebenzisa izinhlelo zokulandelela i-kernel. njengesibonelo, sekuyisikhathi sesifundo esijulile mayelana nezakhiwo ze-BPF, okulandelwa izibonelo zezinhlelo zokusebenza zenethiwekhi nezokuphepha ze-BPF.

Izihloko ezedlule kulolu chungechunge

  1. I-BPF yabancane, ingxenye enguziro: i-BPF yakudala

Izixhumanisi

  1. I-BPF kanye ne-XDP Reference Guide β€” imibhalo ye-BPF evela ku-cilium, noma ngokuqondile evela ku-Daniel Borkman, omunye wabadali nabanakekeli be-BPF. Lena enye yezincazelo zokuqala ezingathi sΓ­na, ehlukile kwezinye ngoba uDaniyeli wazi kahle ukuthi ubhala ngani futhi awekho amaphutha lapho. Ikakhulukazi, lo mbhalo uchaza indlela yokusebenza nezinhlelo ze-BPF zezinhlobo ze-XDP ne-TC kusetshenziswa insiza eyaziwayo. ip kusuka kuphakheji iproute2.

  2. Documentation/networking/filter.txt β€” ifayela langempela elinamadokhumenti e-BPF yakudala bese eyandiswa. Ukufundwa okuhle uma ufuna ukujula olimini lomhlangano kanye nemininingwane yezakhiwo zobuchwepheshe.

  3. Ibhulogi nge-BPF evela ku-facebook. Ibuyekezwa kuyaqabukela, kodwa ngokufanelekile, njengoba u-Alexei Starovoitov (umbhali we-eBPF) no-Andrii Nakryiko - (umlondolozi) bebhala lapho. libbpf).

  4. Izimfihlo ze-bpftool. Intambo ye-twitter ejabulisayo evela ku-Quentin Monnet enezibonelo nezimfihlo zokusebenzisa i-bpftool.

  5. Ngena ku-BPF: uhlu lwezinto zokufunda. Uhlu olukhulu (futhi olusagciniwe) lwezixhumanisi zemibhalo ye-BPF oluvela ku-Quentin Monnet.

Source: www.habr.com

Engeza amazwana