Brevis Introductio ad BPF et eBPF*

Heus Habr! Tibi notificamus nos paramus librum dimittere "Linux Observabilitas cum BPF".

Brevis Introductio ad BPF et eBPF*
Cum BPF machina virtualis evolutionis pergit et active usus est in praxi, articulum nostrum interpretati sumus tibi delineatum eius praecipuum et statum currentem.

Superioribus annis, instrumenta programmandi et technicae popularis lucrati sunt ut limites nuclei Linux compenset in casibus in quibus summus effectus processus fasciculus requiritur. Una e celeberrimis eiusmodi methodis vocatur core bypass (nucleo bypass) et sinit, omissis retis iacuit nuclei, omnem fasciculum processus ab spatio usoris conficere. Praeteriens nucleum etiam involvit administrandi retiacula card e user spatium. Id est, cum opus retis, in auriga fidimus user spatium.

Cum plenam potestatem retis ad programmatum usoris spatium transferendo, caput nuclei (context virgas, processus retis iacuit, obloquitur, etc.), quod satis magni momenti est, cum velocitatibus 10 Gb/s vel cursu currit. altior. Praeteriens nucleus plus compositum ex aliis features (batch processus) Et diligens effectus tuning (NUMA ratio, CPU solitudo, etc.) apta ad fundamenta fundamentalis spatii retis usoris. Forsitan exemplaris huius novi accessus ad conleci processui exemplum est DPDK ex Intel (Data Plane Development Kit) , licet alia instrumenta et artes notae sint, inclusa VPP a Cisco (Vector Packet Processing), Netmap et, sane, Snab.

Organizationis retis interationes in spatio usoris plura incommoda habet:

  • Kernel OS est abstractio strati pro opibus ferrariis. Quia programmata spatii usoris habent suas facultates directe administrare, ipsi etiam sua ferramenta disponere debent. Hoc saepe significat programmatio propria coegi.
  • Cum spatium nuclei omnino relinquimus, etiam omnem functionem retis ad nucleum omittimus. Programmata spatium usoris habent ad lineamenta re- perficienda quae iam a nucleo vel systemate operante provideri possunt.
  • Programmata in sandbox in modum operantur, qui eorum commercium graviter limitat et impedit ne cum aliis systematis operantis partibus integrari possit.

Essentialiter, cum networking in spatio usoris, quaestus effectus efficiuntur movendo fasciculum processus a nucleo ad spatium usoris. XDP prorsus contrarium facit: progressio retis movet ab spatio usoris (filterae, converters, fugans, etc.) ad aream nuclei. XDP nobis permittit ut munus retis exsequi quam primum fasciculum retis interfaciei ferit et antequam incipit ire usque ad subsystem retis nuclei. Quam ob rem celeritas processus fasciculus insigniter augetur. Sed quomodo nucleus permittit utentem ad programmata sua in spatio nucleo currere? Priusquam huic quaestioni respondeat, inspiciamus quid sit BPF.

BPF et eBPF *

Quamvis nomen non omnino clarum, BPF (Packet Filtering, Berkeley) revera exemplar machinae virtualis est. Haec virtualis machina initio destinata est ad fasciculum eliquandum tractandum, unde nomen.

Unus e notioribus instrumentis utens BPF est tcpdump. Captis cum facis tcpdump usor exprimere potest expressionem fasciculi eliquare. Tantum fasciculi qui huic locutioni congruit capientur. Verbi gratia, "tcp dst port 80” refert ad omnes fasciculos TCP venientes in portum 80. Compilator hanc locutionem minuere potest, eam in BPF bytecode convertens.

$ sudo tcpdump -d "tcp dst port 80"
(000) ldh [12] (001) jeq #0x86dd jt 2 jf 6
(002) ldb [20] (003) jeq #0x6 jt 4 jf 15
(004) ldh [56] (005) jeq #0x50 jt 14 jf 15
(006) jeq #0x800 jt 7 jf 15
(007) ldb [23] (008) jeq #0x6 jt 9 jf 15
(009) ldh [20] (010) jset #0x1fff jt 15 jf 11
(011) ldxb 4*([14]&0xf)
(012) ldh [x + 16] (013) jeq #0x50 jt 14 jf 15
(014) ret #262144
(015) ret #0

Hoc est plerumque id quod supra programma agit:

  • Instructio (000): fasciculum onerat ad XII cinguli, ut XVI frenum verbum, in accumulatorem. XII cinguli ethertypi fasciculi correspondet.
  • Instructio (001): comparat valorem accumulatoris cum 0x86dd, id est, valorem etertypi pro IPv6. Si effectus est verum, ratio calculo instruitur (002), et si non, tunc ad (006).
  • Instructio (006): valorem cum 0x800 (pretii etertypi IPv4) comparat. Si responsio vera est, programma vadit ad (007), si non, tunc ad (015).

Et sic deinceps, donec programmata eliquandi fasciculum exitum redderet. Soleat sit boolean. Revertere in valorem non-nullam (instructionem (014)) significat fasciculum aequare, ac nulla reverti (instructionem (015)) significat fasciculum non aequare.

BPF machina virtualis eiusque bytecode propositae Steve McCann et Van Jacobson nuper 1992 cum charta eorum prodierunt. BSD fasciculum Filter: Nova architectura pro user-gradu fasciculum captisprimum haec technologia in colloquio Usenix hieme 1993 exhibita est.

Quia BPF machina virtualis est, ambitum definit in quo programmata currunt. Praeter bytecode, etiam fasciculum memoriae exemplar definit (instructiones oneris implicite ad fasciculum applicatae), registra (A et X; accumulator et index registra), memoriam repositionis scalpere et programmata implicata calculi. Interestingly, BPF bytecode post Motorola 6502 exemplar ISA. Sicut Steve McCann recordatus est in his plenaria fama apud Sharkfest '11, nota erat 6502 ex alta schola aedificandi cum programmandi in Apple II, et haec cognitio opus suum movit designandi BPF bytecode.

BPF subsidium in Linux nucleo in versione v2.5 perficiendum est et postea, maxime a Jay Schullist additur. In codice BPF mutatus est usque ad MMXI, cum Eric Dumaset BPF interpres resignavit modus operandi in JIT (Source: JIT ad Packet Filtra). Postea, loco BPF bytecode interpretandi, nucleus progressiones BPF ad scopum architecturae directe convertere potuit: x86, ARM, MIPS, etc.

Postea, anno MMXIV, Alexei Starovoitov novam machinam JIT pro BPF proposuit. Re quidem vera haec nova JIT nova architectura in BPF facta est et appellata eBPF est. Puto utrumque VMs aliquo tempore coexistisse, sed fasciculum eliquationis in capite eBPF nunc impleri. Revera in multis documentis recentioribus exemplis, BPF refertur ad eBPF, et classica BPF hodie notus est ut CBPF.

eBPF extendit machinam virtualem classicam BPF pluribus modis:

  • In hodiernis 64-bit architecturis nititur. eBPF utitur tabulariis 64-bit et numerum registrorum promptorum ab 2 (accumulatore et X) ad 10. addit etiam opcodes (BPF_MOV, BPF_JNE, BPF_CALL...) praebet.
  • Quisque a accumsan ipsum. BPF ligatum ad exemplar batch data. Cum ad fasciculos spargendos adhibitum est, signum eius in subsystem fuit quod interationes retiaculas praebebat. Attamen machina virtualis eBPF non iam ad exemplar datae alligata est et ad quemlibet usum adhiberi potest. Nunc ergo eBPF programma cum trace puncto vel kprobe coniungi potest. Haec ianuam aperit instrumentationi eBPF, analysi perficiendi, et multi alii casus utendi in contextu subsystematum aliorum nucleorum. Nunc eBPF codicem in suo itinere situm est: kernel/bpf.
  • Global notitia repono maps appellata. Tabulae geographicae pretii thesauri sunt qui notitias mutuas inter spatium usoris et spatium nuclei praebent. eBPF varia genera chartarum praebet.
  • Munera secundaria. Praesertim rescribere sarcinam, calculare checksum, vel clone involucrum. Hae functiones intra nucleum currunt nec ad programmata spatii usuarii pertinent. Praeterea ratio vocationis fieri potest ex programmatibus eBPF.
  • Finis vocat. Programma amplitudo in EBPF 4096 bytes limitatur. Finis vocationi pluma permittit rationem eBPF ut imperium ad novum eBPF programmatis transferat et sic limitationem praetermittens (usque ad 32 programmata hoc modo ligari potest).

eBPF example

Exempla plura sunt pro eBPF in fontibus nuclei Linux. Praesto sunt ad exempla/bpf/. Ad exempla haec ordinanda, sicut typus:

$ sudo make samples/bpf/

Non novi exemplum pro eBPF me scribens, sed uno exemplorum exemplorum in promptu adhibebo /bpf/. Partes codicis aliquas inspiciam et quomodo opera eius exponam. Exemplum, propositum elegi tracex4.

Fere singula exempla in exemplis/bpf/ duobus scriniis constant. In hoc casu:

  • tracex4_kern.c, fontem codicis in nucleo bytecode eBPF exsecutioni mandandam continet.
  • tracex4_user.c, programma continet ex spatio usoris.

Hoc in casu, compilare opus est tracex4_kern.c ad eBPF bytecode. In momento in gcc nulla pars servo pro eBPF. Fortunate, clang potest producendum eBPF bytecode. Makefile usus clang ordinare tracex4_kern.c objectum lima.

Supra monui unam ex maxime interesting lineamentis eBPF esse mappis. tracex4_kern una tabula definit:

struct pair {
    u64 val;
    u64 ip;
};  

struct bpf_map_def SEC("maps") my_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(long),
    .value_size = sizeof(struct pair),
    .max_entries = 1000000,
};

BPF_MAP_TYPE_HASH unus e multis generibus chartarum ab eBPF oblatis. Hic, iustus Nullam. Etiam notavi ad SEC("maps"). SEC tortor usus est ut novam sectionem fasciculi binarii crearet. Nam in exemplum tracex4_kern duae plures sectiones definiuntur;

SEC("kprobe/kmem_cache_free")
int bpf_prog1(struct pt_regs *ctx)
{   
    long ptr = PT_REGS_PARM2(ctx);

    bpf_map_delete_elem(&my_map, &ptr); 
    return 0;
}
    
SEC("kretprobe/kmem_cache_alloc_node") 
int bpf_prog2(struct pt_regs *ctx)
{
    long ptr = PT_REGS_RC(ctx);
    long ip = 0;

    // получаем ip-адрес вызывающей стороны kmem_cache_alloc_node() 
    BPF_KRETPROBE_READ_RET_IP(ip, ctx);

    struct pair v = {
        .val = bpf_ktime_get_ns(),
        .ip = ip,
    };
    
    bpf_map_update_elem(&my_map, &ptr, &v, BPF_ANY);
    return 0;
}   

Hae duae functiones permittunt ut ingressum ex tabula removeas (kprobe/kmem_cache_free) et novam ingressum in chartam add.kretprobe/kmem_cache_alloc_node). Omnes functiones nomina in litteris maiusculis scripta correspondent macros definitos bpf_helpers.h.

Si sectiones fasciculi obiecti excutiam, viderem has novas sectiones iam definitas esse;

$ objdump -h tracex4_kern.o

tracex4_kern.o: file format elf64-little

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000000 0000000000000000 0000000000000000 00000040 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 kprobe/kmem_cache_free 00000048 0000000000000000 0000000000000000 00000040 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
2 kretprobe/kmem_cache_alloc_node 000000c0 0000000000000000 0000000000000000 00000088 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
3 maps 0000001c 0000000000000000 0000000000000000 00000148 2**2
CONTENTS, ALLOC, LOAD, DATA
4 license 00000004 0000000000000000 0000000000000000 00000164 2**0
CONTENTS, ALLOC, LOAD, DATA
5 version 00000004 0000000000000000 0000000000000000 00000168 2**2
CONTENTS, ALLOC, LOAD, DATA
6 .eh_frame 00000050 0000000000000000 0000000000000000 00000170 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

Ibi quoque est tracex4_user.c, progressio principalis. Plerumque, haec programma certe audit kmem_cache_alloc_node. Cum tale eventum incidit, codice respondente eBPF afficitur. Codex IP attributum servat objecti per chartam, et deinde res per principale programmatis tragulatur. Exemplum:

$ sudo ./tracex4
obj 0xffff8d6430f60a00 is 2sec old was allocated at ip ffffffff9891ad90
obj 0xffff8d6062ca5e00 is 23sec old was allocated at ip ffffffff98090e8f
obj 0xffff8d5f80161780 is 6sec old was allocated at ip ffffffff98090e8f

Quomodo sunt programmata spatii usoris et programmata eBPF relata? In initialization tracex4_user.c onerat object file tracex4_kern.o per munus load_bpf_file.

int main(int ac, char **argv)
{
    struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
    char filename[256];
    int i;

    snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);

    if (setrlimit(RLIMIT_MEMLOCK, &r)) {
        perror("setrlimit(RLIMIT_MEMLOCK, RLIM_INFINITY)");
        return 1;
    }

    if (load_bpf_file(filename)) {
        printf("%s", bpf_log_buf);
        return 1;
    }

    for (i = 0; ; i++) {
        print_old_objects(map_fd[1]);
        sleep(1);
    }

    return 0;
}

Dum faciunt load_bpf_file speculatoriae definitae in eBPF lima additae sunt /sys/kernel/debug/tracing/kprobe_events. Nunc de his rebus auscultamus et propositum nostrum aliquid facere potest cum eveniunt.

$ sudo cat /sys/kernel/debug/tracing/kprobe_events
p:kprobes/kmem_cache_free kmem_cache_free
r:kprobes/kmem_cache_alloc_node kmem_cache_alloc_node

Cetera omnia programmata in sample/bpf/ similiter exstructa sunt. Duo semper continent files:

  • XXX_kern.c: progressio eBPF.
  • XXX_user.c: principale propositum.

Programma eBPF definit tabulas et functiones cum sectione consociata. Cum nucleus eventus cuiusdam generis emittit (ex. gr. tracepointquod, sicut dictum est, munera ligata exercentur. Tabulae communicationem praebent inter programmata nuclei et programmata spatii usoris.

conclusio,

In hoc articulo, BPF, eBPF, generaliter disputatum est. Scio multas informationes et facultates circa eBPF esse hodie, ut paucas plures materias ulterioris studii commendem.

Lectionem commendo;

Source: www.habr.com

Add a comment