BPF va eBPF ga qisqacha kirish

Salom, Xabr! Kitobni nashrga tayyorlayotganimizni ma’lum qilamiz”.BPF bilan Linuxni kuzatish".

BPF va eBPF ga qisqacha kirish
BPF virtual mashinasi rivojlanishda davom etayotganligi va amaliyotda faol qo'llanilayotganligi sababli biz siz uchun uning asosiy imkoniyatlari va hozirgi holatini tavsiflovchi maqolani tarjima qildik.

So'nggi yillarda yuqori samarali paketlarni qayta ishlash zarur bo'lgan hollarda Linux yadrosining cheklovlarini qoplash uchun dasturlash vositalari va usullari tobora ommalashib bormoqda. Ushbu turdagi eng mashhur texnikalardan biri deyiladi yadro chetlab o'tish (yadro bypass) va yadro tarmog'i qatlamini chetlab o'tib, foydalanuvchi maydonidan barcha paketlarni qayta ishlashni amalga oshirishga imkon beradi. Yadroni chetlab o'tish tarmoq kartasini boshqarishni ham o'z ichiga oladi foydalanuvchi maydoni. Boshqacha qilib aytganda, tarmoq kartasi bilan ishlashda biz haydovchiga tayanamiz foydalanuvchi maydoni.

Tarmoq kartasini to'liq boshqarishni foydalanuvchi-kosmik dasturga o'tkazish orqali biz yadro yukini (kontekstni almashtirish, tarmoq qatlamini qayta ishlash, uzilishlar va boshqalar) kamaytiramiz, bu 10 Gb / s yoki undan yuqori tezlikda ishlaganda juda muhimdir. Yadro bypass va boshqa xususiyatlarning kombinatsiyasi (ommaviy qayta ishlash) va ehtiyotkorlik bilan ishlashni sozlash (NUMA hisobi, CPU izolyatsiyasiva boshqalar) foydalanuvchi makonida yuqori samarali tarmoqni qayta ishlash asoslariga mos keladi. Ehtimol, paketlarni qayta ishlashga yangi yondashuvning namunali misoli bo'lishi mumkin DPDK Inteldan (Ma'lumotlar tekisligini ishlab chiqish to'plami), boshqa taniqli vositalar va texnikalar mavjud bo'lsa-da, jumladan Cisco VPP (Vector Packet Processing), Nemap va, albatta, snab.

Foydalanuvchi makonida tarmoq shovqinlarini tashkil qilish bir qator kamchiliklarga ega:

  • OT yadrosi apparat resurslari uchun abstraksiya qatlamidir. Foydalanuvchi kosmik dasturlari o'z resurslarini to'g'ridan-to'g'ri boshqarishi kerakligi sababli, ular o'zlarining apparat vositalarini ham boshqarishlari kerak. Bu ko'pincha o'z drayverlaringizni dasturlash kerakligini anglatadi.
  • Biz yadro maydonidan butunlay voz kechganimiz sababli, yadro tomonidan taqdim etilgan barcha tarmoq funksiyalaridan ham voz kechamiz. Foydalanuvchilar uchun mo'ljallangan dasturlar yadro yoki operatsion tizim tomonidan taqdim etilishi mumkin bo'lgan funktsiyalarni qayta amalga oshirishi kerak.
  • Dasturlar sandbox rejimida ishlaydi, bu ularning o'zaro ta'sirini jiddiy ravishda cheklaydi va operatsion tizimning boshqa qismlari bilan integratsiyalashuviga to'sqinlik qiladi.

Aslini olganda, foydalanuvchi makonida tarmoqqa ulanganda, paketlarni qayta ishlash yadrodan foydalanuvchi maydoniga ko'chirish orqali samaradorlikka erishiladi. XDP buning teskarisini bajaradi: u tarmoq dasturlarini foydalanuvchi maydonidan (filtrlar, rezolyutsiyalar, marshrutlash va boshqalar) yadro maydoniga o'tkazadi. XDP bizga paket tarmoq interfeysiga kirishi bilanoq va yadro tarmog'i quyi tizimiga o'tishni boshlashdan oldin tarmoq funksiyasini bajarishga imkon beradi. Natijada, paketlarni qayta ishlash tezligi sezilarli darajada oshadi. Biroq, yadro foydalanuvchiga yadro maydonida o'z dasturlarini bajarishga qanday ruxsat beradi? Bu savolga javob berishdan oldin, keling, BPF nima ekanligini ko'rib chiqaylik.

BPF va eBPF

Chalkash nomiga qaramay, BPF (Berkeley Packet Filtering) aslida virtual mashina modelidir. Ushbu virtual mashina dastlab paketlarni filtrlashni boshqarish uchun mo'ljallangan, shuning uchun nomi.

BPF dan foydalanadigan eng mashhur vositalardan biri tcpdump. yordamida paketlarni qo'lga olishda tcpdump foydalanuvchi paketlarni filtrlash uchun ifodani belgilashi mumkin. Faqat ushbu ifodaga mos keladigan paketlar yozib olinadi. Masalan, ibora "tcp dst port 80” 80-portga kelgan barcha TCP paketlariga ishora qiladi. Kompilyator bu ifodani BPF bayt-kodiga aylantirish orqali qisqartirishi mumkin.

$ 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

Yuqoridagi dastur asosan shunday qiladi:

  • Yo'riqnoma (000): Paketni 12-ofsetda, 16-bitli so'z sifatida akkumulyatorga yuklaydi. Ofset 12 paketning etertipiga mos keladi.
  • Ko'rsatma (001): akkumulyatordagi qiymatni 0x86dd bilan, ya'ni IPv6 uchun etertip qiymati bilan solishtiradi. Agar natija to'g'ri bo'lsa, u holda dastur hisoblagichi ko'rsatmalarga (002), agar bo'lmasa, (006) ga o'tadi.
  • Ko'rsatma (006): qiymatni 0x800 (IPv4 uchun etertip qiymati) bilan taqqoslaydi. Agar javob to'g'ri bo'lsa, dastur (007), bo'lmasa, (015) ga o'tadi.

Va shunga o'xshash paketlarni filtrlash dasturi natijani qaytarmaguncha. Bu odatda Boolean. Nolga teng bo'lmagan qiymatni qaytarish (ko'rsatma (014)) paketning qabul qilinganligini anglatadi va nol qiymatini qaytarish (ko'rsatma (015)) paketning qabul qilinmaganligini anglatadi.

BPF virtual mashinasi va uning bayt-kodi 1992 yil oxirida Stiv Makkann va Van Jeykobson tomonidan maqolalari chop etilganda taklif qilingan. BSD paket filtri: foydalanuvchi darajasidagi paketlarni yozib olish uchun yangi arxitektura, bu texnologiya birinchi marta 1993 yilning qishida Usenix konferensiyasida taqdim etilgan.

BPF virtual mashina bo'lganligi sababli, u dasturlar ishlaydigan muhitni belgilaydi. Bayt-kodga qo'shimcha ravishda u ommaviy xotira modelini (yuklash bo'yicha ko'rsatmalar paketga bevosita qo'llaniladi), registrlarni (A va X; akkumulyator va indeks registrlari), skretch xotirasini saqlashni va yashirin dastur hisoblagichini ham belgilaydi. Qizig'i shundaki, BPF baytkodi Motorola 6502 ISA dan keyin modellashtirilgan. Stiv MakKen o'z asarida eslaganidek yalpi majlis hisoboti Sharkfest '11 da u o'rta maktab davridagi Apple II da dasturlash 6502-qurilish bilan tanish edi va bu bilim uning BPF bayt kodini loyihalash ishiga ta'sir qildi.

BPF-ni qo'llab-quvvatlash Linux yadrosida v2.5 va undan yuqori versiyalarda amalga oshiriladi, asosan Jey Schullistning sa'y-harakatlari bilan qo'shiladi. BPF kodi 2011 yilgacha, Erik Dumaset BPF tarjimonini JIT rejimida ishlash uchun qayta loyihalashgunga qadar o'zgarishsiz qoldi (Manba: Paket filtrlari uchun JIT). Shundan so'ng, yadro BPF bayt kodini sharhlash o'rniga, BPF dasturlarini to'g'ridan-to'g'ri maqsadli arxitekturaga o'zgartirishi mumkin: x86, ARM, MIPS va boshqalar.

Keyinchalik, 2014 yilda Aleksey Starovoitov BPF uchun yangi JIT mexanizmini taklif qildi. Aslida, bu yangi JIT yangi BPF-ga asoslangan arxitekturaga aylandi va eBPF deb nomlandi. Menimcha, ikkala VM ham bir muncha vaqt birga mavjud edi, ammo hozirda paketlarni filtrlash eBPF asosida amalga oshirilmoqda. Aslida, zamonaviy hujjatlarning ko'plab misollarida BPF eBPF deb tushuniladi va klassik BPF bugungi kunda cBPF sifatida tanilgan.

eBPF klassik BPF virtual mashinasini bir necha usul bilan kengaytiradi:

  • Zamonaviy 64-bitli arxitekturaga asoslangan. eBPF 64 bitli registrlardan foydalanadi va mavjud registrlar sonini 2 tadan (akkumulyator va X) 10 tagacha oshiradi. eBPF shuningdek qo'shimcha opkodlarni (BPF_MOV, BPF_JNE, BPF_CALL...) taqdim etadi.
  • Tarmoq qatlami quyi tizimidan ajratilgan. BPF ommaviy ma'lumotlar modeliga bog'langan. U paketlarni filtrlash uchun ishlatilganligi sababli uning kodi tarmoq aloqalarini ta'minlovchi quyi tizimda joylashgan edi. Biroq, eBPF virtual mashinasi endi ma'lumotlar modeliga bog'lanmagan va har qanday maqsadda ishlatilishi mumkin. Shunday qilib, endi eBPF dasturi tracepoint yoki kprobe-ga ulanishi mumkin. Bu boshqa yadro quyi tizimlari kontekstida eBPF asboblari, ishlash tahlili va boshqa ko'plab foydalanish holatlariga yo'l ochadi. Endi eBPF kodi o'z yo'lida joylashgan: yadro/bpf.
  • Xaritalar deb nomlangan global ma'lumotlar do'konlari. Xaritalar - bu foydalanuvchi maydoni va yadro maydoni o'rtasida ma'lumotlar almashinuvini ta'minlaydigan kalit-qiymat do'konlari. eBPF bir necha turdagi xaritalarni taqdim etadi.
  • Ikkilamchi funktsiyalar. Xususan, paketni qayta yozish, nazorat summasini hisoblash yoki paketni klonlash. Bu funksiyalar yadro ichida ishlaydi va foydalanuvchi-kosmik dasturlar emas. Shuningdek, siz eBPF dasturlaridan tizim qo'ng'iroqlarini amalga oshirishingiz mumkin.
  • Qo'ng'iroqlarni tugatish. eBPF-dagi dastur hajmi 4096 bayt bilan cheklangan. Quyi chaqiruv xususiyati eBPF dasturiga boshqaruvni yangi eBPF dasturiga o'tkazish va shu tariqa ushbu cheklovni chetlab o'tish imkonini beradi (32 tagacha dastur shu tarzda ulanishi mumkin).

eBPF: misol

Linux yadro manbalarida eBPF uchun bir nechta misollar mavjud. Ular namunalar/bpf/ da mavjud. Ushbu misollarni jamlash uchun quyidagilarni kiriting:

$ sudo make samples/bpf/

Men o'zim eBPF uchun yangi misol yozmayman, lekin namunalar/bpf/ da mavjud namunalardan birini ishlataman. Men kodning ba'zi qismlarini ko'rib chiqaman va uning qanday ishlashini tushuntiraman. Misol tariqasida men dasturni tanladim tracex4.

Umuman olganda, samples/bpf/ dagi misollarning har biri ikkita fayldan iborat. Ushbu holatda:

  • tracex4_kern.c, yadroda eBPF bayt kodi sifatida bajariladigan manba kodini o'z ichiga oladi.
  • tracex4_user.c, foydalanuvchi maydonidan dasturni o'z ichiga oladi.

Bunday holda, biz kompilyatsiya qilishimiz kerak tracex4_kern.c eBPF bayt kodiga. Hozirda gcc eBPF uchun backend yo'q. Baxtga, clang eBPF bayt kodini chiqarishi mumkin. Makefile ispolzet clang kompilyatsiya uchun tracex4_kern.c ob'ekt fayliga.

Men eBPF ning eng qiziqarli xususiyatlaridan biri bu xaritalar ekanligini yuqorida aytib o'tdim. tracex4_kern bitta xaritani belgilaydi:

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 eBPF tomonidan taqdim etilgan ko'plab karta turlaridan biridir. Bunday holda, bu shunchaki xash. Siz ham reklamaga e'tibor bergan bo'lishingiz mumkin SEC("maps"). SEC - bu ikkilik faylning yangi qismini yaratish uchun ishlatiladigan makros. Aslida, misolda tracex4_kern yana ikkita bo'lim belgilangan:

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

Bu ikki funksiya xaritadan yozuvni oʻchirish imkonini beradi (kprobe/kmem_cache_free) va xaritaga yangi yozuv qo'shing (kretprobe/kmem_cache_alloc_node). Katta harflar bilan yozilgan barcha funksiya nomlari makroslarda belgilangan bpf_helpers.h.

Agar ob'ekt faylining bo'limlarini tashlab yuborsam, bu yangi bo'limlar allaqachon aniqlanganligini ko'rishim kerak:

$ 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

Hali bor tracex4_user.c, asosiy dastur. Asosan, bu dastur voqealarni tinglaydi kmem_cache_alloc_node. Bunday hodisa sodir bo'lganda, tegishli eBPF kodi bajariladi. Kod ob'ektning IP atributini xaritada saqlaydi va keyin ob'ekt asosiy dastur orqali o'tkaziladi. Misol:

$ 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

Foydalanuvchi kosmik dasturi va eBPF dasturi qanday bog'liq? Boshlashda tracex4_user.c obyekt faylini yuklaydi tracex4_kern.o funksiyasidan foydalanish 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;
}

Qilayotganda load_bpf_file eBPF faylida belgilangan problar qo'shiladi /sys/kernel/debug/tracing/kprobe_events. Endi biz bu voqealarni tinglaymiz va dasturimiz ular sodir bo'lganda nimadir qila oladi.

$ 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

sample/bpf/ dagi barcha boshqa dasturlar xuddi shunday tuzilgan. Ular har doim ikkita faylni o'z ichiga oladi:

  • XXX_kern.c: eBPF dasturi.
  • XXX_user.c: asosiy dastur.

eBPF dasturi bo'lim bilan bog'liq xaritalar va funktsiyalarni aniqlaydi. Yadro ma'lum turdagi hodisani chiqarganda (masalan, tracepoint), bog'langan funksiyalar bajariladi. Kartalar yadro dasturi va foydalanuvchi kosmik dasturi o'rtasidagi aloqani ta'minlaydi.

xulosa

Ushbu maqolada BPF va eBPF umumiy ma'noda muhokama qilingan. Bugungi kunda eBPF haqida juda ko'p ma'lumot va manbalar borligini bilaman, shuning uchun men keyingi o'rganish uchun yana bir nechta manbalarni tavsiya qilaman

Men o'qishni tavsiya qilaman:

Manba: www.habr.com

a Izoh qo'shish