pro parvulis BPF, pars una: extensa BPF

In principio erat technicae artis et vocatum BPF. Vidimus eam prior, Veteris Testamenti articulus huius seriei. Anno 2013, per conatus Alexei Starovoitov et Daniel Borkman, eius versio emendata, optimizata pro modernis machinis 64 frenum, in Linux nucleo evoluta est et inclusa. Haec nova technologia breviter appellata Interna BPF, deinde BPF appellata, et nunc, post aliquot annos, omnes simpliciter appellat BPF.

Dure loquendo, BPF permittit te utentis arbitrarii copiam in spatio nuclei Linux currere, et nova architectura tam prospere evenit ut duodecim plures articulos egebimus ad omnes eius applicationes describendas. (Sola res tincidunt bene non fecerunt, ut videre potes in codice perficiendi infra, logo honestum creabat.

Hic articulus describit structuram machinae virtualis BPF, nuclei interfaces ad operandum cum instrumentis BPF, evolutionis instrumentis, necnon brevissima et brevissima perspectiva exsistentium facultatum, i.e. omnia quae in posterum desiderabimus ad altiorem applicationem applicationum BPF.
pro parvulis BPF, pars una: extensa BPF

Summarium articuli

Introductio ad architecturam BPF. Primum oculum avem accipiemus ex architectura BPF visum et partes principales adumbrabimus.

Registra et systema imperii BPF apparatus virtualis. Iam ideam totius architecturae habentes, structuram machinae virtualis BPF describemus.

Vita cycli BPF obiecti, bpffs fasciculi systematis. In hac sectione, arctius inspiciemus cyclum vitae objectorum BPF - programmatum et tabularum.

Administrandi ratio bpf obiecti utens vocationem. Cum aliquo intellectu systematis iam positi, tandem spectabimus quomodo res ab usuario spatii creare et manipulare utendo speciali systemate vocamus. bpf(2).

ПишСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ libbpf. Utique scribere potes programmata vocationis systematis utens. Sed difficile est. Ad missionem magis realisticam, programmarii nuclei bibliothecam elaboraverunt libbpf. Nos basicum BPF applicationem sceleti creabimus, quo in exemplis subsequentibus utemur.

Kernel Diaconi. Hic discemus quomodo programmata BPF accessere possint munera adiutoris nuclei - instrumentum quod cum mappis fundamentaliter dilatat facultates novae BPF comparatae classicae.

Accessus ad chartas ex programmatibus BPF. Hoc loco satis clare intelligemus quomodo programmata quae in mappis utuntur, creare possimus. Et etiam in verificatorem magnum et potentem acumen accipiamus.

Instrumenta progressio. Subsidia de sectione quam ad utilitates et nucleos experimentorum convocandas.

Conclusio. In fine articuli, qui hoc longe legunt, verba moventia invenient, et brevem descriptionem eorum quae in sequentibus articulis fient. Ponemus etiam plures nexus studiorum sui erga eos qui desiderium vel facultatem continuationem exspectare non habent.

Introductio ad Architecturam BPF

Antequam architecturam BPF considerare incipiamus, unum extremum tempus ad (oh) referemus classic BPFquae tamquam responsio ad adventum machinis RISC evoluta est et quaestionem eliquandi efficiendi televisificam solvit. Architectura ita feliciter evenit ut, cum in Berkeley UNIX novemties collisione nata esset, ad systemata operativa maxime exsistentia deportaretur, in viginti insanis superfuit et adhuc novas applicationes invenit.

Novus BPF explicavit ut responsio ad ubiquitatem machinis 64-frenum, nubium officia et auctam necessitatem instrumentorum ad SDN creandum (Software-defined networking). A nucleo fabrum retis evolutae ut emendato reposito pro classic BPF, novus BPF literam sex mensium postea applicationes in difficili negotio systemata Linux investigandi invenit, et nunc, sex annis post eius speciem, totum proximum articulum mox indigebimus. enumerare rationes programmata.

Ridiculam imaginibus

In suo nucleo, BPF est sandbox virtualis machina quae te permittit ut "arbitrarium" codicem in spatio nucleo currere sine securitate afferat. BPF programmata in spatio usoris creantur, in nucleum onusta et ad fontem aliquo eventui connexae. Eventus esse potest, exempli gratia, traditio fasciculi ad interfaciem retis, deductio functionis alicuius nuclei, etc. In casu sarcina, progressio BPF habebit accessum ad notitias et metadatas fasciculi (ad legendi et fortasse scribendi secundum rationem programmatis); in casu nuclei muneris, argumenta. munus, additis acinum indicibusque memoriae, etc.

Propius inspiciamus hunc processum. In primis, fama de prima differentia a classicis BPF, quae programmata scripta sunt in coadunatione. In nova versione, architectura amplificata est ut programmata in linguis alta conscribi possent, imprimis, sane in C. Propter hoc, finis llvm elaboratum est, quod permittit te ad architecturam bytecode generare.

pro parvulis BPF, pars una: extensa BPF

Architectura BPF designata est, ex parte, ut efficaciter in hodiernis machinis curreret. Ad hoc opus in praxi faciendum, bytecode BPF, olim in nucleum onustus, in codicem nativum translatum est utens componente compilator nomine JIT.Jquemad In Time). Deinde, si meministi, programmata classica BPF in nucleo onerata erat et eventui fonti atomice affixa - in contextu unius systematis vocationis. In nova architectura, hoc duobus gradibus accidit - primo, codice oneratur in nucleo utens ratio vocationis. bpf(2)ac deinde, postea, per alias machinas varias secundum rationem programmatis, propositum eventui principii adiungitur.

Hic lector quaestionem habere potest: an fieri potuit? Quomodo salus talis codicis praestatur exsecutio? Executio salus nobis praestatur a stadio onerandi BPF programmatis verificantis (Anglice haec scaena verificatrix appellatur et verbo Anglico uti pergo);

pro parvulis BPF, pars una: extensa BPF

Verificatorium analysris staticae est, quod efficit ut programma normalem operationem nuclei non rumpat. Hoc obiter non significat propositum non posse impedire operationi systematis - BPF programmatis, secundum genus, legere et rescribere sectiones memoriae nuclei, reddere valores functionum, stringere, appendere, rescribere. atque etiam deinceps retiacula facis. Verificatorium cautiones quae programmatis BPF currit, nucleum non collidet et programma quod secundum regulas accessum scribere habet, exempli gratia, notitia exitu fasciculi, memoriam nuclei extra fasciculum rescribere non poterit. Verificatorium paulo subtilius in sectione respondente intuebimur, postquam cetera omnia BPF comprehendimus.

Quid ergo tam longe didicimus? Usor programmatis in C scribit, eam in nucleo utens ratio vocationis onerat bpf(2), ubi a uerificante retunditur et bytecode in natalem translatum. Tunc idem vel alius usor programmatum cum eventu coniungit et incipit agere. Caliga et nexus separare pluribus de causis necessarium est. Uno modo, currens verificator est relative carus et ex eadem programmate sumendo pluries tempus computatorium consumimus. Secundo, quemadmodum programma coniungitur a suo genere dependet, et unum interface "universale" ante annum elaboratum non potest convenire novis programmatis rationibus. (Quamquam nunc architectura maturior fieri possit, idea est hoc instrumenti in plano coniungendi libbpf.)

Videat attentus lector nos imaginibus nondum confectos esse. Immo omnia supradicta non explicant cur BPF fundamentaliter imaginem mutet comparatam classic BPF. Duae innovationes quae insigniter ampliant scopum applicabilitatis, facultas est utendi memoria communi et adiutorio nucleo functionum. In BPF, memoria communicata perficit utens maps sic dictas β€” structuris communicatis cum certis API. Probabiliter hoc nomen obtinuit quod primum genus tabulae ut appareret erat mensa Nullam. Tunc apparuerunt vestes, locales (per-CPU) tabulae Nullam et vestitus localis, arbores quaesitae, tabulae quae in BPF programmata et multo plura indicant. Quid nunc nobis interest, quod programmata BPF nunc facultatem habent perseverandi status inter vocat et eam cum aliis programmatis et cum spatio usoris communicandi.

Maps accessed ex processibus usoris utens ratio vocationis bpf(2), et ex BPF programmatibus in nucleo decurrentibus functionibus adiutoris utentis. Praeterea adiutores sunt non solum ad operandum cum mappis, sed etiam ad alias facultates nucleos accedunt. Exempli gratia, BPF programmata adiutoria functionibus uti possunt ad alia interfaces transmittere, eventus perf generare, structuras nuclei accedere, et sic porro.

pro parvulis BPF, pars una: extensa BPF

In summa, BPF facultatem praebet arbitrariam, i.e., verificantis probatam, usoris in spatio nuclei onerandi. Hoc signum statum inter vocationes et commutationem notitias cum spatio usoris servare potest, et etiam accessum ad subsystematum nuclei subsystematis permissum est.

Hoc iam simile est facultatibus a nucleo modulorum comparatis, quibus BPF aliquas utilitates habet (sane, si similes applicationes comparare potes, exempli gratia ratio typum - arbitrarium cum BPF scribere non potes). Limen ingressum inferiorem notare potes (quaedam utilitates quae BPF utuntur, utentem non requirunt ut artes nuclei programmandi, vel artes programmandi in genere), salus runtime (tolle manum tuam in commenta pro iis qui systema scribentem non rumpunt. seu modulorum probatio), atomicity - est tempus downtime cum modulorum reloading, et subsystem subsystem BPF efficit ut nullae eventus fallantur (quod pulchrum est, hoc omnibus generibus BPF programmatis verum non est).

Praesentia talium facultatum instrumentum universale facit BPF ad augendum nucleum, quod in praxi confirmatur: plura ac magis nova programmatum genera adduntur BPF, magis magisque magnae societates BPF utuntur in pugna servientibus 24-7, magis ac magis satus negotium suum aedificant in solutionibus secundum quae in BPF nituntur. BPF ubique adhibetur: in defensione contra impetus DDoS, SDN creandi (exempli gratia, retiacula kubernetes exsequentes), sicut instrumentum systematis principale repetens et collectorem statisticum, in intrusione systemata detectionis et systemata sandbox, etc.

Percontationem partem articuli hic perficiamus et accuratius machinam virtualem et BPF ecosystematis intueamur.

Digressio: utilitates

Ut exempla in sequentibus sectionibus currere possint, pluribus utilitatibus saltem opus sit llvm/clang cum bpf auxilio et bpftool. sectioni Progressio Tools Leges instructiones ad utilitatem congregandas ac acinum tuum. Hoc capitulum infra positum est, ne nostre praesentationis concordiam turbet.

Rectum BPF Machina registra et Instructio Ratio

Architectura et ratio imperii BPF elaborata est ratione habita quod programmata in lingua C scribenda et in nucleo oneratique in codicem vernacum translati sunt. Numerus ergo registrorum ac mandatorum statuto oculo ad intersectionem, sensu mathematico, de facultatibus machinis recentiorum electi sunt. Variae praeterea programmata restrictiones impositae sunt, exempli gratia, donec nuper loramenta et subroutina scribere non potuit, et numerus instructionum ad 4096 limitatus est (nunc programmata privilegiata usque ad decies centena millia instructionum onerare possunt).

BPF habet undecim user-pervia 64-bit commentariis r0-r10 et programma considit. Register r10 tabulam continet regulam et solum legitur. Programmata aditus ad 512 byte acervum runtime et indefinitum memoriae communicatae in forma mappis.

BPF programmata certa certae programmatis nuclei adiutores currere permittuntur et functiones regulares recentius. Unumquodque munus vocatum capere potest quinque argumentis, in registris elapsis r1-r5ac reditus pretii est r0. Confirmatur quod post reditum ab officio contenta tabulariorum r6-r9 Non mutabitur.

Ad translationem programmatis efficiens, registra r0-r11 omnes enim architecturae fultae unice sunt descriptae ad veras tabulas, ratione habita ABI notarum architecturae hodiernae. Verbi gratia, x86_64 registra r1-r5, ad munus parametri transeundi, monstrantur rdi, rsi, rdx, rcx, r8, quae ad parametri functiones transire solebant x86_64. Exempli gratia, codicem a sinistra vertit ad codicem a dextra sic;

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

actis mandare r0 etiam proventus programmatis et in registro redire solebant r1 progressio monstratorem contextum reddit - secundum rationem programmatis, hoc esse potest, exempli gratia, structuram struct xdp_md (Nam XDP) seu structuram struct __sk_buff (Pro diversis network programs) seu structuram struct pt_regs (pro diversis generibus programmatum) etc.

Statutum igitur tabularum habuimus, adiutores nucleos, acervum, monstratorem contextus et memoriam in forma mappis communicavit. Non quod haec omnia absolute necessaria sint in itinere, sed...

Descriptio pergamus et loqui de systemate imperii in his rebus operandi. Omnis (Fere omnes) BPF 64- bit habent instructiones certam magnitudinem. Si unam disciplinam spectes super 64 frenum Big Machina Endian videbis

pro parvulis BPF, pars una: extensa BPF

est Code β€” haec est descriptam instructionis; Dst/Src sunt descriptam accepti et principii respective; Off - 16-bit incisum signatum, et Imm est 32-bit signatus integer in quibusdam instructionibus (similis CBPF constanti K). modum translitterandi Code unum est duorum generum;

pro parvulis BPF, pars una: extensa BPF

Instructiones classes 0, 1, 2, 3 definiunt praecepta ad memoriam operandam. They dicuntur, BPF_LD, BPF_LDX, BPF_ST, BPF_STXrespectively. Classes IV, VII.BPF_ALU, BPF_ALU64) ALU instructiones constituunt. Classes V, VI.BPF_JMP, BPF_JMP32) Mandata continent jump.

Ulterior ratio perscrutandi ratio instructionis BPF est haec: loco adamussim recensentes omnes instructiones earumque parametri, duo exemplorum in hac sectione videbimus et ex illis patebit quomodo instructiones actu operantur et quomodo. manually disassemble quolibet binario lima pro BPF. Ad materiam postea in articulo consolidandam, etiam singulis instructionibus occurremus in sectionibus de Verifier, JIT compilator, translatione classicorum BPF, tum cum mappis studens, functiones vocantes, etc.

Cum de singulis praeceptis loquimur, ad nucleum imaginum referemus bpf.h ΠΈ bpf_common.hquae definiunt instructiones numerales codicis BPF. Cum architecturae in tuo proprio et/vel binario parsing studeas, in sequentibus fontibus semanticos invenire potes, ordine multiplicitatis digestus: Priyatus eBPF spec, BPF et XDP Reference Guide, Instructio Set, Documentation/networking/filter.txt et quidem in codice fonte Linux - uerificante, JIT, BPF interprete.

Exempli gratia: disassembling BPF in caput tuum

Intueamur exemplum in quo programma componimus readelf-example.c et specta inde binarii. Nos originale contentus erit revelare readelf-example.c infra, postquam logicam suam ex codicibus binariis restituimus;

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

Primum agmen in output readelf incisum est et propositum nostrum sic ex quattuor praeceptis;

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

Imperio codes sunt pares b7, 15, b7 ΠΈ 95. Recole quod minimum significantes tres frusta sunt instructionis classis. In nobis, quarta pars omnium praeceptorum vacua est, ita instructio classes sunt 7, 5, 7, 5, respective. Classis 7 est. BPF_ALU64et 5 is BPF_JMP. Utraque enim forma instructio eadem est (vide supra), et programmata nostra sic rescribere possumus (simul reliquas columnas in forma humana scribemus);

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

operatio b class ALU64 - eam BPF_MOV. Pretium assignat ad locum desideratum. Si frenum est paro s tunc valorem ex tabulario fonte sumatur et si, ut in nobis est, non sit positum, tunc ex agro pretium accipitur. Imm. Sic ergo in prima et tertia instructiones operationis perficimus r0 = Imm. Praeterea, JMP operatio 1 classis est BPF_JEQ (Sil si aequalis). In nobis, cum bit S nulla est, valorem fontis mandare cum agro comparat Imm. Si valores coincidunt, transitus occurrit PC + Offquibus PCut solet, sequentis instructionis oratio continet. Denique JMP Classis IX Operatio est BPF_EXIT. Haec institutio propositum terminat, ad nucleum reverti r0. Novam columnam addamus tabulae nostrae;

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

Hoc commodiore forma scribere possumus:

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

Si meminimus quid sit in actis mandare r1 programma monstratorem contextus e nucleo reddit et in registro r0 valor ad nucleum redditur, tunc videre possumus quod si monstrator contextus nullus est, tunc revertamur 1, et aliter - 2. Inspiciamus nos recte considerare principium;

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

Etiam programma vanum est, sed in quattuor simplices tantum instructiones vertit.

Exempli gratia: 16-byte disciplinam

Supra memoravimus nonnullas instructiones plusquam 64 frusta sumere. Hoc valet, verbi gratia, ad instructiones lddw (Codex = 0x18 = BPF_LD | BPF_DW | BPF_IMM) β€” duplici verbo ex agris in registro onerare Imm. Qui est punctus Imm Magnitudinem habet XXXII, et duplex sermo est 32 bits, qui statim valorem 64-bit levans in tabulario in uno 64 frenum instructio non operatur. Ad hoc faciendae duae instructiones adjacentes solent alteram partem valoris 64-obscenorum in agro recondere Imm. Exemplum:

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

Duae tantum instructiones sunt in programmate binario:

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

Occurremus iterum instructiones lddwcum de relocationibus et operibus geographicis loquimur.

Exemplum: disassembling BPF utens vexillum instrumenta

Itaque binarii codices BPF legere didicimus et parati sumus ad aliquam instructionem si opus sit. Sed dignum est dicere in usu commodius et velocius programmata discurrere ut instrumenta normae adhibentes, exempli gratia:

$ 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

Vitacyclus rerum BPF, bpffs systematis fasciculi

(Primo didici quaedam de singulis in hoc ordine descriptis jejunium Alexei Starovoitov in BPF Blog.)

BPF objects - programs and maps - are created from user space using command BPF_PROG_LOAD ΠΈ BPF_MAP_CREATE ratio vocationis bpf(2)quomodo hoc in sequente articulo acciderit, exacte loquemur. Facit nucleos notitias structuras et pro unoquoque eorum refcount (reference count) positum est ad unum, et lima descriptor obiecto demonstrans usori redditur. Post manubrium clauditur refcount objectum ab uno reducitur, et cum nihilum pervenit, destruitur objectum.

Si progressio mappis utitur, tunc refcount hae mappae auctae singulatim onerata ratione, i.e. eorum documenti descriptores possunt claudi a user processum et adhuc refcount non fiet nulla;

pro parvulis BPF, pars una: extensa BPF

Post feliciter programmata onerantes, eam ad aliquem generantis eventum pertinere solemus. Exempli causa, in retis interfaciem imponere possumus cum fasciculis advenientis vel cum aliquo connectere tracepoint in core. Hic, relatio contrarii etiam unum augebit et in programmate oneratus tabellam descriptorem claudere poterimus.

Quid fit, si iam caesus occlusus est? Genus eventus generantis dependet (hamo). Omnes uncini retis erunt postquam oneratus complet, hi uncini globalis sic dicti sunt. Et, exempli gratia, programmatis vestigium solvetur post processum qui eas terminat (et ideo locales vocantur, a "locus ad processum"). Technicaliter, unci locales semper respondentem fasciculi descriptor in spatio usoris habent et ideo claudunt cum processu clauso, at hami globalis non sunt. In sequenti figura, cruces rubras utens, ostendere conor quomodo terminationis oneris programma afficit objectorum in rebus localibus et in global hamis.

pro parvulis BPF, pars una: extensa BPF

Quare distinctio uncinorum localium et globalum est? Currens nonnulla genera programmatum retis sensum sine usoris spatio facit, exempli gratia, finge praesidium DDoS - bootloader scribit regulas et programmata BPF coniungit cum retis interfaciei, post quae potest ire et occidere se. Contra, debugging vestigium programma finge, quod in genibus decem minutas scripseras - cum consummatum est, nihil coenum in systemate relictum esse velis, et loci hami id efficiet.

Ex altera vero parte, finge te velle cum nucleo in nucleo coniungere et statisticam per multos annos colligere. Hoc in casu, partem usoris absolvere velis et ad statisticam subinde redire. Ratio fasciculi bpf hanc occasionem praebet. In memoria solum pseudo- fasciculi ratio est quae creationem imaginum admittit quae referat BPF obiecta et ita auget refcount obiicit. Post hoc, oneratus potest exire, et res creatas viva remanebit.

pro parvulis BPF, pars una: extensa BPF

Files creandi in bpffs quae referat obiecta BPF, "fibulare" dicitur (ut in sequenti locutione: "processus programmatis BPF vel tabulam suspendere potest"). File obiecta creans pro obiectis BPF sensum facit non solum ad vitam localium rerum amplificandam, sed etiam ad rerum globalium usabilitatem - rediens ad exemplum cum programmate tutelae globalis DDoS, venire ac intueri posse statisticas volumus. de tempore usque ad tempus.

The BPF file system is usually mounted in /sys/fs/bpfsed potest etiam localiter collocari, verbi gratia, sic;

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

File systema nomina creantur per mandatum BPF_OBJ_PIN BPF ratio vocationis. Ad illustrandum, programma sumamus, componamus, fasciamus, figamus bpffs. Propositum nostrum nihil utile facit, tantum codicem exhibemus ut exemplum possis referre:

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

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

Hoc programma compilare et exemplar locale tabellae systematis creare bpffs:

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

Nunc videamus programmata nostra utilitate utens bpftool et respice in comitante ratio vocat bpf(2) (lineae quaedam irrelevant a strace output remota):

$ 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

Hic programmata oneravimus utendo BPF_PROG_LOAD, file descriptor ex nucleo accepit 3 ac per mandatum BPF_OBJ_PIN adfixum hoc file descriptor ut lima "bpf-mountpoint/test". Post haec progressio bootloader bpftool peractum opus, sed propositum nostrum in nucleo manebat, quamquam eam nulli interfaciei retis adiunximus;

$ 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

Non possumus delere quod lima Northmanni unlink(2) et postea programma respondente delebitur:

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

Deletio obiecti

De obiectis deletis loquendo, declarare necesse est nos, postquam progressio ab hamo (evente generante disiungitur), ne unus novus eventus eius incussus erit, omnes tamen instantiae hodiernae programmatis in ordine normali complebuntur. .

Aliqua genera programmatum BPF permittunt te institutum in musca reponere, i.e. providere serie atomicity replace = detach old program, attach new program. In hoc casu, omnes instantiae activae veteris progressionis opus suum perficiet, et novus eventus tractatores ex novo programmate creabuntur, et "atomicitas" hic significat ne unus eventus omittatur.

Programs attachiando ad res fontes

In hoc articulo, programmata ad eventum fontes coniungentes separatim non describemus, cum sensum hoc in contextu certae rationis evolvamus. Cm. exempli gratia infra, in quo ostendemus quomodo programmata XDP connexa sint.

Manipulating res per bpf System Call

BPF programmata

Omnia BPF obiecta creantur et administrantur ex spatio usoris utens ratio vocationis bpfsequens prototypum habens;

#include <linux/bpf.h>

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

Hic est dolor cmd est de valores generis enum bpf_cmd, attr - monstratorem parametri pro specifica progressio et size β€” object size according to the point, i.e. plerumque hoc sizeof(*attr). In nucleo 5.8 ratio vocationis bpf 34 alia imperia sustinet; definition union bpf_attr occupat CC lineas. Sed hoc non est perterritum, cum per plures articulos nosmetipsos praeceptis et parametris assuefaciamus.

Sit scriptor satus cum bigas BPF_PROG_LOAD, quae programmata BPF creat - copiam BPF mandatorum accipit et in nucleum onerat. In momento onerationis, verificator educitur, deinde JIT compilator et, postquam prospere exsecutionem egerit, programmata fasciculi descriptor ad usorem redditur. Quid ei contigerit proximo in sectione superiore vidimus de vita cycle obiecti BPF.

Nunc scribemus rationem consuetudinis quae simplex BPF programmata onerabit, sed primum diiudicare oportet qualem rationem onerare velimus - eligere debebimus genus et intra huius generis compagem scribe rationem, quae experimentum verificantis praeteribit. Attamen, ne processum inpediat, prompta solutio est hic: programma simile capiemus BPF_PROG_TYPE_XDPqui reddet valorem XDP_PASS (Omit omnes sarcinas). In BPF coadunator valde simplex spectat;

r0 = 2
exit

Post constituimus quod onerabimus, indicabimus tibi quomodo id faciamus;

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

Interestingly events in a programme incipe cum definitione exercitus insns - BPF programma nostrum in machina codice. Hoc in casu, unaquaeque institutio progressionis BPF in structuram referta est bpf_insn. Primum elementum insns prosequitur instructiones r0 = 2, secundus - exit.

Receptum. Acinum nuclei commodiores macros ad machinas scribendas definit, et fasciculi nuclei capitis usus tools/include/linux/filter.h potuimus scribere

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

Sed quia programmata scribentis BPF in codice patrio tantum necessarium est ad scripturas probationes in nucleo et articulos circa BPF, absentia horum macronum re vera vitam viae non inpediunt.

Ratione BPF definita, eam ad nucleum onerando movemus. Nostra minimalist paro parametri attr progressio includit genus, copia et numerus instructionum, licentia requiritur et nomen "woo"quam in programmate nostro reperiendi systema demptione utimur. Propositum, ut pollicitus est, in systemate vocationis utendi oneratur bpf.

In fine programmatis finimus in ansa infinita quae payload simulat. Sine ea progressio a nucleo interficietur cum descriptor tabellae quae ratio vocationis ad nos rediit clausa est bpfet non videbimus in ratione.

Bene parati sumus ad probationem. Sit scriptor progressio conveniunt et currere sub stracesisto quod omne opus est ut debet;

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

Omnia est bonum, bpf(2) rediit ansa 3 ad nos et ivimus in ansam infinitam cum pause(). Conemur invenire propositum nostrum in systemate. Ad hoc ad alium terminum ibimus et utilitate utimur 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)

Videmus programmata onusta in systematis esse woo cui global ID est CCCXC et est currently in progressu simple-prog non est aperta lima descriptor monstrans progressio (et si simple-prog consummans officium, tum woo peribit). Ut malesuada progressio woo bytes - duas instructiones - ex codicibus binariis in architectura BPF sumit, sed in forma nativi (x16_86) iam 64 bytes est. Intueamur propositum nostrum in forma originali;

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

non miror. Nunc videamus codicem a JIT compilator genitum:

# 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

non est valde efficax exit(2)sed in aequitate nimis simplex programma nostra est, et pro non levibus programmatibus prologus et epilogus a JIT compilator additi sunt, utique necessarii.

Maps

BPF programmata memoriae structurae locis uti possunt, quae pervia sunt tum aliis programs BPF et programmata in spatio usoris. Res mappae dictae sunt et in hac sectione ostendemus quomodo ea tractandi utens ratio vocationis bpf.

Dicamus statim facultates tabularum non limitari solum ad accessum ad memoriam communem. Exstant mappae speciales quae continentes, exempli gratia, monstratores programmatis BPF vel indicibus retis interfaces, mappas operandi cum rebus pert, etc. Nolumus hic loqui, ne lectorem confundamus. Praeter haec, quaestiones synchronisationum neglegimus, cum exempla nostris non magni momenti sint. A list of available map types can be found in <linux/bpf.h>atque in hac sectione exemplum primi generis historice, tabulae detrahendae adhibebimus BPF_MAP_TYPE_HASH.

Nullam mensam si facias, inquis, C++, dicas unordered_map<int,long> wooQuod in Russian significat "mensam opus" woo immensa magnitudine, cuius claves typus sunt intac valores generis sunt long" Ad mensam detrahendam BPF, necesse est nos multum idem facere, praeterquam quod magnitudinem maximam tabulae denotare debemus et pro specierum clavium et valorum specificando . Ad partum uti imperium maps BPF_MAP_CREATE ratio vocationis bpf. Inspice programmata plus minusve minima quae chartam geographicam creat. Post priorem rationem quae programmata BPF onerat, hic tibi simplex videri debet:

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

Hic definimus ambitum parametri attr, in qua dicimus "necessarium mensam cum clavibus et valore quantitatis" sizeof(int)in quibus maximum quattuor elementorum ponere possum. Cum tabulas BPF creans, alios parametros exprimere potes, exempli gratia, eodem modo ac in exemplo programmatis, nomen obiecti quod designamus. "woo".

Lets compilare et currunt programma:

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

Hic est ratio vocationis bpf(2) nobis reddidit descriptor numerus map 3 deinde programma, ut expectatur, ulteriores instructiones in vocatione systematis observat pause(2).

Nunc propositum nostrum ad curriculum vel ad terminum alium aperiendum mittamus et rem nostram utilitate utentem intueamur bpftool (mappa nostra ab aliis nomine suo distinguere possumus);

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

Numerus 114 est global ID obiecti nostri. Aliqua programma in systematis uti potest hoc ID ad aperiendum tabulam existentem utens mandatum BPF_MAP_GET_FD_BY_ID ratio vocationis bpf.

Nunc cum nostra Nullam mensam ludere possumus. Intueamur contenta:

$ sudo bpftool map dump id 114
Found 0 elements

Vacua. Let's put a value in it hash[1] = 1:

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

Intueamur ad mensam iterum:

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

euge! Unum elementum addere potuimus. Nota nos laborare in gradu byte ad hoc faciendum, quia bptftool Nescit cuius generis bona in tabula fascia sint. (Scientia haec ad usum BTF transferri potest, sed nunc plura.

Quam exacte bpftool legit et elementa addit? Vide sub cucullo:

$ 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

Primum tabulam aperuimus a suo globali ID usura imperio BPF_MAP_GET_FD_BY_ID ΠΈ bpf(2) rediit descriptor III nobis. Praeterea per imperium BPF_MAP_GET_NEXT_KEY invenimus primam clavem in mensa transeundo NULL ut monstrator "prior" clavis. Si habent clavem facere possumus BPF_MAP_LOOKUP_ELEMquae refert ad valorem monstratorem value. Proximum gradum conamur invenire proximum elementum transeunte monstratorem ad clavem currentem, sed mensa nostra unum tantum elementum continet ac mandatum. BPF_MAP_GET_NEXT_KEY redit ENOENT.

Bene, valorem in clavis mutemus 1, dicamus logica negotia nostra perscriptum requirit 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

Sicut expectatur, valde simplex est: mandatum BPF_MAP_GET_FD_BY_ID aperit tabulam nostram per ID, et mandatum BPF_MAP_UPDATE_ELEM elementum overwrites.

Itaque, mensa Nullam ab uno programmate creando, ex alio contenta legere et scribere possumus. Nota quod si ex linea recta facere potuimus, tunc quodlibet aliud propositum in ratione facere potest. Praeter praecepta supra scripta, ad operandum cum mappis ex spatio usoris; haec:

  • BPF_MAP_LOOKUP_ELEM: Invenire valorem per clavem
  • BPF_MAP_UPDATE_ELEM; Renovatio / valorem creare
  • BPF_MAP_DELETE_ELEM: Aufer clavem
  • BPF_MAP_GET_NEXT_KEY: Invenies altera (vel prima) clavis
  • BPF_MAP_GET_NEXT_ID: permittit te ire per omnes mappas existentes, id est quomodo operatur bpftool map
  • BPF_MAP_GET_FD_BY_ID: Aperire tabula existentium in global ID
  • BPF_MAP_LOOKUP_AND_DELETE_ELEM: Atomically update ad valorem obiecti et revertetur ad senem
  • BPF_MAP_FREEZE; Fac tabula immutabilis a userspace (hoc operandi infectum non potest)
  • BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, BPF_MAP_UPDATE_BATCH, BPF_MAP_DELETE_BATCH: massa operationes. Exempli gratia BPF_MAP_LOOKUP_AND_DELETE_BATCH - Haec unicus modus certa est ut omnes valores e charta legendi et reset

Non omnia mandata haec omnia operantur pro omnibus generibus tabularum, sed in generali operando cum aliis mappis ex spatio usoris, prorsus idem spectat ac opus cum tabulis Nullam.

Propter ordinem, experimenta mensa Nullam finiamus. Memento nos mensam creavisse quae quattuor claues continere potest? Pauca plura addamus elementa;

$ 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

Sic tantum bonum:

$ 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

Adde unum s tentant:

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

Ut expectatur, non successit. Intueamur errorem planius;

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

Omnia denique sunt: ​​ut expectatur, manipulus BPF_MAP_UPDATE_ELEM novum, quintum, clavem creare conatur, sed fragores E2BIG.

Ita, BPF programmata creare et onerare possumus, ac tabulas ex spatio usoris creare et administrare. Iam spectare logicum est quomodo ex ipsis BPF programmatibus mappis uti possumus. De hac re loqui potuimus in programmatibus difficile-ad-lectus in codicibus machinae tortoribus, sed tempus venit ut ostenderet quomodo programmata BPF re vera scripta et conservata sint - utens libbpf.

(Ad lectores qui inopia exempli humili gradu displicent: in speciali programmata resolvemus quae mappis utentibus et functionibus auxiliatoribus utentibus creatis utuntur. libbpf et dicam tibi, quod ad instructionem attinet. Pro lectoribus displicent maleAddimus exempli gratia suo loco in articulo).

Scribens BPF programs utens libbpf

BPF scribens programmata machinae in codicibus utens primum modo interesting esse potest, deinde satietas oritur. Nunc opus est ut animum ad llvmquae habet backend ad codicem generandi pro architectura BPF, necnon bibliothecae libbpf, quod permittit tibi scribere applicationes usoris BPF et codicem programmatum BPF generatorum utens onerare llvm/clang.

Nam, ut in hoc et subsequentibus articulis videbimus; libbpf non satis multum opus est sine qua (vel instrumenta similia - iproute2, libbcc, libbpf-goImpossibile est vivere. Una interfectorem features project libbpf est BPF CO-RE (Compile Semel, Curre Ubique) - consilium quod permittit tibi libellos BPF scribere, qui ab uno nucleo in alterum portabiles sunt, cum facultate currere in diversis APIs (exempli gratia, cum structura nuclei mutatur ex versione. to version). Ut cum CO-RE laborare possit, nucleus tuus cum subsidio BTF componendus est (describimus quomodo hoc in sectione facere possit. Progressio Tools. Potes inspicere utrum nucleus tuus cum BTF sit constructus vel non admodum simpliciter - praesente fasciculo sequenti:

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

Hic fasciculus informationum de omnibus notitiarum generibus in nucleo usus est et in omnibus nostris exemplis adhibetur libbpf. Singillatim loquemur de CO-RE in sequenti articulo, sed in hoc uno - modo aedifica te nucleum cum CONFIG_DEBUG_INFO_BTF.

library libbpf recte vivit in indicem tools/lib/bpf nucleus eiusque progressus per tabulas tabellariorum exercetur [email protected]. Repositorium autem separatum servatur pro necessitatibus applicationum extra nucleum viventium https://github.com/libbpf/libbpf in quo plus minusve ac minus acinum bibliotheca praevisa est.

In hac sectione videbimus quomodo project usus creare possit libbpfplura scribere (plus minusve vanum) programmata experiri et quomodo omnia opera enucleare in singillatim. Id nos in sequentibus sectionibus accuratius exponere facilius licebit, quam BPF programmata cum mappis, adiutoribus nucleis, BTF, etc.

Typice uti projects libbpf adde repositorium GitHub pro submodule git, eadem faciemus;

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

Ad libbpf Is est valde simplex:

$ 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

Proximum consilium in hac sectione tale est: scribemus programmata BPF BPF_PROG_TYPE_XDPeaedem ac in exemplo praecedente, sed in C, compilata ea utendo clanget scribe programmata adiutoria quae eam in nucleum onerabunt. In sequentibus sectionibus capacitates utriusque programmatis BPF et programmatis adiutoris augebimus.

Exempli gratia: creando plena application usura libbpf

In primis utimur tabella /sys/kernel/btf/vmlinuxde quo supra dictum est, et eius modi in modum tituli;

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

Hic fasciculus omnia notitiarum structurarum in nucleo nostro promptas recondet, exempli gratia, hoc modo IPv4 capitis in nucleo definitur:

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

Nunc scribemus programmata nostra BPF in 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";

Etsi programma nostra admodum simplex evasit, multa tamen opera attendere oportet. Primum, fasciculi primi tituli includuntur is vmlinux.h, qua modo generata utens bpftool btf dump - Nunc non opus est sarcinam capitis nuclei instituere ad explorandum quid structurae nuclei simile videant. Sequens fasciculus header ad nos ex bibliotheca venit libbpf. Nunc non nisi eget tortor definire SECqui characterem mittit ad aptam sectionem fasciculi ELF rei. Propositum nostrum in sectione continetur xdp/simple, ubi ante exactivationem generis BPF definimus programma - hoc est placitum in " libbpf, ex nomine sectionis rectam rationem substituet apud startup bpf(2). Programma ipsum BPF est C - simplex valde et in una linea consistit return XDP_PASS. Denique sectionem separatam "license" nomine licentiae continet.

Possumus programmata nostra componere utendo llvm/clang, versione >= 10.0.0, vel adhuc melius, maius (vide sectionem Progressio Tools):

$ 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

Inter interesting lineamenta: scopum architecturae indicamus -target bpf et iter ad capitis libbpfquas nuper inauguavimus. Etiam, nolite oblivisci -O2sine hac optione sitis in improviso. Inspice codicem nostrum, nonne nos programmata scribere voluimus?

$ 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

Etiam laboravi! Nunc fasciculum binarium cum programmatis habemus, et applicationem creare volumus quae eam in nucleum onerabunt. Ad hoc bibliothecam libbpf nobis duas optiones praebet - inferiore gradu API vel gradu superiore API utere. Secundum viam ibimus, quia discere volumus quomodo scribere, onera et programmata BPF coniungere minimo conatu pro eorum studio sequentem.

Primum, "sceleton" institutionis nostrae e binario utendo eadem utilitate generare oportet bpftool β€” Helvetica omitta mundi BPF (quod proprie accipi potest, cum Daniel Borkman, unus e auctoribus et assertoribus BPF, Helvetius est);

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

In file xdp-simple.skel.h Codex binarii institutionis nostrae ac functiones continet ad rem nostram administrandam, onerandam, adnectendam, delendam. In nostro simplici casu haec species overkill, sed etiam operatur in casu ubi res fasciculi plures BPF programmata et tabulas continet et ad hunc gigantem ELF onerandum nos solum sceletum generare oportet et unam vel duas functiones ex applicatione consuetudinis appellamus. scribimus Eamus nunc.

Proprie loquendo, programmata oneratus nostra levis est;

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

est struct xdp_simple_bpf definitur tabella xdp-simple.skel.h et describit rem nostram file:

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

Vestigia humili gradu API hic videre possumus: structuram struct bpf_program *simple ΠΈ struct bpf_link *simple. Prima structura nominatim describit propositum nostrum, in sectione scriptum xdp/simpleet secunda describit quomodo progressio ad eventum rei pertinet.

munus xdp_simple_bpf__open_and_load, objectum ELF aperit, parsit, omnes structuras ac substructiones creat (praeter rationem, ELF alias sectiones etiam continet - datas, datas, notitias, debugging informationes, licentiam, etc.), eamque onerat in nucleum systematis utendi. vocatus bpfquam a scribendis ac currendi rationibus inhibere possumus;

$ 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

Nunc inspice programmata nostra utens bpftool. Id inveniamus eam:

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

ac TUBER (utimur forma praecepti correpta bpftool prog dump xlated):

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

Aliquid novi! Programma impressum chunks nostri C, fons lima. Hoc factum est in bibliotheca libbpfquae sectionem debug in binario invenit, eam in objecto BTF compilavit, eam in nucleum utens. BPF_BTF_LOAD, ac deinde descriptor limam inde speciem cum programmate oneret cum imperio BPG_PROG_LOAD.

Kernel Adiutores

BPF programmata munera "externa" - adiutores nuclei currere possunt. Munera auxiliatrix haec permittit programmata BPF ad structuras nucleos accedere, mappas administrare et etiam cum "rei mundi" communicare - eventus perf creare, ferramenta moderari (exempli gratia, fasciculas redirectas) etc.

Exemplum: bpf_get_smp_processor_id

Intra "exemplum discendi" paradigma consideremus unum munerum adiutorium; bpf_get_smp_processor_id(), quidam in file kernel/bpf/helpers.c. Redit numerus processus in quem BPF programmatis currit qui vocatur. Sed non sicut in semanticis, sicut in eo quod exsequendum est unam lineam;

BPF_CALL_0(bpf_get_smp_processor_id)
{
    return smp_processor_id();
}

In BPF adiutorii functiones definitiones sunt similes definitionibus systematis Linux vocatis. Hic, exempli gratia, munus definitur nullas rationes habere. ( Munus quod sumit, inquam, tribus argumentis utens macro definitur BPF_CALL_3. Argumentorum numerus maximus est quinque.) Sed haec prima pars est tantum definitionis. Secunda pars est genus structurae definire struct bpf_func_protoquae descriptionem continet functionis adiutoris quod verificantis intelligit;

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

Subcriptio adiutoris functiones

Ut programmata alicuius generis BPF hoc munere utantur, illud subcriptio, exempli gratia pro typ BPF_PROG_TYPE_XDP munus definitur in nucleo xdp_func_protoquae ab adiutorio functionis ID decernit utrum XDP hoc munus sustineat necne. Munus nostrum est fusiles:

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

Novae BPF programmatis rationes "definiuntur" in tabella include/linux/bpf_types.h usus tortor BPF_PROG_TYPE. In sententiis definitur quia definitio logica est, et in C verbis definitio totius certae structurarum concretarum occurrit alibi. Praesertim in tabella kernel/bpf/verifier.c omnes definitiones ex file bpf_types.h sunt creare aciem structurarum 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
};

Hoc est, ad singulas rationes programmatis BPF, monstratorem ad structuram datam speciei definiendam esse struct bpf_verifier_opsquae initialized cum valore _name ## _verifier_ops, i.e. xdp_verifier_ops ad xdp. Structure xdp_verifier_ops proposuerunt singuli in file net/core/filter.c ut sequitur:

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

Nota munus nostrum hic videmus xdp_func_proto, quae in verificantem quoties incurrit provocationem current aliquid functiones intra BPF programma, vide verifier.c.

Intueamur quomodo hypothetica BPF progressio munere utitur bpf_get_smp_processor_id. Ad hoc propositum ex praecedenti sectione rescribimus hoc modo:

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

signum bpf_get_smp_processor_id proposuerunt singuli Π² <bpf/bpf_helper_defs.h> bibliothecam libbpf quam

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

ille est, bpf_get_smp_processor_id est functio monstratoris cuius valor 8, ubi valor VIII est BPF_FUNC_get_smp_processor_id genus enum bpf_fun_idquae nobis in tabella definita est vmlinux.h (file bpf_helper_defs.h in nucleo scripto generatur, sic numeri "magici" ok sunt. Hoc munus non accipit rationes et valorem generis reddit __u32. Cum in programmate illo curritur; clang generat disciplinam BPF_CALL "jus genus" Progressio et respice in sectione Lets ordinare 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

In prima linea videmus mandatum call, parameter IMM = 8 = SRC_REG β€” nulla. Secundum pactum ABI a uerificante adhibitum, haec vocatio ad munus adiutorium est numerus octonarius. Semel emittitur, logica simplex est. Redi valorem ex mandare r0 copied to r1 et in lineis 2,3 convertitur ad typus u32 β€” Superiores 32 frena purgantur. In lineis 4,5,6,7 redimus 2 (XDP_PASS) Seu I (XDP_DROP) pendens sive munus adiutorium ex linea 0 nullum valorem vel non-nullam reddidit.

Experiamur ipsi: oneramus rationem et vide in output bpftool prog dump xlated:

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

$ sudo bpftool p | grep simple
523: xdp  name simple  tag 44c38a10c657e1b0  gpl
        pids xdp-simple(10915)

$ sudo bpftool p d x id 523
int simple(void *ctx):
; if (bpf_get_smp_processor_id() != 0)
   0: (85) call bpf_get_smp_processor_id#114128
   1: (bf) r1 = r0
   2: (67) r1 <<= 32
   3: (77) r1 >>= 32
   4: (b7) r0 = 2
; }
   5: (15) if r1 == 0x0 goto pc+1
   6: (b7) r0 = 1
   7: (95) exit

Ok, uerificans rectam nucleum adiutorem invenit.

Exempli gratia: rationes praetereundo ac tandem progressio currit!

Omnes currunt-gradu adiutorium functiones habent exemplar

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

Parametri ad munera adiuvantis in regestis transeunt r1-r5et valorem in registro redditur r0. Nullae sunt functiones quae plusquam quinque rationes capiant, earumque subsidia in posterum addi non expectatur.

Inspice nucleum novum adiutorem et quomodo parametri BPF transit. Lets RESCRIBO xdp-simple.bpf.c ut sequitur (reliquae lineae non mutatae sunt);

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

Programma nostrum imprimit numerum CPU in quo currit. Let's compilare et inspicere in codice:

$ 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

In lineis 0-7 scribimus chorda running on CPU%unet deinde in linea 8 notum cucurrimus bpf_get_smp_processor_id. In lineis 9-12 paramus argumenta adiutoria bpf_printk - registra r1, r2, r3. Cur tres eorum et non duo sunt? Quod bpf_printkhoc est tortor serratus circum verus adiutor bpf_trace_printkquae ad magnitudinem chordae format.

Nunc adde duas lineas to xdp-simple.cut programma nostra interface coniungat lo et vere incepit!

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

Munus hic utimur bpf_set_link_xdp_fdquae programs XDP-type BPF coniungit cum interfaces retis. Nos interface hardcoded numerus losemper, 1. Currimus bis munus prius abducere institutum veterem si adicitur. Animadverte nunc nos provocatione non indigere pause vel ansa infinita: programmata oneratus noster exit, sed programmata BPF non interficietur cum eventui fonte coniungitur. Post opportunam download et connexionem, programma mittetur ad unumquemque fasciculum retis perveniens lo.

Progressio Lets download et vide ad interface lo:

$ sudo ./xdp-simple
$ sudo bpftool p | grep simple
669: xdp  name simple  tag 4fca62e77ccb43d6  gpl
$ ip l show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    prog/xdp id 669

Progressio nos downloaded ID 669 ac idem videmus in interface lo. Nos mittemus a duobus packages to 127.0.0.1 (postulatio + responsum);

$ ping -c1 localhost

Et nunc videamus de contentis debug virtualis lima /sys/kernel/debug/tracing/trace_pipe, in quibus bpf_printk scribit epistulas suas:

# 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

Duo sunt maculosus packages lo et processit in CPU0 - primum nostrum progressionis plenae vacuae vanitati BPF operatae!

Notatu dignum est bpf_printk Non nihil est quod ad tabellam debug scribit: hoc adiutrix non est felicissima ad usum in productione, sed propositum est aliquid simplex ostendere.

Accessing maps from BPF programs

Exempli gratia: per chartam geographicam ex programmatis BPF

In sectionibus superioribus didicimus tabulas ex spatio usoris creare et uti, et nunc partem nuclei inspiciamus. Incipiamus, ut soles, exemplo. Sit scriptor progressio auctas xdp-simple.bpf.c ut sequitur:

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

In principio progressionis tabulam definitionis addimus woo: Hoc est 8-elementum ordinatum quod valores addit similes u64 (in C definiamus talem aciem u64 woo[8]). In programma "xdp/simple" nos adepto current processus numerus in variabilis key et utens adiutorium munus bpf_map_lookup_element monstratorem dabimus ad congruentem ingressum in ordine, quem per unum augemus. Translata in Russicam: statistas computamus quibus CPU fasciculi advenientes processit. Progressio scriptor experiri currere:

$ 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

Let's check that she's hook up to lo et mitte fasciculos:

$ 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

Nunc videamus contenta ordinata:

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

Fere omnes processus in CPU7. Hoc nobis non interest, summa res est ut opera programmatis et intelligamus quomodo ad tabulas accessus ex programmatibus BPF - utendo. Ρ…Π΅Π»ΠΏΠ΅Ρ€ΠΎΠ² bpf_mp_*.

Mysticus index

Itaque ad tabulam accedere possumus e programmatis BPF utendi vocat sicut

val = bpf_map_lookup_elem(&woo, &key);

ubi adiutor munus similis

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

sed transeuntes monstratorem &woo ad structuram sine nomine struct { ... }...

Si programmatis coadunatoris inspicimus, valorem videmus &woo non definitum (line 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
...

et in relocationibus continetur;

$ 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

Sed si programmata iam onerata spectemus, monstratorem tabulae rectae videmus (line 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]
...

Ita concludere possumus quod in tempore deductionis nostrae programmatis oneratis ligamen to &woo successit aliquid cum bibliotheca libbpf. Primum nos te intueri output strace:

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

Quod videmus libbpf creatus est tabula woo et nostri progressio downloaded simple. Propius inspiciamus quomodo programmata oneremus:

  • vocatus xdp_simple_bpf__open_and_load ex file xdp-simple.skel.h
  • quae causas xdp_simple_bpf__load ex file xdp-simple.skel.h
  • quae causas bpf_object__load_skeleton ex file libbpf/src/libbpf.c
  • quae causas bpf_object__load_xattr ex libbpf/src/libbpf.c

Munus ultimum, inter alia, vocabo bpf_object__create_mapsquae tabulas exsistentes creat vel aperit, eas in descriptores tabellarios convertens. (Hoc est ubi videmus BPF_MAP_CREATE in output strace.) Deinde munus appellatur bpf_object__relocate nobisque ipsa est, cum meminimus quae vidimus woo in relocation mensa. Id explorantes, tandem in munere versamur bpf_program__relocate, quod " agit cum tabula relocations:

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

Ita accipiamus mandata nostra

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

ac reponere fons mandare in ea cum BPF_PSEUDO_MAP_FDet primo IMM tabellae geographicae nostrae descriptor, si aequalis est, e.g. 0xdeadbeefergo ex hoc recipiemus disciplinam

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

Ita est quam tabula geographica ad certas rationes oneratas BPF transfertur. Hoc in casu, tabula utens creari potest BPF_MAP_CREATEEt aperitur per id utens BPF_MAP_GET_FD_BY_ID.

Totalis, cum usura libbpf algorithmus talis est;

  • in compilatione, monumenta creantur in relocatione mensa pro nexus ad chartas
  • libbpf ELF librum objectum aperit, omnes usus tabulas invenit et tabella descriptores pro illis creat
  • file descriptores oneratur in nucleo ut pars instructionis LD64

Ut credis, plus est venire et inspicere in nucleum debebimus. Fortunate sensum habemus - scripsimus significationem BPF_PSEUDO_MAP_FD in fonte registro sepelire possumus, quai nos ad sanctorum omnium sanctorum -. kernel/bpf/verifier.c, ubi munus cum nomine insignito reponit descriptor cum inscriptione structurae typus 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;

(Potest plenam codice inveniri Link). Ita dilatare possumus algorithmum nostrum:

  • dum programmata levat, uerificans recto usu chartae impedit et inscriptione structurae respondentis scribens struct bpf_map

Cum downloading ELF binarii usura libbpf Plus multum agitur, sed in aliis articulis disseremus.

Loading programs and maps without libbpf

Promissum, hic exemplum est lectoribus qui scire volent rationem creare et onerare programmata mappis utitur, sine auxilio libbpf. Hoc esse utile potest cum in ambitu laboras pro quo clientelas aedificare non potes, vel singulas particulas salvas, vel programmata scribens similia. plygenerans BPF codicem in musca.

Ut facilius logicam sequamur, exemplum nostrum ad haec proposita rescribemus xdp-simple. Codex programmatis perfectus et leviter expansus in hoc exemplo reperiri potest SUMMA.

Ratio applicationis nostri talis est:

  • creare genus tabula BPF_MAP_TYPE_ARRAY per imperium BPF_MAP_CREATE,
  • creare programma quo hac tabula utitur;
  • progressio ad coniungere interface lo,

quae vertit in humana as

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

est map_create tabulam facit eodem modo sicut nos in primo exemplo de ratione vocationis bpf - "nucleus, quaeso, fac mihi novam tabulam in forma ordinatae 8 elementorum sicut " __u64 et redde mihi tabella descriptor";

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

Propositum etiam est facile onerare:

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

Capta pars prog_load Est definitio nostrae BPF progressio, ordinata structurarum struct bpf_insn insns[]. Sed quia programmate utimur quod in C habemus, possumus aliquantulum fallere;

$ 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

In summa, oportet scribere 14 instructiones in forma structurarum similia struct bpf_insn (consilium; accipere TUBER desuper, re- legere instructiones sectionem, open . linux/bpf.h ΠΈ linux/bpf_common.h conantur determinare struct bpf_insn insns[] proprio);

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

Exercitium pro eis qui hoc ipsi non scripserunt map_fd.

Una pars magis clausa in programmate nostro relinquitur. xdp_attach. Infeliciter, programmata quasi XDP coniungi non possunt utens ratio vocationis bpf. Homines, qui BPF et XDP creaverunt, erant ex communitate Linux online, quod ea maxime familiari utebantur (non autem ut normalis " people) interface for interacting cum nucleo; netlink bases, vide quoque RFC3549. Simplicissima via ad effectum deducendi xdp_attach exscribend testatem codice e libbpfscilicet ex tabella netlink.cquod est illud quod fecimus, breve illud breviando;

Welcome to the world of netlink bases

Aperire netlink ostium tabernaculi genus 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;
}

Ab hoc nervum legitur:

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

Denique hic munus nostrum est quod nervum aperit et peculiarem nuntium mittit ei qui descriptorem fasciculi continet;

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

Parata itaque sunt omnia ad probationem;

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

Videamus an programmata nostra coniuncta sint 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

Mittamus pings et vide in tabula;

$ 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

Eia, opera omnia. Nota obiter, quod tabula nostra iterum in forma bytes ostenditur. Hoc ex eo quod dissimilis libbpf type informationes non oneratis (BTF). Sed de hoc proximo tempore plura loquemur.

Progressio Tools

In hac sectione spectabimus minimum toolkit BPF elit.

Generaliter, non indigetis speciali ad programmata BPF explicanda - BPF incurrit in quamlibet honestam distributionem nuclei, et programmata utendo aedificantur. clangquae ex sarcina suppleri potest. Attamen, ob hoc quod BPF sub progressione est, nucleus et instrumenta perpetuo mutantur, si nolis scribere programmata BPF utentes methodi antiqui ex MMXIX, tum scribere debebis.

  • llvm/clang
  • pahole
  • et core
  • bpftool

Debian 10.

llvm/clang

BPF amica est cum LLVM et, quamvis nuper programmata BPF utens gcc componi possit, omnis progressio pro LLVM exercetur. Itaque in emendatione ante omnia aedificabimus clang ex 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
... ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ спустя
$

Nunc inspicere possumus si omnia recte convenirent;

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

(Conventus instructions clang capta est a me bpf_devel_QA.)

Programmata quae modo aedificavimus non instituemus, sed eos mox adiciemus PATHFor example:

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

(Hoc potest addi .bashrc aut file separatum. Personaliter haec addo similia ~/bin/activate-llvm.sh et, cum opus sit, id faciam . activate-llvm.sh.)

Pahole et BTF *

utilitas pahole usus est cum aedificaretur nucleus ad creandum debugging informationes in BTF forma. In hoc articulo de singulis technologiarum BTF non descendemus, nisi quod commodum est ac volumus uti. Si ergo tu acturus es nucleum tuum, primum aedifica pahole (sine pahole nucleum cum optione aedificare non poteris 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

Kernels ad experimentum cum BPF

Cum facultates BPF explorans, nucleum meum convenire volo. Hoc, generaliter loquendo, non est necessarium, quia in distributione nuclei programmata BPF scribere et onerare poteris, tamen nucleum proprium habendo te permittit uti notissimis BPF notis, quae in mensibus maxime apparebit in distributione. aut, ut in quibusdam instrumentis debuggingis, in praevisis futuris omnino non coniciatur. Etiam, nucleus suus, gravem experimentum facit cum codice.

Ad nucleum aedificandum opus est, primum ipsum nucleum, deinde fasciculi nuclei conformationem. Experiri cum BPF uti possumus vanilla nucleo, vel uno nucleo evolutionis. Historice, BPF progressio intra communitatem retis Linux fit ac propterea omnes mutationes citius aut serius per David Miller, Linux conservatorem retis, perveniunt. Secundum naturam earum - emendationum vel novarum notarum - retis mutationes in unum e duobus nucleis cadunt - net aut net-next. Mutationes pro BPF eodem modo distributae sunt bpf ΠΈ bpf-nextquae dein in retia et reticula conduntur, respective. For more details, see bpf_devel_QA ΠΈ netdev-FAQ. Sic nucleum elige in tuo gustu ac firmitate necessitates systematis quam probatis (*-next eorum levissimi nuclei enumerantur).

Extra ambitum huius articuli loqui est quomodo nuclei figurarum imaginum regendi - assumitur te aut hoc facere iam scis. paratus ad discere de proprio. Nihilominus, hae instructiones plus minusve sufficiant ut systema operanti BPF-efficiatur.

Download unum ex nucleis supra:

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

Aedificare minimam operationem nucleo config:

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

Admitte BPF options in file .config de tua electione (verisimile CONFIG_BPF iam praestabitur quia systemd illo utitur). Hic index optionum ex nucleo pro hoc articulo usus est:

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

Deinde facile modulos ac nucleos convenire et instituere (obiter nucleum uti recenti conglobato colligere potes. clangper addendo CC=clang):

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

ac reboot cum nova nucleo (utar hoc kexec ex sarcina 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

Frequentissima utilitas in articulo erit utilitas bpftoolpartem Linux nucleo supplevit. Legitur et conservatur a tincidunt BPF pro tincidunt BPF et adhiberi potest ad omnia genera objectorum BPF - programmata oneranda, mappas crea et recensendas, vitam BPF ecosystem explorandum, etc. Documenta in forma principii codicis pro homine paginae inveniri possunt in core vel, compilata; ad network.

In tempore scripturae huius bpftool ad RHEL, Fedora et Ubuntu tantum parata venit (vide, v. gr. hoc filum, qui narrat inchoatam fabulam packaging bpftool in Debian). Si autem iam acinum struxisti, tunc aedifica bpftool tam facile quam 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  ]

$

(hic ${linux} - Hoc presul est nucleus tuus.) His peractis mandata bpftool colligentur in Directory ${linux}/tools/bpf/bpftool et adiicere potest ad viam (primum omnium ad usoris root) Vel iustus effingo to /usr/local/sbin.

Collecta bpftool suus 'optimus ut hoc clangconvenerunt ut supra dictum est, deprime an recte, utendo, verbi gratia, mandato

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

quod ostendet quae lineamenta BPF in nucleo tuo valeant.

Praecedens praeceptum currere potest obiter

# bpftool f p k

Hoc fit per similitudinem cum utilitatibus e sarcina iproute2ubi possumus, e.g ip a s eth0 pro ip addr show dev eth0.

conclusio,

BPF sinit te culicem calceamere ut efficaciter metiaris et in musca mutet functionem nuclei. Systema egregie evenit in optimis traditionibus UNIX: mechanismum simplex, qui te permittit ut programmata nuclei ingentem numerum hominum et consociationum ad experimentum recipiant. Et, licet experimenta, sicut etiam progressio infrastructurae BPF, absunt ab perfectae, ratio iam stabilis ABI permittit ut certa condere, ac potissimum, logica negotia effectiva.

Vellem notare, mea sententia, technicae artis popularis facta esse quod, ex una parte, potest ludere (architectura machinae una vespera plus minusve intelligi potest), et ex altera parte, quaestiones solvendas quae ante suam speciem (pulchre) solvi non possunt. Haec duo membra simul cogunt homines ad experimentum et somnium, quod ad exitum solutionum magis ac magis eget.

Articulus hic, etsi non proprie brevis, tantum prooemium est ad mundum BPF et notas "progressus" et partes architecturae non describit. Propositum progressus est simile hoc: proximus articulus erit perspectus generum programmatis BPF (sunt 5.8 genera programmatis in 30 nucleo suffulta), tunc demum spectabimus quomodo scribenda sint applicationes reales BPF utentes nucleo typum ducens. ut exemplum, tempus est ad altiorem cursum in architectura BPF, quam exempla BPF retis et applicationis securitatis secuti sunt.

Articuli priores in hac serie

  1. BPF pro parvulis, pars nulla: classic BPF

Vincula

  1. BPF et XDP Reference Guide β€” Documenta de BPF e cilio, vel accuratius ex Daniele Borkman, uno ex auctoribus et assertoribus BPF. Haec una est ex primis gravium descriptionibus, quae ab aliis discrepat, quod Daniel prorsus novit quid scribat, et nulla ibi errata sunt. Praesertim hoc documentum describit quomodo operari cum BPF programmata XDP et TC specierum notae utilitatis utentes. ip ex sarcina iproute2.

  2. Documentation/networking/filter.txt β€” fasciculus originalis cum documentis pro classicis et deinde extensis BPF. Bona lege, si vis in conventum linguam et singulas architecturas technicas ingredi.

  3. Blog about BPF from facebook. Raro renovatur, sed apte, ut Alexei Starovoitov (auctor eBPF) et Andrii Nakryiko - (contentor) ibi scribunt. libbpf).

  4. Secreta bpftool. Delectatio twitter filo Quintini Monnet cum exemplis et arcanis utendi bpftool.

  5. BPF in dive: a album lectionis materiales. Colossus (et adhuc servatur) indicem nexuum cum BPF documentis e Quentin Monnet.

Source: www.habr.com