Usa ka Mubo nga Pasiuna sa BPF ug eBPF

Hello, Habr! Gusto namon ipahibalo kanimo nga nag-andam kami usa ka libro alang sa pagpagawas."Linux Observability uban sa BPF".

Usa ka Mubo nga Pasiuna sa BPF ug eBPF
Tungod kay ang BPF virtual machine nagpadayon sa pag-uswag ug aktibo nga gigamit sa praktis, gihubad namo alang kanimo ang usa ka artikulo nga naghulagway sa mga nag-unang kapabilidad niini ug sa kasamtangan nga kahimtang.

Sa bag-ohay nga mga tuig, ang mga himan sa pagprograma ug mga teknik nahimong mas popular aron mabayran ang mga limitasyon sa Linux kernel sa mga kaso diin gikinahanglan ang pagproseso sa packet nga adunay taas nga performance. Usa sa labing popular nga mga teknik sa niini nga matang mao ang gitawag kernel bypass (kernel bypass) ug nagtugot, sa pag-bypass sa kernel network layer, sa paghimo sa tanang packet processing gikan sa user space. Ang pag-bypass sa kernel naglakip usab sa pagkontrol sa network card gikan sa user nga luna. Sa laing pagkasulti, kung nagtrabaho sa usa ka network card, nagsalig kami sa drayber user nga luna.

Pinaagi sa pagbalhin sa bug-os nga kontrol sa network card ngadto sa usa ka user-space program, atong gipakunhod ang kernel overhead (pagbalhin sa konteksto, pagproseso sa layer sa network, mga interrupts, ug uban pa), nga importante kaayo kon modagan sa gikusgon nga 10Gb/s o mas taas pa. Kernel bypass ug kombinasyon sa ubang mga feature (pagproseso sa batch) ug maampingong pag-tune sa performance (NUMA accounting, Pag-inusara sa CPU, ug uban pa) katumbas sa mga sukaranan sa pagproseso sa high-performance nga network sa wanang sa tiggamit. Tingali ang usa ka panig-ingnan nga pananglitan niining bag-ong pamaagi sa pagproseso sa packet mao ang DPDK gikan sa Intel (Data Plane Development Kit), bisan tuod adunay uban pang iladong mga himan ug mga teknik, lakip ang Cisco's VPP (Vector Packet Processing), Netmap ug, siyempre, Snabb.

Ang pag-organisar sa mga interaksyon sa network sa wanang sa tiggamit adunay daghang mga disbentaha:

  • Ang OS kernel kay abstraction layer para sa hardware resources. Tungod kay ang mga programa sa wanang sa gumagamit kinahanglan nga direktang magdumala sa ilang mga kahinguhaan, kinahanglan usab nila ang pagdumala sa ilang kaugalingon nga hardware. Kanunay kini nagpasabut nga kinahanglan nimo nga i-program ang imong kaugalingon nga mga drayber.
  • Tungod kay bug-os namong gitugyan ang luna sa kernel, gitugyan usab namo ang tanang kagamitan sa networking nga gihatag sa kernel. Ang mga programa sa espasyo sa tiggamit kinahanglan nga mag-implementar pag-usab sa mga bahin nga mahimo nang gihatag sa kernel o operating system.
  • Ang mga programa naglihok sa sandbox mode, nga seryoso nga naglimite sa ilang interaksyon ug nagpugong kanila sa pag-integrate sa ubang bahin sa operating system.

Sa esensya, kung ang networking mahitabo sa user space, ang performance gains makab-ot pinaagi sa pagbalhin sa packet processing gikan sa kernel ngadto sa user space. Ang XDP sukwahi gayod: kini nagpalihok sa mga programa sa networking gikan sa luna sa user (mga filter, solver, routing, ug uban pa) ngadto sa kernel space. Gitugotan kami sa XDP sa paghimo sa usa ka function sa network sa diha nga ang usa ka pakete naigo sa usa ka interface sa network ug sa wala pa kini magsugod sa paglihok sa kernel network subsystem. Ingon usa ka sangputanan, ang katulin sa pagproseso sa pakete labi nga nagdugang. Bisan pa, giunsa pagtugot sa kernel ang tiggamit nga ipatuman ang ilang mga programa sa wanang sa kernel? Sa dili pa tubagon kini nga pangutana, atong tan-awon kung unsa ang BPF.

BPF ug eBPF

Bisan pa sa makalibog nga ngalan, ang BPF (Berkeley Packet Filtering), sa tinuud, usa ka modelo sa virtual machine. Kini nga virtual nga makina orihinal nga gidisenyo sa pagdumala sa packet filtering, busa ang ngalan.

Usa sa labing inila nga mga himan gamit ang BPF mao ang tcpdump. Sa pagkuha sa mga pakete gamit tcpdump ang user mahimong magpiho sa usa ka ekspresyon sa pagsala sa mga pakete. Ang mga pakete ra nga katumbas sa kini nga ekspresyon ang makuha. Pananglitan, ang ekspresyong β€œtcp dst port 80” nagtumong sa tanang TCP packets nga moabot sa port 80. Ang compiler makapamubo niini nga ekspresyon pinaagi sa pag-convert niini ngadto sa BPF bytecode.

$ 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

Mao kini ang kasagarang gibuhat sa programa sa ibabaw:

  • Instruksyon (000): Ikarga ang pakete sa offset 12, isip 16-bit nga pulong, ngadto sa accumulator. Ang offset 12 katumbas sa ethertype sa pakete.
  • Instruksyon (001): nagtandi sa bili sa accumulator sa 0x86dd, nga mao, uban sa ethertype nga bili alang sa IPv6. Kung tinuod ang resulta, nan ang counter sa programa moadto sa panudlo (002), ug kung dili, dayon sa (006).
  • Instruksyon (006): nagtandi sa bili sa 0x800 (ethertype nga bili alang sa IPv4). Kung ang tubag tinuod, nan ang programa moadto sa (007), kung dili, dayon sa (015).

Ug uban pa hangtud nga ang packet filtering program mibalik og resulta. Kini kasagaran usa ka Boolean. Ang pagbalik sa usa ka dili zero nga kantidad (instruksyon (014)) nagpasabut nga ang pakete gidawat, ug ang pagbalik sa usa ka zero nga kantidad (instruksyon (015)) nagpasabut nga ang pakete wala gidawat.

Ang BPF virtual machine ug ang bytecode niini gisugyot ni Steve McCann ug Van Jacobson sa ulahing bahin sa 1992 sa dihang gimantala ang ilang papel BSD Packet Filter: Bag-ong Arkitektura para sa User-Level Packet Capture, kini nga teknolohiya unang gipresentar sa komperensya sa Usenix sa tingtugnaw sa 1993.

Tungod kay ang BPF usa ka virtual nga makina, kini naghubit sa palibot diin ang mga programa nagdagan. Dugang pa sa bytecode, gihubit usab niini ang modelo sa panumduman sa batch (ang mga instruksyon sa pagkarga hingpit nga gipadapat sa batch), mga rehistro (A ug X; mga rehistro sa accumulator ug index), pagtipig sa memorya sa scratch, ug usa ka implicit nga counter sa programa. Makaiikag, ang BPF bytecode gimodelo human sa Motorola 6502 ISA. Sama sa nahinumduman ni Steve McCann sa iyang report sa plenaryo sa Sharkfest '11, pamilyar siya sa build 6502 gikan sa iyang high school days programming sa Apple II, ug kini nga kahibalo nakaimpluwensya sa iyang trabaho sa pagdesinyo sa BPF bytecode.

Ang suporta sa BPF gipatuman sa Linux kernel sa mga bersyon nga v2.5 ug mas taas pa, nga gidugang ilabina sa mga paningkamot ni Jay Schullist. Ang BPF code nagpabilin nga wala mausab hangtod sa 2011, sa dihang gidesinyo pag-usab ni Eric Dumaset ang BPF interpreter aron modagan sa JIT mode (Source: JIT alang sa mga packet filter). Pagkahuman niini, ang kernel, imbis nga maghubad sa BPF bytecode, mahimong direkta nga magbag-o sa mga programa sa BPF sa target nga arkitektura: x86, ARM, MIPS, ug uban pa.

Sa ulahi, sa 2014, gisugyot ni Alexey Starovoitov ang usa ka bag-ong mekanismo sa JIT alang sa BPF. Sa tinuud, kining bag-ong JIT nahimong bag-ong arkitektura nga nakabase sa BPF ug gitawag nga eBPF. Sa akong hunahuna ang duha nga mga VM nag-uban sa pipila ka panahon, apan sa pagkakaron ang packet filtering gipatuman base sa eBPF. Sa tinuud, sa daghang mga pananglitan sa modernong dokumentasyon, ang BPF gisabot nga eBPF, ug ang klasikal nga BPF karon nailhan nga cBPF.

Ang eBPF nagpalapad sa klasiko nga BPF virtual machine sa daghang mga paagi:

  • Gibase sa modernong 64-bit nga mga arkitektura. Ang eBPF naggamit sa 64-bit nga mga rehistro ug nagdugang sa gidaghanon sa magamit nga mga rehistro gikan sa 2 (accumulator ug X) ngadto sa 10. Ang eBPF naghatag usab og dugang nga mga opcode (BPF_MOV, BPF_JNE, BPF_CALL...).
  • Nahimulag gikan sa network layer subsystem. Ang BPF gihigot sa batch data model. Tungod kay gigamit kini alang sa pagsala sa pakete, ang code niini nahimutang sa subsystem nga naghatag mga komunikasyon sa network. Bisan pa, ang eBPF virtual machine wala na nahigot sa modelo sa datos ug mahimong magamit sa bisan unsang katuyoan. Busa, karon ang programa sa eBPF mahimong konektado sa tracepoint o kprobe. Kini nagbukas sa dalan sa eBPF instrumentation, performance analysis, ug daghang uban pang mga kaso sa paggamit sa konteksto sa ubang kernel subsystems. Karon ang eBPF code nahimutang sa kaugalingon nga agianan: kernel/bpf.
  • Mga tindahan sa datos sa kalibutan nga gitawag og Maps. Ang mga mapa kay key-value stores nga makapahimo sa data exchange tali sa user space ug kernel space. Ang eBPF naghatag ug daghang klase sa mga mapa.
  • Ikaduha nga mga gimbuhaton. Sa partikular, aron masulat pag-usab ang usa ka pakete, kuwentaha ang usa ka checksum, o i-clone ang usa ka pakete. Kini nga mga gimbuhaton nagdagan sulod sa kernel ug dili mga programa sa user-space. Makahimo ka usab og mga tawag sa sistema gikan sa mga programa sa eBPF.
  • Tapuson ang mga tawag. Ang gidak-on sa programa sa eBPF limitado sa 4096 bytes. Ang feature sa tail call nagtugot sa usa ka eBPF nga programa sa pagbalhin sa kontrol ngadto sa usa ka bag-ong eBPF nga programa ug sa ingon makalaktaw niini nga limitasyon (hangtod sa 32 ka mga programa mahimong masumpay niining paagiha).

eBPF: pananglitan

Adunay daghang mga pananglitan alang sa eBPF sa mga gigikanan sa kernel sa Linux. Anaa sila sa mga sample/bpf/. Aron ma-compile kini nga mga pananglitan, pagsulod lang:

$ sudo make samples/bpf/

Dili ko mosulat ug bag-ong pananglitan para sa eBPF sa akong kaugalingon, apan gamiton ang usa sa mga sample nga anaa sa samples/bpf/. Akong tan-awon ang pipila ka bahin sa code ug ipasabut kung giunsa kini molihok. Ingon usa ka pananglitan, gipili nako ang programa tracex4.

Sa kinatibuk-an, ang matag usa sa mga pananglitan sa mga sample/bpf/ naglangkob sa duha ka mga file. Niini nga kaso:

  • tracex4_kern.c, naglangkob sa source code nga ipatuman sa kernel isip eBPF bytecode.
  • tracex4_user.c, naglangkob sa usa ka programa gikan sa user space.

Sa kini nga kaso, kinahanglan namon nga mag-compile tracex4_kern.c sa eBPF bytecode. Sa pagkakaron sa gcc walay backend para sa eBPF. Maayo na lang, clang maka-output sa eBPF bytecode. Makefile naggamit clang para sa compilation tracex4_kern.c sa object file.

Gihisgutan ko sa ibabaw nga ang usa sa labing makapaikag nga bahin sa eBPF mao ang mga mapa. Ang tracex4_kern naghubit sa usa ka mapa:

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 mao ang usa sa daghang mga matang sa mga kard nga gitanyag sa eBPF. Sa kini nga kaso, kini usa lamang ka hash. Tingali nakamatikod ka usab sa usa ka ad SEC("maps"). Ang SEC usa ka macro nga gigamit sa paghimo og bag-ong seksyon sa binary file. Sa tinuud, sa pananglitan tracex4_kern duha pa ka seksyon ang gihubit:

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

Kining duha ka mga function nagtugot kanimo sa pagtangtang sa usa ka entry gikan sa mapa (kprobe/kmem_cache_free) ug pagdugang og bag-ong entry sa mapa (kretprobe/kmem_cache_alloc_node). Ang tanan nga mga ngalan sa function nga gisulat sa dagkong mga letra katumbas sa mga macro nga gipasabut sa bpf_helpers.h.

Kung akong ihulog ang mga seksyon sa object file, kinahanglan nakong makita nga kini nga mga bag-ong seksyon gihubit na:

$ 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

Adunay usab tracex4_user.c, nag-unang programa. Sa panguna, kini nga programa naminaw sa mga panghitabo kmem_cache_alloc_node. Kung mahitabo ang ingon nga panghitabo, ang katugbang nga eBPF code ipatuman. Ang code nagtipig sa IP attribute sa butang ngadto sa usa ka mapa, ug ang butang gi-loop sa main program. Pananglitan:

$ 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

Giunsa ang usa ka programa sa espasyo sa gumagamit ug usa ka programa sa eBPF nga adunay kalabotan? Sa pagsugod tracex4_user.c nagkarga ug object file tracex4_kern.o gamit ang function 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;
}

Samtang gibuhat load_bpf_file Ang mga pagsusi nga gihubit sa eBPF file gidugang sa /sys/kernel/debug/tracing/kprobe_events. Karon naminaw kami niini nga mga panghitabo ug ang among programa adunay mahimo kung kini mahitabo.

$ 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

Ang tanan nga uban pang mga programa sa sample/bpf/ parehas nga pagkahan-ay. Kanunay silang adunay duha ka mga file:

  • XXX_kern.c: programa sa eBPF.
  • XXX_user.c: nag-unang programa.

Ang programa sa eBPF nagpaila sa mga mapa ug mga gimbuhaton nga nalangkit sa usa ka seksyon. Kung ang kernel nag-isyu sa usa ka panghitabo sa usa ka matang (pananglitan, tracepoint), ang gigapos nga mga gimbuhaton gipatuman. Ang mga kard naghatag og komunikasyon tali sa kernel program ug sa user space program.

konklusyon

Kini nga artikulo naghisgot sa BPF ug eBPF sa kinatibuk-ang termino. Nahibal-an ko nga adunay daghang kasayuran ug mga kapanguhaan bahin sa eBPF karon, busa magrekomenda ako og pipila pa nga mga kapanguhaan alang sa dugang nga pagtuon

Girekomenda nako ang pagbasa:

Source: www.habr.com

Idugang sa usa ka comment