BPF do na cinn beag, cuid a haon: BPF leathnaithe

I dtús bhí teicneolaíocht agus tugadh BPF air. D'fhéachamar uirthi roimhe seo, Sean-Tiomna, alt sa tsraith seo. Sa bhliain 2013, trí iarrachtaí Alexei Starovoitov agus Daniel Borkman, forbraíodh é agus cuireadh san áireamh é sa chroílár. Linux Leagan feabhsaithe atá optamaithe do mheaisíní nua-aimseartha 64-giotán. Tugadh BPF Inmheánach ar an teicneolaíocht nua seo go hachomair, athainmníodh í mar BPF Leathnaithe ina dhiaidh sin, agus anois, roinnt blianta ina dhiaidh sin, tugann gach duine BPF uirthi go simplí.

Go bunúsach, ceadaíonn BPF do chód treallach arna sholáthar ag úsáideoirí rith sa spás eithne. Linux Agus bhí an ailtireacht nua chomh rathúil sin go mbeadh dosaen alt eile ag teastáil uainn chun cur síos a dhéanamh ar a feidhmchláir go léir. (An t-aon rud nár éirigh leis na forbróirí a dhéanamh, mar is féidir leat a fheiceáil sa chairt éifeachtúlachta thíos, ná lógó maith a chruthú.)

Déanann an t-alt seo cur síos ar struchtúr an mheaisín fíorúil BPF, comhéadain eithne chun oibriú le BPF, uirlisí forbartha, chomh maith le forbhreathnú gairid, an-ghairid ar na cumais atá ann cheana féin, i.e. gach rud a bheidh ag teastáil uainn amach anseo chun staidéar níos doimhne a dhéanamh ar fheidhmiú praiticiúla BPF.
BPF do na cinn beag, cuid a haon: BPF leathnaithe

Achoimre ar an alt

Cur i láthair ar ailtireacht BPF. Ar dtús, glacfaimid radharc súl éan ar ailtireacht an BPF agus leagfaimid amach na príomhchodanna.

Cláir agus córas ordaithe an mheaisín fíorúil BPF. Ag smaoineamh cheana féin ar an ailtireacht ina iomláine, déanfaimid cur síos ar struchtúr meaisín fíorúil BPF.

Saolré rudaí BPF, córas comhaid bpffs. Sa chuid seo, déanfaimid breathnú níos dlúithe ar shaolré rudaí BPF - cláir agus léarscáileanna.

Rudaí a bhainistiú ag baint úsáide as glao an chórais bpf. Agus tuiscint éigin againn ar an gcóras cheana féin, féachfaimid faoi dheireadh ar conas rudaí a chruthú agus a ionramháil ó spás úsáideora ag baint úsáide as glao córais speisialta - bpf(2).

Пишем программы BPF с помощью libbpf. Ar ndóigh, is féidir leat cláir a scríobh ag baint úsáide as glao córais. Ach tá sé deacair. Chun cás níos réadúla a fháil, d'fhorbair ríomhchláraitheoirí núicléacha leabharlann libbpf. Cruthóimid creatlach feidhmchlár BPF bunúsach a úsáidfimid sna samplaí ina dhiaidh sin.

Cúntóirí Eithne. Anseo beidh muid ag foghlaim conas is féidir le cláir BPF rochtain a fháil ar fheidhmeanna cúntóir eithne - uirlis a leathnaíonn go bunúsach, in éineacht le léarscáileanna, cumais an BPF nua i gcomparáid leis an gceann clasaiceach.

Rochtain ar léarscáileanna ó chláir BPF. Faoin bpointe seo, beidh a fhios againn go leor chun a thuiscint go beacht conas is féidir linn cláir a chruthú a úsáideann léarscáileanna. Agus déanaimis fiú breathnú tapa ar an bhfíoraitheoir mór agus cumhachtach.

Uirlisí forbartha. Cuidiú alt ar conas na fóntais riachtanacha agus eithne a chur le chéile le haghaidh turgnaimh.

Conclúid. Ag deireadh an ailt, gheobhaidh na daoine a léann go dtí seo focail spreagúla agus cur síos gairid ar cad a tharlóidh sna hailt seo a leanas. Liostaeoimid freisin roinnt nasc le haghaidh féinstaidéir dóibh siúd nach bhfuil an fonn nó an cumas acu fanacht leis an leanúint.

Réamhrá don Ailtireacht BPF

Sula dtosaímid ag smaoineamh ar ailtireacht BPF, déanfaimid tagairt uair dheireanach amháin (oh) chuig BPF clasaiceach, a forbraíodh mar fhreagra ar theacht na meaisíní RISC agus réitigh sé an fhadhb a bhaineann le scagadh paicéad éifeachtach. D'éirigh chomh maith sin leis an ailtireacht gur rugadh í sna nóchaidí meara i Berkeley UNIX, gur cuireadh ar aghaidh í an chuid is mó de na córais oibriúcháin a bhí ann cheana féin, gur mhair sí sna fichidí mire agus tá feidhmchláir nua á aimsiú fós aige.

Forbraíodh an BPF nua mar fhreagra ar uileláithreacht na meaisíní 64-giotán, seirbhísí néal agus an gá méadaithe le huirlisí chun SDN a chruthú (Searraí-dfineáilte nForbraíodh an BPF nua ag innealtóirí croí-líonra mar ionadach feabhsaithe don BPF clasaiceach, agus fuair sé mhí ina dhiaidh sin an feidhmchlár deacair rianaithe. Linux córais, agus anois, sé bliana tar éis a bhfeicthe, bheadh ​​​​alt nua ar fad ag teastáil uainn chun na cineálacha éagsúla clár a liostáil.

Pictiúir greannmhar

Ag a chroílár, is meaisín fíorúil bosca gainimh é BPF a ligeann duit cód “treallach” a rith i spás eithne gan cur isteach ar shlándáil. Cruthaítear cláir BPF i spás an úsáideora, iad a luchtú isteach san eithne, agus iad a nascadh le foinse imeachtaí éigin. D’fhéadfadh imeacht a bheith, mar shampla, seachadadh paicéad chuig comhéadan líonra, seoladh roinnt feidhm eithne, etc. I gcás pacáiste, beidh rochtain ag an gclár BPF ar shonraí agus ar mheiteashonraí an phacáiste (le haghaidh léamh agus, b'fhéidir, scríbhneoireacht, ag brath ar an gcineál clár a bhaineann le feidhm eithne, beidh argóintí na an fheidhm, lena n-áirítear leideanna chun cuimhne eithne, etc.

Breathnaímis ar an bpróiseas seo. Chun tús a chur leis, déanaimis labhairt faoin gcéad difríocht ón BPF clasaiceach, a scríobhadh cláir le haghaidh cóimeálaí. Sa leagan nua, leathnaíodh an ailtireacht ionas go bhféadfaí cláir a scríobh i dteangacha ardleibhéil, go príomha, ar ndóigh, i C. Chun seo, forbraíodh inneall llvm, a ligeann duit bytecode a ghiniúint don ailtireacht BPF.

BPF do na cinn beag, cuid a haon: BPF leathnaithe

Dearadh an ailtireacht BPF, go páirteach, chun oibriú go héifeachtach ar mheaisíní nua-aimseartha. Chun an obair seo a dhéanamh go praiticiúil, aistrítear seachchód an BPF, a luaithe a luchtaítear é isteach san eithne, go cód dúchais trí úsáid a bhaint as comhpháirt ar a dtugtar tiomsaitheoir JIT (Just In Time). Ansin, más cuimhin leat, i BPF clasaiceach luchtaíodh an clár isteach san eithne agus ceangailte le foinse an imeachta go atomically - i gcomhthéacs glao córais aonair. San ailtireacht nua, tarlaíonn sé seo i dhá chéim - ar dtús, tá an cód luchtaithe isteach san eithne ag baint úsáide as glao córais bpf(2)agus ansin, níos déanaí, trí mheicníochtaí eile a athraíonn ag brath ar an gcineál cláir, ceanglaíonn an clár le foinse an imeachta.

B’fhéidir go mbeadh ceist ag an léitheoir anseo: an raibh sé indéanta? Conas a ráthaítear sábháilteacht forghníomhaithe an chóid sin? Tá sábháilteacht fhorghníomhaithe ráthaithe dúinn ag an gcéim luchtaithe cláir BPF ar a dtugtar fíoraitheoir (i mBéarla tugtar fíoraitheoir ar an gcéim seo agus leanfaidh mé ag úsáid an fhocail Béarla):

BPF do na cinn beag, cuid a haon: BPF leathnaithe

Is anailíseoir statach é fíoraitheoir a chinntíonn nach gcuireann clár isteach ar ghnáthoibriú na heithne. Ní chiallaíonn sé seo, dála an scéil, nach féidir leis an gclár cur isteach ar oibriú an chórais - is féidir le cláir BPF, ag brath ar an gcineál, codanna de chuimhne eithne a léamh agus a athscríobh, luachanna feidhmeanna a chur ar ais, Baile Átha Troim, Iarcheangail, Athscríobh agus fiú paicéid líonra ar aghaidh. Ráthaíonn fíoraitheoir nach ndéanfaidh reáchtáil clár BPF an t-eithne a thuairteáil agus nach mbeidh clár a bhfuil rochtain scríofa aige, mar shampla, sonraí paicéad atá ag dul as oifig, in ann an chuimhne eithne lasmuigh den phaicéad a scríobh. Breathnóimid ar an bhfíoraitheoir go mion sa mhír chomhfhreagrach, tar éis dúinn eolas a fháil ar na comhpháirteanna eile go léir de BPF.

Mar sin cad atá foghlamtha againn go dtí seo? Scríobhann an t-úsáideoir clár i C, lódálann sé isteach san eithne ag baint úsáide as glao córais bpf(2), áit a ndéanann fíoraitheoir é a sheiceáil agus a aistriú go bytecode dúchais. Ansin nascann an t-úsáideoir céanna nó úsáideoir eile an clár le foinse an imeachta agus tosaíonn sé a fhorghníomhú. Tá gá le híoslódáil agus nasc a scaradh ar chúiseanna éagsúla. Ar an gcéad dul síos, tá sé sách costasach fíoraitheoir a rith agus tríd an gclár céanna a íoslódáil arís agus arís eile cuirimid am ríomhaire amú. Ar an dara dul síos, braitheann an chaoi a nasctar clár ar a chineál, agus b’fhéidir nach mbeadh comhéadan “uilíoch” amháin a forbraíodh bliain ó shin oiriúnach do chineálacha nua clár. (Cé go bhfuil an ailtireacht ag éirí níos aibí anois, tá smaoineamh ann an comhéadan seo a aontú ag an leibhéal libbpf.)

Seans go dtabharfaidh an léitheoir aireach faoi deara nach bhfuil muid críochnaithe leis na pictiúir fós. Go deimhin, ní mhíníonn gach ceann de na nithe thuas cén fáth a athraíonn BPF an pictiúr go bunúsach i gcomparáid le BPF clasaiceach. Dhá nuálaíocht a leathnaíonn go suntasach an raon feidhme infheidhmeachta ná an cumas cuimhne roinnte agus feidhmeanna cúntóir eithne a úsáid. I BPF, cuirtear cuimhne roinnte i bhfeidhm ag baint úsáide as léarscáileanna mar a thugtar orthu - struchtúir sonraí roinnte le API ar leith. Is dócha go bhfuair siad an t-ainm seo mar ba é tábla hash an chéad chineál léarscáile a tháinig chun solais. Ansin bhí eagair le feiceáil, táblaí hash áitiúla (in aghaidh an LAP) agus eagair áitiúla, crainn chuardaigh, léarscáileanna ina raibh leideanna maidir le cláir BPF agus i bhfad níos mó. Is é an rud atá suimiúil dúinn anois go bhfuil an cumas ag cláir BPF anois seasamh idir glaonna agus é a roinnt le cláir eile agus le spás úsáideora.

Faightear rochtain ar léarscáileanna ó phróisis úsáideora trí ghlao córais a úsáid bpf(2), agus ó chláir BPF a ritheann san eithne ag baint úsáide as feidhmeanna cúntóra. Ina theannta sin, tá cúntóirí ann ní hamháin chun oibriú le léarscáileanna, ach freisin chun rochtain a fháil ar chumais eithne eile. Mar shampla, is féidir le cláir BPF feidhmeanna cúntóra a úsáid chun paicéid a chur ar aghaidh chuig comhéadain eile, imeachtaí perf a ghiniúint, rochtain a fháil ar struchtúir eithne, agus mar sin de.

BPF do na cinn beag, cuid a haon: BPF leathnaithe

Go hachomair, soláthraíonn BPF an cumas cód úsáideora a lódáil go treallach, i.e., arna thástáil ag fíoraitheoir, isteach sa spás eithne. Is féidir leis an gcód seo staid idir glaonna agus sonraí a mhalartú le spás úsáideora a shábháil, agus tá rochtain aige freisin ar fhochórais eithne a cheadaítear leis an gcineál seo cláir.

Tá sé seo cosúil leis na cumais a sholáthraíonn modúil eithne cheana féin, i gcomparáid leo a bhfuil roinnt buntáistí ag BPF (ar ndóigh, ní féidir leat ach feidhmchláir den chineál céanna a chur i gcomparáid, mar shampla, rianú córais - ní féidir leat tiománaí treallach a scríobh le BPF). Is féidir leat tairseach iontrála níos ísle a thabhairt faoi deara (ní éilíonn roinnt fóntais a úsáideann BPF go mbeadh scileanna ríomhchláraithe eithne ag an úsáideoir, nó scileanna ríomhchláraithe go ginearálta), sábháilteacht am rite (ardaigh do lámh sna tuairimí dóibh siúd nach bhfuil briste ar an gcóras agus iad ag scríobh. nó modúil tástála), adamhacht - tá downtime nuair a athlódáil modúil, agus cinntíonn an fochóras BPF nach bhfuil aon imeachtaí a chailleann (le bheith cothrom, níl sé seo fíor do gach cineál clár BPF).

Déanann láithreacht na gcumas sin BPF mar uirlis uilíoch chun an eithne a leathnú, rud a dheimhnítear go praiticiúil: cuirtear níos mó agus níos mó cineálacha nua clár le BPF, úsáideann cuideachtaí móra níos mó agus níos mó BPF ar fhreastalaithe comhraic 24 × 7, níos mó agus níos mó. tógann gnólachtaí nuathionscanta a ngnó ar réitigh atá bunaithe ar BPF. Úsáidtear BPF i ngach áit: i gcosaint ar ionsaithe DDoS, ag cruthú SDN (mar shampla, líonraí a chur i bhfeidhm le haghaidh kubernetes), mar phríomhuirlis rianaithe córais agus mar bhailitheoir staitisticí, i gcórais braite ionsáite agus córais bosca gainimh, etc.

Críochnaímis an chuid forbhreathnú den alt anseo agus féachaimid ar an meaisín fíorúil agus ar éiceachóras BPF go mion.

Digression: fóntais

D'fhonn a bheith in ann na samplaí a rith sna hailt seo a leanas, b'fhéidir go mbeadh roinnt fóntais ag teastáil uait, ar a laghad llvm/clang le tacaíocht bpf agus bpftool. Sa roinn Uirlisí Forbartha Is féidir leat na treoracha a léamh chun na fóntais a chur le chéile, chomh maith le do eithne. Tá an chuid seo curtha thíos ionas nach gcuirfí isteach ar chomhréiteach ár gcur i láthair.

Clár Meaisín Fíorúil BPF agus Córas Teagaisc

Forbraíodh ailtireacht agus córas ordaithe BPF ag cur san áireamh go scríobhfar cláir i C agus, tar éis iad a luchtú isteach san eithne, go n-aistreofar iad go cód dúchais. Dá bhrí sin, roghnaíodh líon na gclár agus an tsraith orduithe le súil ar an dtrasnaíonn, sa chiall matamaitice, inniúlachtaí meaisíní nua-aimseartha. Ina theannta sin, cuireadh srianta éagsúla i bhfeidhm ar chláir, mar shampla, go dtí le déanaí níorbh fhéidir lúba agus fo-ghnáthamh a scríobh, agus bhí líon na dtreoracha teoranta do 4096 (anois is féidir le cláir phribhléideacha suas le milliún treoracha a luchtú).

Tá aon chlár déag 64-giotán inrochtana ag BPF r0-r10 agus cuntar clár. Clár r10 tá pointeoir fráma agus tá sé inléite amháin. Tá rochtain ag cláir ar chruach 512 beart ag am rite agus méid neamhtheoranta de chuimhne roinnte i bhfoirm léarscáileanna.

Ceadaítear do chláir BPF sraith ar leith de chúntóirí eithne de chineál clár a reáchtáil agus, le déanaí, feidhmeanna rialta. Is féidir le gach feidhm ar a dtugtar suas le cúig argóintí a ghlacadh, a rith i gcláir r1-r5, agus cuirtear an luach tuairisceáin ar aghaidh chuig r0. Tá sé ráthaithe, tar éis filleadh ón bhfeidhm, go mbeidh ábhar na gclár r6-r9 Ní athróidh.

Le haghaidh aistriúchán éifeachtach clár, cláraigh r0-r11 i gcás gach ailtireachta thacaithe tá siad mapáilte go sainiúil chuig cláir fhíora, ag cur gnéithe ABI na hailtireachta reatha san áireamh. Mar shampla, le haghaidh x86_64 cláir r1-r5, a úsáidtear chun pas a fháil paraiméadair feidhm, ar taispeáint ar rdi, rsi, rdx, rcx, r8, a úsáidtear chun paraiméadair a chur ar aghaidh chuig feidhmeanna x86_64. Mar shampla, aistríonn an cód ar chlé go dtí an cód ar dheis mar seo:

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

Cláraigh r0 a úsáidtear freisin chun toradh fhorghníomhú an chláir a thabhairt ar ais, agus sa chlár r1 Cuirtear pointeoir chuig an gcomhthéacs ar an gclár - ag brath ar an gcineál cláir, d'fhéadfadh sé seo a bheith, mar shampla, ina struchtúr struct xdp_md (do XDP) nó struchtúr struct __sk_buff (do chláir líonra éagsúla) nó struchtúr struct pt_regs (le haghaidh cineálacha éagsúla clár rianaithe), etc.

Mar sin, bhí sraith clár againn, cúntóirí eithne, stack, pointeoir comhthéacs agus cuimhne roinnte i bhfoirm léarscáileanna. Ní hé go bhfuil sé seo go léir fíor-riachtanach ar an turas, ach...

Leanaimis leis an gcur síos agus labhróimid faoin gcóras ordaithe chun oibriú leis na cuspóirí seo. Gach (Beagnach ar fad) Tá méid seasta 64-giotán ag treoracha BPF. Má fhéachann tú ar threoir amháin ar mheaisín 64-giotán Big Endian feicfidh tú

BPF do na cinn beag, cuid a haon: BPF leathnaithe

Anseo Code - seo ionchódú an teagaisc, Dst/Src is ionchóduithe an ghlacadóra agus na foinse iad, faoi seach, Off - eangú sínithe 16-giotán, agus Imm is slánuimhir sínithe 32-giotán é a úsáidtear i roinnt treoracha (cosúil leis an tairiseach cBPF K). Ionchódú Code tá ceann amháin de dhá chineál aige:

BPF do na cinn beag, cuid a haon: BPF leathnaithe

Sainíonn ranganna teagaisc 0, 1, 2, 3 orduithe chun oibriú le cuimhne. siad Tugtar, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, faoi seach. Aicmí 4, 7 (BPF_ALU, BPF_ALU64(c) tacar treoracha ALU. Ranganna 5, 6 (BPF_JMP, BPF_JMP32) treoracha léime a bheith iontu.

Is é seo a leanas an plean breise chun staidéar a dhéanamh ar chóras teagaisc BPF: in ionad na treoracha agus na paraiméadair go léir a liostú go cúramach, féachfaimid ar chúpla sampla san alt seo agus uathu beidh sé soiléir conas a oibríonn na treoracha i ndáiríre agus conas díchóimeáil de láimh aon chomhad dénártha le haghaidh BPF. Chun an t-ábhar a chomhdhlúthú níos déanaí san alt, buailfimid freisin le treoracha aonair sna hailt faoi Fhíoraitheoir, tiomsaitheoir JIT, aistriúchán ar BPF clasaiceach, chomh maith le linn staidéar a dhéanamh ar léarscáileanna, feidhmeanna glaonna, etc.

Nuair a labhairt linn faoi threoracha aonair, déanfaimid tagairt do na croíchomhaid bpf.h и bpf_common.h, a shainíonn na cóid uimhriúla de threoracha BPF. Agus tú ag déanamh staidéir ar an ailtireacht leat féin agus/nó ag parsáil dhénártha, is féidir leat séimeantaic a aimsiú sna foinsí seo a leanas, curtha in ord castachta: Sonrú neamhoifigiúil EBPF, Treoir Thagartha BPF agus XDP, Tacar Treoracha, Doiciméadú/líonrú/filter.txt agus, ar ndóigh, sna cóid foinse Linux — fíoraitheoir, JIT, ateangaire BPF.

Sampla: díchóimeáil BPF i do cheann

Breathnaímid ar shampla ina gcuirimid clár le chéile readelf-example.c agus féach ar an dénártha mar thoradh air. Nochtfaimid an t-ábhar bunaidh readelf-example.c thíos, tar éis dúinn a loighic a athbhunú ó chóid dhénártha:

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

An chéad cholún san aschur readelf Is eangú é agus mar sin tá ceithre ordú inár gclár:

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

Tá cóid ordú comhionann b7, 15, b7 и 95. Thabhairt chun cuimhne gurb iad na trí ghiotán is lú tábhacht an rang teagaisc. Is é ár gcás, tá an ceathrú giotán de na treoracha go léir folamh, mar sin is iad na ranganna teagaisc 7, 5, 7, 5, faoi seach BPF_ALU64, agus tá 5 BPF_JMP. Don dá rang, tá an fhormáid teagaisc mar an gcéanna (féach thuas) agus is féidir linn ár gclár a athscríobh mar seo (ag an am céanna athscríobhfaimid na colúin atá fágtha i bhfoirm dhaonna):

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

Oibríocht b rang ALU64 - An bhfuil BPF_MOV. Sannann sé luach don chlár cinn scríbe. Má tá an giotán socraithe s (foinse), ansin tógtar an luach ón gclár foinse, agus más rud é, mar atá inár gcás, nach bhfuil sé socraithe, ansin tógtar an luach ón réimse Imm. Mar sin sa chéad agus sa tríú treoracha déanaimid an oibríocht r0 = Imm. Thairis sin, tá oibríocht rang 1 JMP BPF_JEQ (léim más ionann é). Is é ár gcás, ós rud é an giotán S náid, cuireann sé luach an chláir foinse i gcomparáid leis an réimse Imm. Má thagann na luachanna i gcomhthráth, ansin tarlaíonn an t-aistriú go PC + OffI gcás ina PC, mar is gnách, ina bhfuil seoladh an chéad teagaisc eile. Ar deireadh, tá Oibríocht Aicme 9 JMP BPF_EXIT. Críochnaíonn an teagasc seo an clár, ag filleadh ar an eithne r0. Cuirimis colún nua lenár tábla:

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

Is féidir linn é seo a athscríobh i bhfoirm níos áisiúla:

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

Más cuimhin linn cad atá sa chlár r1 cuirtear pointeoir chuig an gcomhthéacs ón eithne sa chlár, agus sa chlár r0 cuirtear an luach ar ais chuig an eithne, ansin is féidir linn a fheiceáil má tá an pointeoir chuig an gcomhthéacs náid, ansin filleann muid 1, agus ar shlí eile - 2. Déanaimis seiceáil go bhfuil an ceart againn trí bhreathnú ar an bhfoinse:

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

Sea, is clár gan brí é, ach ní aistrítear ach ceithre threoir shimplí é.

Sampla eisceachta: teagasc 16 beart

Luaigh muid níos luaithe go dtógann roinnt treoracha níos mó ná 64 giotán. Baineann sé seo, mar shampla, le treoracha lddw (Cód = 0x18 = BPF_LD | BPF_DW | BPF_IMM) — lódáil focal dúbailte as na réimsí isteach sa chlár Imm. Is é an fírinne sin Imm tá méid 32 aige, agus is é 64 giotán focal dúbailte, mar sin ní oibreoidh luach láithreach 64-giotán a luchtú isteach i gclár i dtreoir 64-giotán amháin. Chun seo a dhéanamh, úsáidtear dhá threoir in aice láimhe chun an dara cuid den luach 64-giotán a stóráil sa réimse Imm. Sampla:

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

Níl ach dhá threoir i gclár dénártha:

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

Buailfimid arís le treoracha lddw, nuair a labhraímid faoi athlonnú agus oibriú le léarscáileanna.

Sampla: díchóimeáil BPF ag baint úsáide as uirlisí caighdeánacha

Mar sin, ní mór dúinn a fhoghlaim a léamh BPF cóid dénártha agus go bhfuil muid réidh a pharsáil aon treoir más gá. Mar sin féin, is fiú a rá go bhfuil sé níos áisiúla agus níos tapúla cláir a dhíchóimeáil ag baint úsáide as uirlisí caighdeánacha, mar shampla:

$ 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

Saolré rudaí BPF, córas comhaid bpffs

(D'fhoghlaim mé ar dtús roinnt de na sonraí a bhfuil cur síos orthu san fho-alt seo ó an post Alexei Starovoytov saor in aisce, Blag BPF.)

Cruthaítear réada BPF - cláir agus léarscáileanna - ó spás úsáideora ag baint úsáide as orduithe BPF_PROG_LOAD и BPF_MAP_CREATE glao córais bpf(2), beidh muid ag caint faoi go díreach conas a tharlaíonn sé seo sa chéad chuid eile. Cruthaíonn sé seo struchtúir sonraí eithne agus do gach ceann acu refcount (comhaireamh tagartha) socraithe go ceann amháin, agus cuirtear tuairisceoir comhaid a dhíríonn ar an réad ar ais chuig an úsáideoir. Tar éis an láimhseáil a dhúnadh refcount laghdaítear an réad faoi cheann amháin, agus nuair a shroicheann sé nialas, scriostar an réad.

Má úsáideann an clár léarscáileanna, ansin refcount déantar na léarscáileanna seo a mhéadú faoi cheann tar éis an clár a lódáil, i.e. is féidir a dtuairisceoirí comhad a dhúnadh ón bpróiseas úsáideora agus fós refcount ní thiocfaidh chun bheith nialas:

BPF do na cinn beag, cuid a haon: BPF leathnaithe

Tar éis clár a luchtú go rathúil, de ghnáth ní mór dúinn é a cheangal le gineadóir imeacht de chineál éigin. Mar shampla, is féidir linn é a chur ar chomhéadan líonra chun paicéid atá ag teacht isteach a phróiseáil nó é a nascadh le roinnt tracepoint sa chroílár. Ag an bpointe seo, méadóidh an gcuntar tagartha ceann amháin freisin agus beimid in ann an tuairisceoir comhaid a dhúnadh sa chlár lódóra.

Cad a tharlaíonn má dhruidimid an tosaitheoir anois? Braitheann sé ar an gcineál gineadóra imeacht (hook). Beidh gach crúcaí líonra ann tar éis don lódóir a bheith críochnaithe, is iad seo na crúcaí domhanda mar a thugtar orthu. Agus, mar shampla, eiseofar rianchláir tar éis don phróiseas a chruthaigh iad críochnú (agus mar sin tugtar áitiúil orthu, ó “áitiúil go dtí an próiseas”). Go teicniúil, tá tuairisceoir comhaid comhfhreagrach i spás úsáideora ag crúcaí áitiúla i gcónaí agus dá bhrí sin dúnann siad nuair a bhíonn an próiseas dúnta, ach ní dhéanann crúcaí domhanda. San fhigiúr seo a leanas, ag baint úsáide as crosa dearga, déanaim iarracht a thaispeáint conas a théann deireadh leis an gclár lódóra i bhfeidhm ar shaolré rudaí i gcás crúcaí áitiúla agus domhanda.

BPF do na cinn beag, cuid a haon: BPF leathnaithe

Cén fáth a bhfuil idirdhealú idir crúcaí áitiúla agus domhanda? Tá ciall ag rith roinnt cineálacha clár líonra gan spás úsáideora, mar shampla, cosaint DDoS a shamhlú - scríobhann an bootloader na rialacha agus nascann sé an clár BPF leis an gcomhéadan líonra, agus ina dhiaidh sin is féidir leis an bootloader dul agus é féin a mharú. Ar an láimh eile, samhlaigh clár rian dífhabhtaithe a scríobh tú ar do ghlúine i ndeich nóiméad - nuair a bheidh sé críochnaithe, ba mhaith leat nach mbeidh aon truflais fágtha sa chóras, agus cinnteoidh crúcaí áitiúla é sin.

Ar an láimh eile, samhlaigh gur mhaith leat ceangal le rianphointe san eithne agus staitisticí a bhailiú thar na blianta fada. Sa chás seo, ba mhaith leat an chuid úsáideora a chomhlánú agus filleadh ar na staitisticí ó am go chéile. Soláthraíonn an córas comhaid bpf an deis seo. Is córas pseudo-chomhad i gcuimhne amháin é a cheadaíonn comhaid a chruthú a dhéanann tagairt do réada BPF agus a mhéadaíonn ar an gcaoi sin refcount rudaí. Tar éis seo, is féidir leis an lódóir imeacht, agus fanfaidh na rudaí a chruthaigh sé beo.

BPF do na cinn beag, cuid a haon: BPF leathnaithe

Tugtar "pinning" ar chomhaid a chruthú i bpffs a thagraíonn do rudaí BPF (mar atá san abairt seo a leanas: "is féidir le próiseas clár nó léarscáil BPF a phionnú"). Tá ciall ag baint le cruthú réada comhaid le haghaidh rudaí BPF, ní hamháin chun saolré rudaí áitiúla a leathnú, ach freisin maidir le hinúsáidteacht rudaí domhanda - ag dul ar ais go dtí an sampla leis an gclár cosanta domhanda DDoS, ba mhaith linn a bheith in ann teacht agus breathnú ar staitisticí. ó am go chéile.

Is gnách go mbíonn córas comhaid BPF suite i /sys/fs/bpf, ach is féidir é a shuiteáil go háitiúil freisin, mar shampla, mar seo:

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

Cruthaítear ainmneacha córais comhaid leis an ordú BPF_OBJ_PIN Glao ar chóras BPF. Chun é a léiriú, déanaimis clár a ghlacadh, é a thiomsú, é a uaslódáil, agus bioráin chuige bpffs. Ní dhéanann ár gclár aon rud úsáideach, níl ach an cód á chur i láthair againn ionas gur féidir leat an sampla a atáirgeadh:

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

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

Déanaimis an clár seo a thiomsú agus cóip áitiúil den chóras comhaid a chruthú bpffs:

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

Anois, déanaimis ár gclár a íoslódáil ag baint úsáide as an bhfóntas bpftool agus féachaint ar na glaonna córais a théann leo bpf(2) (baintear roinnt línte nach mbaineann le hábhar ón aschur 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

Anseo tá an clár luchtaithe againn ag baint úsáide as BPF_PROG_LOAD, fuair tuairisceoir comhaid ón eithne 3 agus an t-ordú á úsáid BPF_OBJ_PIN phionnáil an tuairisceoir comhaid seo mar chomhad "bpf-mountpoint/test". Tar éis seo an clár bootloader bpftool críochnaithe ag rith, ach d'fhan ár gclár san eithne, cé nár cheangail muid le haon chomhéadan líonra é:

$ 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

Is féidir linn an réad comhaid a scriosadh de ghnáth unlink(2) agus ina dhiaidh sin scriosfar an clár comhfhreagrach:

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

Rudaí á scriosadh

Agus é ag caint faoi rudaí a scriosadh, is gá a shoiléiriú, tar éis dúinn an clár a dhícheangal ón hook (gineadóir imeachtaí), ní spreagfaidh imeacht amháin nua é a sheoladh, áfach, críochnófar gach cás reatha den chlár sa ghnáthordú. .

Ligeann roinnt cineálacha clár BPF duit an clár a athsholáthar ar an eitilt, i.e. adamhacht seicheamh a sholáthar replace = detach old program, attach new program. Sa chás seo, críochnóidh gach cás gníomhach den seanleagan den chlár a gcuid oibre, agus cruthófar láimhseálaithe imeachtaí nua ón gclár nua, agus ciallaíonn “atomicity” anseo nach gcaillfear imeacht amháin.

Cláir a cheangal le foinsí imeachtaí

San Airteagal seo, ní dhéanfaimid cur síos ar leithligh ar chláir a nascadh le foinsí imeachtaí, ós rud é go bhfuil ciall le staidéar a dhéanamh air seo i gcomhthéacs cineál sonrach cláir. Cm. mar shampla thíos, ina léirímid conas atá cláir cosúil le XDP ceangailte.

Réada a Ionramháil Ag Úsáid Glao an Chórais bpf

Cláir BPF

Cruthaítear agus bainistítear gach réad BPF ó spás úsáideora ag baint úsáide as glao córais bpf, ar fíor ina leith an fhréamhshamhail seo a leanas:

#include <linux/bpf.h>

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

Seo an fhoireann cmd ar cheann de na luachanna cineáil enum bpf_cmd, attr — pointeoir do pharaiméadair do chlár sonrach agus size — méid an réad de réir an phointeora, i.e. de ghnáth seo sizeof(*attr). In eithne 5.8 glao an chórais bpf tacaíonn 34 orduithe éagsúla, agus cinneadh de union bpf_attr 200 líne. Ach níor cheart dúinn a bheith imeaglaithe faoi seo, mar beidh muid ag cur amach na horduithe agus paraiméadair thar thréimhse roinnt alt.

Cuirimis tús leis an bhfoireann BPF_PROG_LOAD, a chruthaíonn cláir BPF - glacann sé sraith de threoracha BPF agus é a ualaí isteach san eithne. Faoi láthair an luchtaithe, seoltar an fíoraitheoir, agus ansin cuirtear an tiomsaitheoir JIT agus, tar éis é a fhorghníomhú go rathúil, cuirtear tuairisceoir comhaid an chláir ar ais chuig an úsáideoir. Chonaic muid cad a tharlóidh dó sa roinn roimhe seo faoi ​​shaolré rudaí BPF.

Scríobhfaimid clár saincheaptha anois a luchtóidh clár simplí BPF, ach ar dtús ní mór dúinn cinneadh a dhéanamh cén cineál clár a theastaíonn uainn a luchtú - beidh orainn a roghnú Cineál agus faoi chuimsiú an chineáil seo, clár a scríobh a éireoidh sa tástáil fíoraithe. Mar sin féin, ionas nach gcuirfear casta ar an bpróiseas, seo réiteach réidh: déanfaimid clár cosúil le BPF_PROG_TYPE_XDP, a thabharfaidh an luach ar ais XDP_PASS (scipeáil ar gach pacáiste). I gcóimeálaí BPF tá cuma an-simplí air:

r0 = 2
exit

Tar éis dúinn cinneadh a dhéanamh ar go uaslódálfaimid, is féidir linn a insint duit conas a dhéanfaimid é:

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

Tosaíonn imeachtaí suimiúla i gclár leis an sainmhíniú ar eagar insns - ár gclár BPF i gcód meaisín. Sa chás seo, tá gach treoir den chlár BPF pacáilte isteach sa struchtúr bpf_insn. An chéad eilimint insns chloíonn sé le treoracha r0 = 2, an dara - exit.

Cúlú. Sainmhíníonn an eithne macraí níos áisiúla chun cóid meaisín a scríobh, agus an comhad ceanntásca eithne a úsáid tools/include/linux/filter.h d'fhéadfaimis scríobh

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

Ach ós rud é nach bhfuil gá le cláir BPF a scríobh i gcód dúchais ach amháin le haghaidh tástálacha a scríobh san eithne agus ailt faoi BPF, ní chuireann easpa na macraí seo casta ar shaol an fhorbróra.

Tar éis an clár BPF a shainiú, bogaimid ar aghaidh chun é a luchtú isteach san eithne. Ár sraith íosta de pharaiméadair attr folaíonn sé cineál an chláir, sraith agus líon na dtreoracha, an ceadúnas riachtanach, agus an t-ainm "woo", a úsáidimid chun ár gclár a aimsiú ar an gcóras tar éis é a íoslódáil. Lódáiltear an clár, mar a gealladh, isteach sa chóras ag baint úsáide as glao córais bpf.

Ag deireadh an chláir deireadh muid suas i lúb gan teorainn a insamhladh ar an pálasta. Gan é, maróidh an t-eithne an ríomhchlár nuair a dhúntar an tuairisceoir comhaid a sheol an glao córais ar ais chugainn bpf, agus ní fheicfimid sa chóras é.

Bhuel, táimid réidh le haghaidh tástála. A ligean ar chéile agus a reáchtáil ar an gclár faoi stracea sheiceáil go bhfuil gach rud ag obair mar ba chóir:

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

Tá gach rud breá, bpf(2) ar ais láimhseáil 3 chugainn agus chuaigh muid isteach i lúb gan teorainn le pause(). Déanaimis iarracht ár gclár a aimsiú sa chóras. Chun seo a dhéanamh beidh muid ag dul go dtí críochfort eile agus úsáid a bhaint as an bhfóntas 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)

Feicimid go bhfuil clár luchtaithe ar an gcóras woo a bhfuil a ID domhanda 390 agus atá ar siúl faoi láthair simple-prog tá tuairisceoir comhaid oscailte a dhíríonn ar an gclár (agus má tá simple-prog chríochnóidh an post, ansin woo imeoidh). Mar a bheifí ag súil leis, an clár woo Tógann sé 16 beart - dhá threoir - de chóid dhénártha san ailtireacht BPF, ach ina fhoirm dhúchais (x86_64) tá sé 40 beart cheana féin. Breathnaímis ar ár gclár ina bhunfhoirm:

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

gan aon iontas. Breathnaímid anois ar an gcód a ghineann tiomsaitheoir JIT:

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

nach bhfuil an-éifeachtach le haghaidh exit(2), ach le cothrom na féinne, tá ár gclár ró-shimplí, agus i gcás clár neamhfhánach tá gá, ar ndóigh, leis an réamhrá agus leis an epilogue a chuir tiomsaitheoir JIT leis.

Léarscáileanna

Is féidir le cláir BPF limistéir cuimhne struchtúrtha a úsáid atá inrochtana do chláir BPF eile agus do chláir i spás úsáideoirí. Léarscáileanna a thugtar ar na réada seo agus sa rannán seo taispeánfaimid conas iad a ionramháil le glao córais bpf.

Ligean le rá láithreach nach bhfuil cumais na léarscáileanna teoranta do rochtain ar chuimhne roinnte amháin. Tá léarscáileanna sainchuspóra ann ina bhfuil, mar shampla, leideanna do chláir BPF nó leideanna maidir le comhéadain líonra, léarscáileanna chun oibriú le himeachtaí cumhra, etc. Ní bheidh muid ag caint fúthu anseo, ionas nach gcuirfí amú ar an léitheoir. Seachas sin, déanaimid neamhaird ar shaincheisteanna sioncrónaithe, ós rud é nach bhfuil sé seo tábhachtach dár samplaí. Is féidir liosta iomlán de na cineálacha léarscáileanna atá ar fáil a fháil i <linux/bpf.h>, agus san alt seo tógfaimid mar shampla an chéad chineál stairiúil, an tábla hash BPF_MAP_TYPE_HASH.

Má chruthaíonn tú tábla hash i, abair, C++, déarfá unordered_map<int,long> woo, rud a chiallaíonn i Rúisis “Tá tábla ag teastáil uaim woo méid neamhtheoranta, a bhfuil a n-eochracha den chineál int, agus is iad na luachanna an cineál long" D'fhonn tábla hash BPF a chruthú, ní mór dúinn an rud céanna a dhéanamh i bhfad, ach amháin go gcaithfimid uasmhéid an tábla a shonrú, agus in ionad na cineálacha eochracha agus luachanna a shonrú, ní mór dúinn a méideanna a shonrú i mbearta. . Úsáid an t-ordú chun léarscáileanna a chruthú BPF_MAP_CREATE glao córais bpf. Breathnaímid ar chlár íosta níos mó nó níos lú a chruthaíonn léarscáil. Tar éis an chláir roimhe seo a luchtaíonn cláir BPF, ba cheart go mbeadh an chuma ar an gceann seo simplí duit:

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

Anseo sainímid sraith paraiméadair attr, ina ndeirimid “Tá tábla hash de dhíth orm le heochracha agus luachanna méide sizeof(int), inar féidir liom uasmhéid de cheithre eilimint a chur." Agus léarscáileanna BPF á gcruthú agat, is féidir leat paraiméadair eile a shonrú, mar shampla, ar an mbealach céanna leis an sampla leis an gclár, shonraigh muid ainm an ruda mar "woo".

Déanaimis an clár a thiomsú agus a rith:

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

Seo é an glao córais bpf(2) ar ais chugainn an uimhir léarscáile tuairisceora 3 agus ansin fanann an clár, mar a bhíothas ag súil leis, le tuilleadh treoracha sa ghlao córais pause(2).

Anois cuirimis ár gclár chuig an gcúlra nó osclaíonn muid críochfort eile agus féach ar ár réad ag baint úsáide as an bhfóntas bpftool (is féidir linn ár léarscáil a idirdhealú ó dhaoine eile faoina ainm):

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

Is é an uimhir 114 ID domhanda ár réad. Is féidir le haon ríomhchlár ar an gcóras an t-aitheantas seo a úsáid chun léarscáil atá ann cheana a oscailt leis an ordú BPF_MAP_GET_FD_BY_ID glao córais bpf.

Anois is féidir linn imirt lenár tábla hash. Breathnaímid ar a bhfuil ann:

$ sudo bpftool map dump id 114
Found 0 elements

Folamh. Cuirimis luach ann hash[1] = 1:

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

Breathnaímis ar an mbord arís:

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

Hooray! D’éirigh linn eilimint amháin a chur leis. Tabhair faoi deara go gcaithfimid oibriú ag an leibhéal beart chun é seo a dhéanamh, ós rud é bptftool níl a fhios cén cineál na luachanna atá sa tábla hash. (Is féidir an t-eolas seo a aistriú chuici ag baint úsáide as BTF, ach níos mó air sin anois.)

Conas go díreach a léann agus a chuireann bpftool eilimintí? Breathnaímid faoin gcochall:

$ 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

Ar dtús d'oscail muid an léarscáil ag a ID domhanda ag baint úsáide as an ordú BPF_MAP_GET_FD_BY_ID и bpf(2) ar ais tuairisceoir 3 chugainn BPF_MAP_GET_NEXT_KEY fuaireamar an chéad eochair sa tábla ag rith NULL mar phointeoir don eochair "roimhe". Má tá an eochair againn is féidir linn a dhéanamh BPF_MAP_LOOKUP_ELEMa thugann luach ar ais go pointeoir value. Is é an chéad chéim eile déanaimid iarracht an chéad eilimint eile a aimsiú trí phointeoir a chur chuig an eochair reatha, ach níl ach eilimint amháin inár dtábla agus an t-ordú BPF_MAP_GET_NEXT_KEY filleann ENOENT.

Ceart go leor, déanaimis an luach a athrú le heochair 1, a ligean ar a rá go bhfuil ár loighic gnó ag teastáil chun clárú 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

Mar a bhíothas ag súil, tá sé an-simplí: an t-ordú BPF_MAP_GET_FD_BY_ID osclaíonn ár léarscáil ag ID, agus an t-ordú BPF_MAP_UPDATE_ELEM forscríobhann an eilimint.

Mar sin, tar éis tábla hash a chruthú ó chlár amháin, is féidir linn a bhfuil ann a léamh agus a scríobh ó chlár eile. Tabhair faoi deara má bhí muid in ann é seo a dhéanamh ón líne ordaithe, ansin is féidir le haon ríomhchlár eile ar an gcóras é a dhéanamh. Chomh maith leis na horduithe a thuairiscítear thuas, chun oibriú le léarscáileanna ó spás úsáideora, an méid seo a leanas:

  • BPF_MAP_LOOKUP_ELEM: faigh luach le heochair
  • BPF_MAP_UPDATE_ELEM: nuashonraigh/cruthaigh luach
  • BPF_MAP_DELETE_ELEM: bain eochair
  • BPF_MAP_GET_NEXT_KEY: faigh an chéad (nó an chéad) eochair eile
  • BPF_MAP_GET_NEXT_ID: ligeann sé duit dul tríd na léarscáileanna go léir atá ann cheana féin, sin an chaoi a n-oibríonn sé bpftool map
  • BPF_MAP_GET_FD_BY_ID: léarscáil atá ann cheana a oscailt trína ID domhanda
  • BPF_MAP_LOOKUP_AND_DELETE_ELEM: nuashonraigh luach réada go adamhach agus cuir ar ais an seancheann
  • BPF_MAP_FREEZE: déan an léarscáil a athrú ó spás úsáideora (ní féidir an oibríocht seo a chealú)
  • BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, BPF_MAP_UPDATE_BATCH, BPF_MAP_DELETE_BATCH: olloibríochtaí. Mar shampla, BPF_MAP_LOOKUP_AND_DELETE_BATCH - is é seo an t-aon bhealach iontaofa chun gach luach ón léarscáil a léamh agus a athshocrú

Ní oibríonn na horduithe seo go léir do gach cineál léarscáile, ach go ginearálta tá an chuma ar an scéal go n-oibríonn oibriú le cineálacha eile léarscáileanna ó spás úsáideora agus oibriú le táblaí hash.

Ar mhaithe le hordú, déanaimis ár dturgnaimh tábla hash a chríochnú. Cuimhnigh gur chruthaigh muid tábla a bhfuil suas le ceithre eochair ann? Cuirimis cúpla eilimint eile leis:

$ 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

Go dtí seo chomh maith:

$ 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

Déanaimis iarracht ceann amháin eile a chur leis:

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

Mar a bheifí ag súil leis, níor éirigh linn. Breathnaímid ar an earráid níos mine:

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

Tá gach rud go breá: mar a bhíothas ag súil leis, an fhoireann BPF_MAP_UPDATE_ELEM iarracht a chruthú nua, cúigiú, eochair, ach tuairteanna E2BIG.

Mar sin, is féidir linn cláir BPF a chruthú agus a luchtú, chomh maith le léarscáileanna a chruthú agus a bhainistiú ó spás úsáideoirí. Anois tá sé loighciúil féachaint ar conas is féidir linn léarscáileanna ó na cláir BPF iad féin a úsáid. D'fhéadfaimis labhairt faoi seo i dteanga na gclár atá deacair le léamh i gcód macra meaisín, ach i ndáiríre tá an t-am tagtha chun a thaispeáint conas a dhéantar cláir BPF a scríobh agus a chothabháil i ndáiríre - ag baint úsáide as libbpf.

(Do léitheoirí atá míshásta leis an easpa sampla ísealleibhéil: déanfaimid anailís mhionsonraithe ar chláir a úsáideann léarscáileanna agus feidhmeanna cúnta a chruthaítear ag baint úsáide as libbpf agus a insint duit cad a tharlaíonn ag an leibhéal teagaisc. Do léitheoirí atá míshásta an, chuireamar mar shampla san áit chuí san alt.)

Cláir BPF a scríobh ag baint úsáide as libbpf

Is féidir le cláir BPF a scríobh ag baint úsáide as cóid mheaisín a bheith suimiúil ach an chéad uair, agus ansin cuireann satiety isteach. Ag an nóiméad seo ní mór duit d'aird a dhíriú ar llvm, a bhfuil inneall aige chun cód a ghiniúint don ailtireacht BPF, chomh maith le leabharlann libbpf, a ligeann duit a scríobh ar an taobh úsáideora na n-iarratas BPF agus luchtú an cód cláir BPF a ghintear ag baint úsáide as llvm/clang.

Go deimhin, mar a fheicfimid san alt seo agus ina dhiaidh sin, libbpf a dhéanann go leor oibre gan é (nó uirlisí comhchosúla - iproute2, libbcc, libbpf-go, etc.) go bhfuil sé dodhéanta maireachtáil. Ceann de na gnéithe killer an tionscadail libbpf is BPF CO-RE (Compile Once, Run Everywhere) - tionscadal a ligeann duit cláir BPF a scríobh atá iniompartha ó eithne amháin go ceann eile, leis an gcumas reáchtáil ar APIanna éagsúla (mar shampla, nuair a athraíonn an struchtúr eithne ón leagan a leagan). Chun a bheith in ann oibriú le CO-RE, ní mór d'eithne a thiomsú le tacaíocht BTF (cuirimid síos ar conas é seo a dhéanamh sa rannán Uirlisí Forbartha. Is féidir leat a sheiceáil cibé an bhfuil do eithne tógtha le BTF nó nach bhfuil - trí láithreacht an chomhaid seo a leanas:

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

Stórálann an comhad seo faisnéis faoi gach cineál sonraí a úsáidtear san eithne agus úsáidtear é inár samplaí go léir ag baint úsáide as libbpf. Déanfaimid labhairt go mion faoi CO-RE san alt seo chugainn, ach sa cheann seo - ach a thógáil duit féin eithne le CONFIG_DEBUG_INFO_BTF.

leabharlann libbpf ina chónaí ceart san eolaire tools/lib/bpf eithne agus déantar é a fhorbairt tríd an liosta postála bpf@vger.kernel.org. Mar sin féin, coimeádtar stór ar leith do riachtanais na n-iarratas a chónaíonn lasmuigh den eithne https://github.com/libbpf/libbpf ina bhfuil an leabharlann eithne scáthánaithe le haghaidh rochtain léite níos mó nó níos lú mar atá.

Sa chuid seo féachfaimid ar conas is féidir leat tionscadal a chruthú a úsáideann libbpf, scríobhaimis roinnt clár tástála (níos mó nó níos lú gan brí) agus déanaimis anailís mhionsonraithe ar conas a oibríonn sé go léir. Tabharfaidh sé seo deis dúinn a mhíniú níos éasca sna hailt seo a leanas go beacht conas a idirghníomhaíonn cláir BPF le léarscáileanna, cúntóirí eithne, BTF, etc.

De ghnáth tionscadail ag baint úsáide as libbpf cuir stór GitHub leis mar fhomhodúl git, déanfaimid an rud céanna:

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

Ag dul go dtí libbpf an-simplí:

$ 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

Seo a leanas an chéad phlean eile atá againn sa chuid seo: scríobhfaimid clár BPF mar BPF_PROG_TYPE_XDP, mar an gcéanna leis an sampla roimhe seo, ach i C, déanaimid é a thiomsú ag baint úsáide as clang, agus scríobh clár cúntóra a luchtóidh isteach san eithne é. Sna hailt seo a leanas leathnóimid cumais an chláir BPF agus an chláir chúntóra araon.

Sampla: feidhmchlár lánchuimsitheach a chruthú ag baint úsáide as libbpf

Chun tús a chur leis, úsáidimid an comhad /sys/kernel/btf/vmlinux, a luadh thuas, agus cruthaigh a choibhéis i bhfoirm ceanntásc:

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

Stórálfaidh an comhad seo na struchtúir sonraí go léir atá ar fáil inár n-eithne, mar shampla, seo mar a shainmhínítear an ceanntásc IPv4 san eithne:

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

Anois scríobhfaimid ár gclár BPF i 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";

Cé go raibh ár gclár an-simplí, ní mór dúinn fós aird a thabhairt ar go leor sonraí. Ar dtús, is é an chéad chomhad ceanntásc a chuirimid san áireamh vmlinux.h, rud a ghin muid díreach ag baint úsáide as bpftool btf dump - anois ní gá dúinn an pacáiste ceanntásca eithne a shuiteáil chun a fháil amach cén chuma atá ar na struchtúir eithne. Tagann an ceanntásc seo a leanas chugainn ón leabharlann libbpf. Anois ní gá dúinn ach é chun an macra a shainiú SEC, a sheolann an carachtar chuig an gcuid cuí de chomhad oibiachta ELF. Tá ár gclár le fáil sa rannóg xdp/simple, áit roimh an slaise a shainímid an cineál cláir BPF - is é seo an coinbhinsiún a úsáidtear i libbpf, bunaithe ar ainm na rannóige cuirfidh sé an cineál ceart in ionad an am tosaithe bpf(2). Tá an clár BPF féin C - an-simplí agus comhdhéanta de líne amháin return XDP_PASS. Ar deireadh, alt ar leith "license" ina bhfuil ainm an cheadúnais.

Is féidir linn ár gclár a thiomsú ag úsáid llvm/clang, leagan >= 10.0.0, nó níos fearr fós, níos mó (féach an chuid Uirlisí Forbartha):

$ 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

I measc na gnéithe suimiúla: in iúl dúinn an ailtireacht sprioc -target bpf agus an cosán go dtí na ceanntásca libbpf, a chuireamar isteach le déanaí. Chomh maith leis sin, ná déan dearmad faoi -O2, gan an rogha seo is féidir go mbeidh iontas ort amach anseo. Breathnaímid ar ár gcód, ar éirigh linn an clár a bhí uainn a scríobh?

$ 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

Sea, d'oibrigh sé! Anois, tá comhad dénártha againn leis an gclár, agus ba mhaith linn feidhmchlár a chruthú a luchtóidh isteach san eithne é. Chun na críche seo an leabharlann libbpf cuireann sé dhá rogha ar fáil dúinn - úsáid API leibhéal níos ísle nó API ardleibhéil. Rachaimid an dara bealach, ós rud é go dteastaíonn uainn foghlaim conas cláir BPF a scríobh, a luchtú agus a nascadh le hiarracht íosta dá staidéar ina dhiaidh sin.

Ar dtús, ní mór dúinn “cnámharlach” ár gclár a ghiniúint óna dhénártha ag baint úsáide as an bhfóntas céanna bpftool - scian na hEilvéise ar fud an domhain BPF (is féidir a ghlacadh go litriúil, ós rud é go bhfuil Daniel Borkman, duine de chruthaitheoirí agus chothabhálaithe BPF, na hEilvéise):

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

I gcomhad xdp-simple.skel.h ina bhfuil cód dénártha ár gclár agus feidhmeanna chun bainistíocht a dhéanamh - ár réad a luchtú, a cheangal, a scriosadh. In ár gcás simplí tá cuma overkill air seo, ach oibríonn sé freisin sa chás go bhfuil go leor clár agus léarscáileanna BPF sa chomhad réad agus chun an fathach ELF seo a luchtú ní mór dúinn ach an creatlach a ghiniúint agus feidhm nó dhó a ghlaoch ón bhfeidhmchlár saincheaptha. ag scríobh Bogaimis ar aghaidh anois.

Go fírinneach, is fánach ár gclár lódóra:

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

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

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

    pause();

    xdp_simple_bpf__destroy(obj);
}

Anseo struct xdp_simple_bpf sainithe sa chomhad xdp-simple.skel.h agus déanann sé cur síos ar ár gcomhad oibiachta:

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

Is féidir linn rianta de API íseal-leibhéil a fheiceáil anseo: an struchtúr struct bpf_program *simple и struct bpf_link *simple. Déanann an chéad struchtúr cur síos go sonrach ar ár gclár, atá scríofa sa chuid xdp/simple, agus déanann an dara ceann cur síos ar an gcaoi a nascann an clár le foinse an imeachta.

Feidhm xdp_simple_bpf__open_and_load, osclaíonn réad ELF, parsálann sé, cruthaíonn sé na struchtúir agus na fo-struchtúir go léir (seachas an clár, tá rannóga eile ag ELF freisin - sonraí, sonraí inléite amháin, faisnéis dífhabhtaithe, ceadúnas, etc.), agus ansin é a luchtú isteach san eithne ag baint úsáide as córas glaoch bpf, ar féidir linn a sheiceáil tríd an gclár a thiomsú agus a rith:

$ 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

A ligean ar breathnú anois ar ár gclár ag baint úsáide as bpftool. Faighimis a haitheantas:

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

agus dumpáil (úsáidimid foirm ghiorraithe den ordú bpftool prog dump xlated):

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

Rud nua! Phriontáil an clár píosaí dár gcomhad foinse C. Rinne an leabharlann é seo libbpf, a d'aimsigh an chuid dífhabhtaithe sa dhénártha, thiomsaigh sé isteach i réad BTF é, lódáil isteach san eithne é ag baint úsáide as BPF_BTF_LOAD, agus ansin shonraigh an tuairisceoir comhaid a bhí mar thoradh air agus an clár á luchtú leis an ordú BPG_PROG_LOAD.

Cúntóirí Eithne

Is féidir le cláir BPF feidhmeanna “seachtracha” a rith - cúntóirí eithne. Ligeann na feidhmeanna cúntóra seo do chláir BPF rochtain a fháil ar struchtúir eithne, léarscáileanna a bhainistiú, agus cumarsáid a dhéanamh leis an “fíorshaol” - imeachtaí perf a chruthú, crua-earraí rialaithe (mar shampla, paicéid a atreorú), etc.

Sampla: bpf_get_smp_processor_id

Faoi chuimsiú na paraidím “foghlaim trí shampla”, déanaimis machnamh ar cheann de na feidhmeanna cúntóra, bpf_get_smp_processor_id(), áirithe i gcomhad kernel/bpf/helpers.c. Filleann sé uimhir an phróiseálaí ar a bhfuil an clár BPF a thug air. Ach níl an oiread sin suime againn ina shéimeantaic mar go bhfuil líne amháin ag baint lena chur i bhfeidhm:

BPF_CALL_0(bpf_get_smp_processor_id)
{
    return smp_processor_id();
}

Tá sainmhínithe feidhm chúnta BPF cosúil le sainmhínithe glaonna córais. LinuxAnseo, mar shampla, sainmhínítear feidhm nach bhfuil aon argóintí aici. (Sainmhínítear feidhm a ghlacann, abair, trí argóint ag baint úsáide as macra BPF_CALL_3. Is é an t-uaslíon argóintí ná cúig.) Níl anseo, áfach, ach an chéad chuid den sainmhíniú. Is é an dara cuid an struchtúr cineál a shainiú struct bpf_func_proto, ina bhfuil cur síos ar fheidhm an chúntóra a thuigeann an fíoraitheoir:

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

Feidhmeanna Cúntóra a Chlárú

Ionas go bhféadfaidh cláir BPF de chineál áirithe an fheidhm seo a úsáid, ní mór dóibh é a chlárú, mar shampla don chineál BPF_PROG_TYPE_XDP sainmhínítear feidhm san eithne xdp_func_proto, a chinneann ó ID feidhm an chúntóra cibé an dtacaíonn XDP leis an bhfeidhm seo nó nach dtacaíonn. Is é an fheidhm atá againn tacaíochtaí:

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

Tá cineálacha nua clár BPF "sainithe" sa chomhad include/linux/bpf_types.h ag baint úsáide as macra BPF_PROG_TYPE. Sainmhínítear é i Sleachta toisc gur sainmhíniú loighciúil é, agus i dtéarmaí teanga C tarlaíonn sainmhíniú ar shraith iomlán de struchtúir nithiúla in áiteanna eile. Go háirithe, sa chomhad kernel/bpf/verifier.c gach sainmhíniú ó chomhad bpf_types.h úsáidtear iad chun sraith struchtúr a chruthú 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
};

Is é sin, le haghaidh gach cineál cláir BPF, sainmhínítear pointeoir chuig struchtúr sonraí den chineál struct bpf_verifier_ops, a thosaítear leis an luach _name ## _verifier_ops, i.e., xdp_verifier_ops le haghaidh xdp. Struchtúr xdp_verifier_ops cinnte i gcomhad net/core/filter.c ar an mbealach seo a leanas:

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

Anseo feicimid ár bhfeidhm eolach xdp_func_proto, a reáchtálfaidh an fíoraitheoir gach uair a thagann sé ar dhúshlán roinnt feidhmeanna taobh istigh de chlár BPF, féach verifier.c.

Breathnaímid ar conas a úsáideann clár BPF hipitéiseach an fheidhm bpf_get_smp_processor_id. Chun seo a dhéanamh, déanaimid an clár a athscríobh ón rannóg roimhe seo mar seo a leanas:

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

Siombail bpf_get_smp_processor_id cinnte в <bpf/bpf_helper_defs.h> leabharlanna libbpf как

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

Is é sin, bpf_get_smp_processor_id is pointeoir feidhme é a bhfuil a luach 8, áit arb é 8 an luach BPF_FUNC_get_smp_processor_id типа enum bpf_fun_id, atá sainmhínithe dúinn sa chomhad vmlinux.h (comhad bpf_helper_defs.h sa eithne a ghintear le script, mar sin tá na "draíochta" uimhreacha ceart go leor). Ní ghlacann an fheidhm seo le hargóintí agus cuireann sé luach cineáil ar ais __u32. Nuair a rithimid é inár gclár, clang gineann treoir BPF_CALL "an cineál ceart" Déanaimis an clár a thiomsú agus breathnú ar an alt xdp/simple:

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

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

Disassembly of section xdp/simple:

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

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

Sa chéad líne feicimid treoracha call, paraiméadar IMM atá comhionann le 8, agus SRC_REG - nialas. De réir an chomhaontaithe ABI a úsáideann fíoraitheoir, is feidhm glao chuig cúntóir uimhir a hocht é seo. Nuair a sheoltar é, tá an loighic simplí. An luach a thabhairt ar ais ón gclár r0 chóipeáil go r1 agus ar línte 2,3 déantar é a thiontú go cineál u32 — glantar na 32 giotán uachtaracha. Ar línte 4,5,6,7 filleann muid 2 (XDP_PASS) nó 1(XDP_DROP) ag brath ar cibé ar thug feidhm an chúntóra ó líne 0 luach nialasach nó luach neamh-nialais.

Déanaimis sinn féin a thástáil: an clár a luchtú agus breathnú ar an aschur 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

Ceart go leor, fuair an fíoraitheoir an cúntóir eithne ceart.

Sampla: argóintí a rith agus ar deireadh an clár a rith!

Tá fréamhshamhail ag gach feidhm cúntóir leibhéal reatha

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

Cuirtear paraiméadair chuig feidhmeanna cúntóirí ar aghaidh sna cláir r1-r5, agus cuirtear an luach ar ais sa chlár r0. Níl aon fheidhmeanna ann a ghlacann níos mó ná cúig argóint, agus níltear ag súil go gcuirfear tacaíocht ar fáil dóibh amach anseo.

Breathnaímid ar an cúntóir eithne nua agus conas a théann BPF thar pharaiméadair. Déanaimis athscríobh xdp-simple.bpf.c mar seo a leanas (níl aon athrú ar an gcuid eile de na línte):

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

Priontaí ár gclár uimhir an LAP ar a bhfuil sé ag rith. Déanaimis é a thiomsú agus breathnú ar an gcód:

$ 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

I línte 0-7 scríobhaimid an teaghrán running on CPU%un, agus ansin ar líne 8 ritheann muid an ceann eolach bpf_get_smp_processor_id. Ar línte 9-12 ullmhaímid argóintí an chúntóra bpf_printk - cláir r1, r2, r3. Cén fáth go bhfuil trí cinn acu agus nach bhfuil dhá? Mar bpf_printkis fillteán macra é seo timpeall an cúntóir fíor bpf_trace_printk, a chaithfidh méid an teaghrán formáid a phasáil.

Cuirimis anois cúpla líne le xdp-simple.cionas go nascann ár gclár leis an gcomhéadan lo agus thosaigh i ndáiríre!

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

Anseo úsáidimid an fheidhm bpf_set_link_xdp_fd, a nascann cláir BPF de chineál XDP le comhéadain líonra. Rinneamar uimhir an chomhéadain a chódú crua lo, atá i gcónaí 1. Rithimid an fheidhm faoi dhó chun an seanchlár a dhícheangal ar dtús má bhí sé ceangailte. Tabhair faoi deara nach bhfuil dúshlán ag teastáil uainn anois pause nó lúb gan teorainn: scoirfidh ár gclár lódóra, ach ní marófar an clár BPF ós rud é go bhfuil sé ceangailte le foinse an imeachta. Tar éis íoslódáil agus nasc rathúil, seolfar an clár le haghaidh gach paicéad líonra a thagann chuig lo.

A ligean ar a íoslódáil an clár agus breathnú ar an comhéadan 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

Tá ID 669 ag an gclár a d'íoslódálamar agus feicimid an t-aitheantas céanna ar an gcomhéadan lo. Seolfaimid cúpla pacáiste chuig 127.0.0.1 (iarratas + freagra):

$ ping -c1 localhost

agus anois déanaimis féachaint ar a bhfuil sa chomhad fíorúil dífhabhtaithe /sys/kernel/debug/tracing/trace_pipe, ina bhfuil bpf_printk scríobhann sé a chuid teachtaireachtaí:

# 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

Chonacthas dhá phacáiste ar lo agus próiseáilte ar CPU0 - d'oibrigh ár gcéad chlár iomlán BPF gan bhrí!

Is fiú é sin a thabhairt faoi deara bpf_printk Ní hé seo an rud a scríobhann sé chuig an gcomhad dífhabhtaithe: ní hé seo an cúntóir is rathúla le húsáid i dtáirgeadh, ach ba é an sprioc a bhí againn rud éigin simplí a thaispeáint.

Rochtain a fháil ar léarscáileanna ó chláir BPF

Sampla: ag baint úsáide as léarscáil ón gclár BPF

Sna hailt roimhe seo d'fhoghlaimíomar conas léarscáileanna a chruthú agus a úsáid ó spás úsáideora, agus anois déanaimis féachaint ar an gcuid eithne. Let tús, mar is gnách, le sampla. Déanaimis ár gclár a athscríobh xdp-simple.bpf.c ar an mbealach seo a leanas:

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

Ag tús an chláir chuireamar sainmhíniú léarscáile leis woo: Seo eagar 8-eilimint a stórálann luachanna mar u64 (i C thabharfaimis eagar den sórt sin mar u64 woo[8]). I gclár "xdp/simple" cuirimid uimhir an phróiseálaí reatha in athróg key agus ansin an fheidhm cúntóir a úsáid bpf_map_lookup_element Faighimid pointeoir don iontráil chomhfhreagrach san eagar, a mhéadaímid faoi cheann amháin. Aistrithe go Rúisis: ríomhaimid staitisticí ar ar phróiseáil LAP paicéid isteach. Déanaimis iarracht an clár a rith:

$ 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

A ligean ar a sheiceáil go bhfuil sí hooked suas go dtí lo agus seol roinnt paicéid:

$ 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

Anois breathnaímid ar a bhfuil san eagar:

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

Rinneadh beagnach gach próiseas a phróiseáil ar CPU7. Níl sé seo tábhachtach dúinn, is é an rud is mó go n-oibríonn an clár agus tuigimid conas teacht ar léarscáileanna ó chláir BPF - ag baint úsáide as хелперов bpf_mp_*.

Innéacs mystical

Mar sin, is féidir linn rochtain a fháil ar an léarscáil ón gclár BPF ag baint úsáide as glaonna mar

val = bpf_map_lookup_elem(&woo, &key);

áit a bhfuil cuma an fheidhm chúntóra

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

ach táimid ag dul thar pointeoir &woo le struchtúr gan ainm struct { ... }...

Má táimid ar an cóimeálaí clár, feicimid go bhfuil an luach &woo nach bhfuil sainmhínithe i ndáiríre (líne 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
...

agus tá sé le fáil in athlonnú:

$ 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

Ach má bhreathnaíonn muid ar an gclár atá luchtaithe cheana féin, feicimid pointeoir don léarscáil cheart (líne 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]
...

Mar sin, is féidir linn a thabhairt i gcrích, ag an am a seoladh ár gclár loader, an nasc chuig &woo Cuireadh rud éigin le leabharlann ina ionad libbpf. Ar dtús féachfaimid ar an aschur 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

Feicimid é sin libbpf chruthaigh léarscáil woo agus ansin íoslódáil ár gclár simple. Breathnaímid ar an gcaoi a lódálaimid an clár:

  • glaoch xdp_simple_bpf__open_and_load ó chomhad xdp-simple.skel.h
  • a chuireann faoi deara xdp_simple_bpf__load ó chomhad xdp-simple.skel.h
  • a chuireann faoi deara bpf_object__load_skeleton ó chomhad libbpf/src/libbpf.c
  • a chuireann faoi deara bpf_object__load_xattr de libbpf/src/libbpf.c

Glaofaidh an fheidhm dheireanach, i measc rudaí eile bpf_object__create_maps, a chruthaíonn nó a osclaíonn léarscáileanna atá ann cheana féin, agus iad á gcur ina dtuairisceoirí comhaid. (Seo é an áit a bhfeicimid BPF_MAP_CREATE san aschur strace.) Ansin tugtar an fheidhm bpf_object__relocate agus is í is spéis linn, mar is cuimhin linn an méid a chonaiceamar woo sa tábla athlonnaithe. Agus é á iniúchadh, aimsímid ar deireadh thiar san fheidhm bpf_program__relocate, a déileálann sé le hathlonnú léarscáileanna:

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

Mar sin glacaimid ár dtreoracha

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

agus ionad an chláir foinse atá ann BPF_PSEUDO_MAP_FD, agus an chéad IMM chuig tuairisceoir comhaid ár léarscáile agus, má tá sé comhionann le, mar shampla, 0xdeadbeef, ansin mar thoradh air sin gheobhaidh muid an teagasc

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

Seo mar a aistrítear faisnéis léarscáile chuig clár BPF lódáilte ar leith. Sa chás seo, is féidir an léarscáil a chruthú ag baint úsáide as BPF_MAP_CREATE, agus d'oscail ID ag baint úsáide as BPF_MAP_GET_FD_BY_ID.

Iomlán, nuair a úsáid libbpf Seo a leanas an t-algartam:

  • le linn tiomsaithe, cruthaítear taifid sa tábla athlonnaithe le haghaidh naisc chuig léarscáileanna
  • libbpf osclaíonn sé leabhar oibiachtaí ELF, aimsíonn sé gach léarscáil a úsáideadh agus cruthaíonn sé tuairisceoirí comhaid dóibh
  • luchtaítear tuairisceoirí comhaid isteach san eithne mar chuid den treoir LD64

Mar is féidir leat a shamhlú, tá níos mó le teacht agus beidh orainn féachaint isteach sa chroílár. Ar ámharaí an tsaoil, tá clue againn - tá an bhrí scríofa síos againn BPF_PSEUDO_MAP_FD isteach sa chlár foinse agus is féidir linn é a adhlacadh, rud a thabharfaidh chun naofa na naomh uile sinn - kernel/bpf/verifier.c, i gcás ina gcuirtear seoladh struchtúir cineáil in ionad tuairisceoir comhaid 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;

(Is féidir cód iomlán a fháil по ссылке). Mar sin is féidir linn ár n-algartam a leathnú:

  • Agus an clár á luchtú, seiceann an fíoraitheoir úsáid cheart na léarscáile agus scríobhann sé seoladh an struchtúir chomhfhreagrach struct bpf_map

Nuair a íoslódáil an dénártha ELF ag baint úsáide as libbpf Tá go leor eile ar siúl, ach pléifimid é sin in ailt eile.

Íoslódáil cláir agus léarscáileanna gan libpf

Mar a gealladh, seo sampla do léitheoirí atá ag iarraidh a fháil amach conas a chruthú agus a luchtú clár a úsáideann léarscáileanna, gan chabhair libbpf. Féadfaidh sé seo a bheith úsáideach agus tú ag obair i dtimpeallacht nach féidir leat spleáchais a thógáil dó, nó gach beagán a shábháil, nó nuair atá tú ag scríobh clár mar ply, a ghineann cód dénártha BPF ar an eitilt.

Chun é a dhéanamh níos éasca an loighic a leanúint, athscríobhfaimid ár sampla chun na gcríoch sin xdp-simple. Is féidir cód iomlán agus beagán leathnaithe an chláir a phléitear sa sampla seo a fháil anseo giosta.

Seo a leanas loighic ár n-iarratas:

  • cruthaigh léarscáil cineáil BPF_MAP_TYPE_ARRAY ag baint úsáide as an ordú BPF_MAP_CREATE,
  • clár a chruthú a úsáideann an léarscáil seo,
  • ceangal an clár leis an gcomhéadan lo,

a aistríonn go daonna mar

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

Anseo map_create cruthaíonn sé léarscáil ar an mbealach céanna agus a rinne muid sa chéad sampla faoin nglao córais bpf - “eithne, le do thoil déan léarscáil nua dom i bhfoirm sraithe de 8 eilimint mar __u64 agus tabhair tuairisceoir an chomhaid ar ais dom":

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

Tá an clár éasca le luchtú freisin:

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

An chuid tricky prog_load an sainmhíniú ar ár gclár BPF mar raon struchtúr struct bpf_insn insns[]. Ach ós rud é go bhfuil muid ag baint úsáide as clár atá againn i C, is féidir linn a cheat beagán:

$ 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

San iomlán, ní mór dúinn 14 treoracha a scríobh i bhfoirm struchtúir cosúil le struct bpf_insn (comhairle: tóg an Dumpáil ó thuas, léigh an chuid treoracha arís, oscail linux/bpf.h и linux/bpf_common.h agus iarracht a dhéanamh a chinneadh struct bpf_insn insns[] leat féin):

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

Cleachtadh dóibh siúd nár scríobh é seo iad féin - aimsigh map_fd.

Tá cuid amháin eile gan nochtadh inár gclár - xdp_attach. Ar an drochuair, ní féidir cláir mar XDP a nascadh le glao córais bpfBa as an bpobal ar líne na daoine a chruthaigh BPF agus XDP. Linux, rud a chiallaíonn gur úsáid siad an ceann ba mhó a raibh cur amach acu air (ach ní le haghaidh gnáth daoine) comhéadan chun idirghníomhú leis an eithne: soicéid netlink, Féach freisin RFC3549. An bealach is simplí a chur i bhfeidhm xdp_attach ag cóipeáil cód ó libbpf, eadhon, ón gcomhad netlink.c, a rinne muid, é a ghiorrú beagán:

Fáilte chuig saol na soicéid netlink

Oscail cineál soicéad 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;
}

Léimid ón soicéad seo:

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

Ar deireadh, seo an fheidhm atá againn a osclaíonn soicéad agus a sheolann teachtaireacht speisialta chuige ina bhfuil tuairisceoir comhaid:

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

Mar sin, tá gach rud réidh le haghaidh tástála:

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

A ligean ar a fheiceáil má tá ár gclár nasctha le 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

Seolfaimid pings agus breathnóimid ar an léarscáil:

$ 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, oibríonn gach rud. Tabhair faoi deara, dála an scéil, go bhfuil ár léarscáil ar taispeáint arís i bhfoirm beart. Tá sé seo mar gheall ar an bhfíric go bhfuil, murab ionann agus libbpf níor lódálamar faisnéis chineáil (BTF). Ach labhróimid níos mó faoi seo an chéad uair eile.

Uirlisí Forbartha

Sa chuid seo, féachfaimid ar an íosmhéid uirlisí d’fhorbróirí BPF.

Go ginearálta, ní bhíonn aon rud speisialta ag teastáil uait chun cláir BPF a fhorbairt - ritheann BPF ar aon eithne dáilte réasúnta, agus baintear úsáid as cláir a thógáil clang, is féidir a sholáthar ón bpacáiste. Mar sin féin, toisc go bhfuil BPF á fhorbairt, tá an eithne agus na huirlisí ag athrú i gcónaí, mura bhfuil tú ag iarraidh cláir BPF a scríobh ag baint úsáide as modhanna sean-aimseartha ó 2019, ansin beidh ort a thiomsú.

  • llvm/clang
  • pahole
  • a chroí
  • bpftool

(Mar thagairt: rinneadh an chuid seo agus na samplaí uile san alt a rith ar Debian 10.)

llvm/clag

Tá BPF cairdiúil le LLVM agus, cé gur féidir cláir do BPF a chur le chéile le déanaí ag baint úsáide as gcc, déantar an fhorbairt reatha ar fad do LLVM. Dá bhrí sin, ar an gcéad dul síos, tógfaimid an leagan reatha clang ó 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
... много времени спустя
$

Anois is féidir linn a sheiceáil ar tháinig gach rud le chéile i gceart:

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

(Treoracha tionóil clang tógtha ag dom ó bpf_devel_QA.)

Ní shuiteálfaimid na cláir a thógamar díreach, ach ina ionad sin cuirfimid leis iad PATH, mar shampla:

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

(Is féidir cur leis seo .bashrc nó chuig comhad ar leith. Go pearsanta, cuirim rudaí mar seo le ~/bin/activate-llvm.sh agus nuair is gá déanaim é . activate-llvm.sh.)

Pahole agus BTF

Fóntais pahole a úsáidtear agus an t-eithne á thógáil chun faisnéis dífhabhtaithe a chruthú i bhformáid BTF. Ní rachaimid isteach go mion san Airteagal seo faoi mhionsonraí teicneolaíocht BTF, seachas an bhfíric go bhfuil sé áisiúil agus ba mhaith linn é a úsáid. Mar sin má tá tú chun do eithne a thógáil, tóg ar dtús pahole (gan pahole ní bheidh tú in ann an eithne a thógáil leis an rogha 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

Eithne chun triail a bhaint as BPF

Agus féidearthachtaí BPF á bhfiosrú agam, ba mhaith liom mo chroílár féin a chur le chéile. Ní gá é seo, go ginearálta, ós rud é go mbeidh tú in ann cláir BPF a thiomsú agus a luchtú ar an eithne dáileacháin, áfach, má tá d’eithne féin agat is féidir leat na gnéithe BPF is déanaí a úsáid, a thaispeánfar i do dháileadh sna míonna is fearr. , nó, mar atá i gcás roinnt uirlisí dífhabhtaithe, ní dhéanfar iad a phacáistiú ar chor ar bith sa todhchaí intuartha. Chomh maith leis sin, mothaíonn a chroílár féin go bhfuil sé tábhachtach triail a bhaint as an gcód.

Chun eithne a thógáil is gá duit, ar an gcéad dul síos, an t-eithne féin, agus sa dara háit, comhad cumraíochta eithne. Chun triail a bhaint as BPF is féidir linn úsáid a bhaint as an gnáth vanilla croí nó ceann de chroílár an fhorbróra. Go stairiúil, tharla forbairt BPF laistigh den phobal líonra. Linux agus dá bhrí sin téann gach athrú luath nó mall trí David Miller, cothabhálaí an líonra LinuxAg brath ar a nádúr—socruithe nó gnéithe nua—críochnaíonn athruithe líonra i gceann amháin de dhá chroílár: netnet-next. Déantar athruithe do BPF a dháileadh ar an mbealach céanna idir bpf и bpf-next, a chomhthiomsaítear ansin ina líontán agus ina nglan-chéad, faoi seach. Le haghaidh tuilleadh sonraí, féach bpf_devel_QA и netdev-FAQ. Mar sin roghnaigh eithne bunaithe ar do bhlas agus ar riachtanais chobhsaíochta an chórais a bhfuil tú ag tástáil air (*-next eithne na cinn is éagobhsaí díobh siúd atá liostaithe).

Tá sé lasmuigh de raon feidhme an ailt seo labhairt faoi conas comhaid cumraíochta eithne a bhainistiú - glactar leis go bhfuil a fhios agat cheana féin conas é seo a dhéanamh, nó réidh le foghlaim ar duine féin. Mar sin féin, ba cheart go mbeadh na treoracha seo a leanas a bheag nó a mhór go leor chun córas oibre BPF-chumasaithe a thabhairt duit.

Íoslódáil ceann de na kernels thuas:

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

Tóg cumraíocht eithne íosta oibre:

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

Cumasaigh roghanna BPF sa chomhad .config de do rogha féin (is dócha CONFIG_BPF cumasaithe cheana féin ó úsáideann systemd é). Seo liosta de na roghanna ón eithne a úsáidtear don alt seo:

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

Ansin is féidir linn na modúil agus an eithne a chóimeáil agus a shuiteáil go héasca (dála an scéil, is féidir leat an eithne a chur le chéile ag baint úsáide as an nua-chéile clangag cur CC=clang):

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

agus atosaigh leis an eithne nua (úsáidim le haghaidh seo kexec as an bpacáiste 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

Is é an fóntais is coitianta a úsáidtear san alt ná an áirgiúlacht bpftool, arna sholáthar mar chuid den eithne LinuxScríobhann agus cothabhálann forbróirí BPF é do fhorbróirí BPF agus is féidir é a úsáid chun gach cineál réad BPF a bhainistiú—cláir a luchtú, léarscáileanna a chruthú agus a mhodhnú, éiceachóras BPF a iniúchadh, agus níos mó. Is féidir doiciméadacht i bhfoirm cód foinse do na leathanaigh fear a fháil. sa chroílár nó, curtha le chéile cheana féin, ar an líon.

Tráth na scríbhneoireachta seo bpftool tagann sé réidh le haghaidh RHEL, Fedora agus amháin Ubuntu (féach, mar shampla, an snáithe seo, a insíonn scéal neamhchríochnaithe an phacáistithe bpftool в Debian). Ach má tá do chroílár curtha le chéile agat cheana féin, ansin cuir le chéile é bpftool chomh héasca le pie:

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

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

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

$

(Seo ${linux} - seo é do chomhadlann eithne.) Tar éis na horduithe seo a chur i gcrích bpftool a bhailiú i eolaire ${linux}/tools/bpf/bpftool agus is féidir é a chur leis an gcosán (ar an gcéad dul síos don úsáideoir root) nó díreach cóipeáil chuig /usr/local/sbin.

Bailigh bpftool is fearr an dara ceann a úsáid clang, le chéile mar a thuairiscítear thuas, agus seiceáil an bhfuil sé le chéile i gceart - ag baint úsáide as, mar shampla, an t-ordú

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

a thaispeánfaidh cé na gnéithe BPF atá cumasaithe i do eithne.

Dála an scéil, is féidir an t-ordú roimhe seo a rith mar

# bpftool f p k

Déantar é seo de réir analaí leis na fóntais ón bpacáiste iproute2, áit ar féidir linn, mar shampla, a rá ip a s eth0 in ionad ip addr show dev eth0.

Conclúid

Ligeann BPF duit flea a bhróg chun feidhmiúlacht an chroíláir a thomhas go héifeachtach agus a athrú ar an eitilt. D'éirigh go han-mhaith leis an gcóras, sna traidisiúin is fearr de UNIX: thug meicníocht shimplí a ligeann duit an t-eithne a ríomhchlárú arís agus is féidir le líon mór daoine agus eagraíochtaí triail a bhaint as. Agus, cé go bhfuil na turgnaimh, chomh maith le forbairt an bhonneagair BPF féin, i bhfad ó bheith críochnaithe, tá ABI cobhsaí ag an gcóras cheana féin a ligeann duit loighic gnó iontaofa, agus is tábhachtaí, éifeachtach a thógáil.

Ba mhaith liom a thabhairt faoi deara, i mo thuairim, go bhfuil an-tóir ar an teicneolaíocht mar, ar thaobh amháin, is féidir imirt (is féidir ailtireacht meaisín a thuiscint níos mó nó níos lú i tráthnóna amháin), agus ar an láimh eile, chun fadhbanna a réiteach nach bhféadfaí a réiteach (go hálainn) roimh a chuma. Cuireann an dá chomhpháirt le chéile iallach ar dhaoine triail a bhaint as agus aisling a dhéanamh, rud a fhágann go dtiocfaidh réitigh níos nuálaí chun cinn.

Cé nach bhfuil an t-alt seo ró-ghearr, níl ann ach réamhrá ar shaol na BPF agus ní chuireann sé síos ar ghnéithe “chun cinn” agus ar chodanna tábhachtacha den ailtireacht. Is é an plean atá ag dul ar aghaidh ná rud éigin mar seo: beidh an chéad alt eile ina fhorbhreathnú ar chineálacha clár BPF (tá 5.8 cineál clár tacaithe san eithne 30), ansin féachfaimid faoi dheireadh ar conas fíor-iarratais BPF a scríobh ag baint úsáide as cláir rianaithe eithne. mar shampla, ansin tá sé in am do chúrsa níos doimhne ar ailtireacht BPF, agus samplaí d'fheidhmchláir líonraithe agus slándála BPF ina dhiaidh sin.

Ailt roimhe seo sa tsraith seo

  1. BPF do na cinn beag, cuid nialais: BPF clasaiceach

Naisc

  1. Treoir Thagartha BPF agus XDP — doiciméadú ar BPF ó cilium, nó níos cruinne ó Daniel Borkman, duine de chruthaitheoirí agus de lucht cothabhála BPF. Is é seo ceann de na chéad tuairiscí tromchúiseacha, atá difriúil ó na cinn eile sa mhéid is go bhfuil a fhios ag Daniel go díreach cad atá á scríobh aige agus nach bhfuil aon bhotúin ann. Go háirithe, déantar cur síos sa doiciméad seo ar conas oibriú le cláir BPF de na cineálacha XDP agus TC ag baint úsáide as an bhfóntas aitheanta ip as an bpacáiste iproute2.

  2. Doiciméadú/líonrú/filter.txt — bunchomhad le doiciméid don BPF clasaiceach agus ansin leathnaithe. Léamh maith más mian leat mionscrúdú a dhéanamh ar theanga an tionóil agus ar shonraí teicniúla ailtireachta.

  3. Blag faoi BPF ó facebook. Déantar é a nuashonrú go hannamh, ach go hoiriúnach, mar a scríobhann Alexei Starovoitov (údar eBPF) agus Andrii Nakryiko - (cothabhálaí) ann libbpf).

  4. Rúin bpftool. Snáithe twitter siamsúil ó Quentin Monnet le samplaí agus rúin maidir le húsáid bpftool.

  5. Léim isteach sa BPF: liosta ábhar léitheoireachta. Liosta ollmhór (agus fós á chothabháil) de naisc chuig doiciméadú BPF ó Quentin Monnet.

Foinse: will.com

Ceannaigh óstáil iontaofa do shuímh le cosaint DDoS, freastalaithe VPS VDS 🔥 Ceannaigh óstáil gréasáin iontaofa le cosaint DDoS, freastalaithe VPS VDS | ProHoster