BPF နှင့် eBPF အကျဉ်းမိတ်ဆက်

မင်္ဂလာပါ Habr။ စာအုပ်ထုတ်ဝေရန် ပြင်ဆင်နေပါကြောင်း အသိပေးအပ်ပါသည်။"BPF ဖြင့် Linux Observability".

BPF နှင့် eBPF အကျဉ်းမိတ်ဆက်
BPF virtual machine သည် ဆက်လက်တိုးတက်နေပြီး လက်တွေ့တွင် တက်ကြွစွာအသုံးပြုနေသောကြောင့် ၎င်း၏ပင်မစွမ်းရည်များနှင့် လက်ရှိအခြေအနေအကြောင်းဖော်ပြသည့် ဆောင်းပါးကို သင့်အတွက် ဘာသာပြန်ထားပါသည်။

မကြာသေးမီနှစ်များအတွင်း၊ စွမ်းဆောင်ရည်မြင့်မားသော packet လုပ်ဆောင်ခြင်း လိုအပ်သည့်ကိစ္စများတွင် Linux kernel ၏ကန့်သတ်ချက်များကို လျော်ကြေးပေးရန် ပရိုဂရမ်ရေးကိရိယာများနှင့် နည်းစနစ်များသည် လူကြိုက်များလာခဲ့သည်။ ဤအမျိုးအစား၏ရေပန်းအစားဆုံးနည်းပညာများထဲမှတစ်ခုဟုခေါ်သည်။ kernel ကိုရှောင်ကွင်း (kernel bypass) နှင့် kernel network layer ကို ကျော်ဖြတ်ကာ user space မှ packet processing အားလုံးကို လုပ်ဆောင်ရန် ခွင့်ပြုသည်။ kernel ကိုကျော်ဖြတ်ခြင်းသည်လည်း network card ကိုထိန်းချုပ်ခြင်းလည်းပါဝင်သည်။ အသုံးပြုသူနေရာ. တစ်နည်းဆိုရသော် ကွန်ရက်ကတ်တစ်ခုဖြင့် အလုပ်လုပ်သောအခါ ကျွန်ုပ်တို့သည် ယာဉ်မောင်းကို အားကိုးသည်။ အသုံးပြုသူနေရာ.

ကွန်ရက်ကတ်၏ ထိန်းချုပ်မှု အပြည့်အဝကို အသုံးပြုသူ-အာကာသပရိုဂရမ်သို့ လွှဲပြောင်းခြင်းဖြင့်၊ ကျွန်ုပ်တို့သည် 10Gb/s သို့မဟုတ် ထို့ထက်မြင့်မားသော အမြန်နှုန်းဖြင့် လုပ်ဆောင်သောအခါတွင် အလွန်အရေးကြီးသည့် kernel overhead (context switching, network layer processing, interrupts, etc.) ကို လျှော့ချပေးပါသည်။ Kernel bypass နှင့် အခြားအင်္ဂါရပ်များ ပေါင်းစပ်မှု (batch processing) နှင့် ဂရုတစိုက် စွမ်းဆောင်ရည် ချိန်ညှိခြင်း (NUMA စာရင်းကိုင်, CPU အထီးကျန်စသည်တို့) သည် သုံးစွဲသူနေရာရှိ စွမ်းဆောင်ရည်မြင့် ကွန်ရက်လုပ်ဆောင်ခြင်း၏ အခြေခံများနှင့် ကိုက်ညီပါသည်။ packet processing တွင် ဤချဉ်းကပ်မှုအသစ်၏ စံနမူနာပြဖြစ်နိုင်သည်။ DPDK Intel မှ (Data Plane Development KitCisco ၏ VPP (Vector Packet Processing)၊ Netmap နှင့် အပါအဝင် အခြားသော နာမည်ကြီး ကိရိယာများနှင့် နည်းပညာများ ရှိသော်လည်း၊ လျှပ်တစ်ပြက်.

အသုံးပြုသူနေရာရှိ ကွန်ရက် အပြန်အလှန်ဆက်သွယ်မှုများကို စုစည်းရာတွင် အားနည်းချက်များစွာရှိသည်။

  • OS kernel သည် ဟာ့ဒ်ဝဲအရင်းအမြစ်များအတွက် abstraction layer တစ်ခုဖြစ်သည်။ အသုံးပြုသူအာကာသပရိုဂရမ်များသည် ၎င်းတို့၏အရင်းအမြစ်များကို တိုက်ရိုက်စီမံခန့်ခွဲရမည်ဖြစ်သောကြောင့်၊ ၎င်းတို့၏ကိုယ်ပိုင် hardware ကိုလည်း စီမံခန့်ခွဲရမည်ဖြစ်သည်။ ၎င်းသည် သင့်ကိုယ်ပိုင်ယာဉ်မောင်းများကို ပရိုဂရမ်ထားရှိခြင်းကို မကြာခဏဆိုလိုသည်။
  • ကျွန်ုပ်တို့သည် kernel space ကို လုံးလုံးလျားလျား စွန့်လွှတ်နေသောကြောင့်၊ kernel မှ ပံ့ပိုးပေးသော ကွန်ရက်ချိတ်ဆက်မှု လုပ်ဆောင်နိုင်စွမ်းအားလုံးကိုလည်း စွန့်လွှတ်လိုက်ပါသည်။ အသုံးပြုသူနေရာလွတ်ပရိုဂရမ်များသည် kernel သို့မဟုတ် operating system မှပေးဆောင်ထားပြီးဖြစ်သည့်အင်္ဂါရပ်များကို ပြန်လည်ပြင်ဆင်ရပါမည်။
  • ပရိုဂရမ်များသည် ၎င်းတို့၏ အပြန်အလှန်ဆက်သွယ်မှုကို ပြင်းထန်စွာ ကန့်သတ်ထားပြီး လည်ပတ်မှုစနစ်၏ အခြားအစိတ်အပိုင်းများနှင့် ပေါင်းစည်းခြင်းမှ တားဆီးပေးသည့် sandbox မုဒ်တွင် လုပ်ဆောင်သည်။

အနှစ်သာရအားဖြင့်၊ user space တွင် networking လုပ်သောအခါ၊ packet processing ကို kernel မှ user space သို့ ရွှေ့ခြင်းဖြင့် စွမ်းဆောင်ရည် အကျိုးကျေးဇူးများ ရရှိပါသည်။ XDP သည် ဆန့်ကျင်ဘက်အဖြစ် အတိအကျလုပ်ဆောင်သည်- ၎င်းသည် အသုံးပြုသူနေရာ (filters၊ ဖြေရှင်းသူများ၊ လမ်းကြောင်းပေးခြင်းစသည်) မှ ကွန်ရက်ချိတ်ဆက်မှုပရိုဂရမ်များကို kernel space သို့ ရွှေ့သည်။ XDP သည် ပက်ကက်တစ်ခုသည် ကွန်ရက်အင်တာဖေ့စ်ကိုထိမှန်သည်နှင့် ၎င်းသည် kernel ကွန်ရက်ခွဲစနစ်သို့မစတင်မီတွင် ကွန်ရက်လုပ်ဆောင်ချက်ကို လုပ်ဆောင်နိုင်စေပါသည်။ ရလဒ်အနေဖြင့် packet processing speed သိသိသာသာတိုးလာသည်။ သို့သော်၊ kernel သည် သုံးစွဲသူအား ၎င်းတို့၏ ပရိုဂရမ်များကို kernel space တွင် မည်သို့လုပ်ဆောင်ခွင့်ပြုသနည်း။ ဒီမေးခွန်းကို မဖြေခင် BPF ဆိုတာ ဘာလဲဆိုတာ လေ့လာကြည့်ရအောင်။

BPF နှင့် eBPF

နာမည်ရှုပ်ထွေးနေသော်လည်း BPF (Berkeley Packet Filtering) သည် အမှန်တကယ်တော့ virtual machine model တစ်ခုဖြစ်သည်။ ဤ virtual machine သည် packet filtering ကို ကိုင်တွယ်ရန် မူလက ဒီဇိုင်းဆွဲထားသောကြောင့် နာမည်ဖြစ်သည်။

BPF ကိုအသုံးပြုသည့်အကျော်ကြားဆုံးကိရိယာများထဲမှတစ်ခုဖြစ်သည်။ tcpdump. packets များကို ဖမ်းယူရာတွင် အသုံးပြုသည်။ tcpdump အသုံးပြုသူသည် packets ကိုစစ်ထုတ်ရန် expression တစ်ခုကို သတ်မှတ်နိုင်သည်။ ဤအသုံးအနှုန်းနှင့်ကိုက်ညီသော ပက်ကေ့ခ်ျများကိုသာ ဖမ်းယူမည်ဖြစ်သည်။ ဥပမာအားဖြင့် “အသုံးအနှုန်း၊tcp dst port 80” သည် port 80 တွင်ရောက်ရှိလာသော TCP packet အားလုံးကိုရည်ညွှန်းသည်။ compiler သည် ၎င်းကို 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

အထက်ဖော်ပြပါ ပရိုဂရမ်သည် အခြေခံအားဖြင့် လုပ်ဆောင်သည်-

  • ညွှန်ကြားချက် (000)- 12-bit စကားလုံးအဖြစ် offset 16 တွင် packet ကို accumulator ထဲသို့ ထည့်ပါ။ Offset 12 သည် packet ၏ ethertype နှင့် ကိုက်ညီသည်။
  • ညွှန်ကြားချက် (001)- စုဆောင်းကိရိယာရှိတန်ဖိုးကို 0x86dd နှင့် IPv6 အတွက် ethertype တန်ဖိုးနှင့် နှိုင်းယှဉ်သည်။ ရလဒ်မှန်ပါက ပရိုဂရမ်ကောင်တာသည် ညွှန်ကြားချက် (002) သို့သွား၍ မဟုတ်ပါက (006) သို့သွားပါ။
  • ညွှန်ကြားချက် (006): တန်ဖိုးကို 0x800 (IPv4 အတွက် အီသာအမျိုးအစားတန်ဖိုး) နှင့် နှိုင်းယှဉ်သည်။ အဖြေမှန်ပါက ပရိုဂရမ်သည် (007) သို့ မဟုတ်ပါက (015) သို့သွားပါမည်။

packet filtering program ရလဒ်တစ်ခုပြန်မလာမချင်း စသည်တို့ဖြစ်သည်။ ၎င်းသည် အများအားဖြင့် Boolean ဖြစ်သည်။ သုညမဟုတ်သောတန်ဖိုး (ညွှန်ကြားချက် (014)) ကို ပြန်ဆိုခြင်းသည် ပက်ကတ်ကို လက်ခံခဲ့ကြောင်းနှင့် သုညတန်ဖိုး (ညွှန်ကြားချက် (015)) ပြန်လာခြင်းကို ဆိုလိုသည်မှာ ပက်ကေ့ခ်ျကို လက်မခံကြောင်း ဆိုလိုသည်။

BPF virtual machine နှင့် ၎င်း၏ bytecode ကို Steve McCann နှင့် Van Jacobson တို့က ၁၉၉၂ ခုနှစ်နှောင်းပိုင်းတွင် ၎င်းတို့၏ စာတမ်းကို ထုတ်ဝေသောအခါ အဆိုပြုခဲ့သည်။ BSD Packet Filter- User-Level Packet Capture အတွက် ဗိသုကာအသစ်ဤနည်းပညာကို 1993 ခုနှစ် ဆောင်းရာသီတွင် Usenix ကွန်ဖရင့်တွင် ပထမဆုံးတင်ပြခဲ့သည်။

BPF သည် virtual machine တစ်ခုဖြစ်သောကြောင့်၊ ၎င်းသည် ပရိုဂရမ်များလည်ပတ်သည့် ပတ်ဝန်းကျင်ကို သတ်မှတ်ပေးသည်။ bytecode အပြင်၊ ၎င်းသည် batch memory model (load ညွှန်ကြားချက်များကို batch အတွက် သွယ်ဝိုက်သောနည်းဖြင့် အသုံးပြုသည်)၊ မှတ်ပုံတင်များ (A နှင့် X; accumulator နှင့် index registers)၊ scratch memory storage နှင့် implicit program counter တို့ကိုလည်း သတ်မှတ်ပေးပါသည်။ စိတ်ဝင်စားစရာကောင်းတာက BPF bytecode ကို Motorola 6502 ISA ရဲ့နောက်မှာ ပုံစံထုတ်ထားပါတယ်။ Steve McCann က သူ့အထဲမှာ မှတ်မိသလိုပါပဲ။ စုံညီအစီရင်ခံစာ Sharkfest '11 တွင်၊ သူသည် Apple II တွင် အထက်တန်းကျောင်းတက်စဉ်ကာလက ပရိုဂရမ်ရေးဆွဲခြင်းမှ build 6502 နှင့် ရင်းနှီးခဲ့ပြီး ဤအသိပညာသည် BPF bytecode ကို ဒီဇိုင်းထုတ်သည့် သူ၏အလုပ်အပေါ် လွှမ်းမိုးခဲ့သည်။

BPF ပံ့ပိုးမှုကို Jay Schullist ၏ကြိုးစားအားထုတ်မှုဖြင့် ဗားရှင်း v2.5 နှင့်အထက်တွင် Linux kernel တွင်အကောင်အထည်ဖော်ထားသည်။ Eric Dumaset သည် JIT မုဒ်တွင်အလုပ်လုပ်ရန် BPF စကားပြန်အား ပြန်လည်ဒီဇိုင်းထုတ်သောအခါ BPF ကုဒ်သည် 2011 ခုနှစ်အထိ မပြောင်းလဲသေးပါ (အရင်းအမြစ်- packet filters အတွက် JIT) ၎င်းနောက်၊ kernel သည် BPF bytecode ကို ဘာသာပြန်ခြင်းအစား BPF ပရိုဂရမ်များကို ပစ်မှတ်ဗိသုကာအဖြစ်သို့ တိုက်ရိုက်ပြောင်းလဲနိုင်သည်- x86၊ ARM၊ MIPS စသည်ဖြင့်။

နောက်ပိုင်းတွင်၊ 2014 ခုနှစ်တွင် Alexey Starovoitov သည် BPF အတွက် JIT ယန္တရားအသစ်ကိုအဆိုပြုခဲ့သည်။ တကယ်တော့၊ ဒီ JIT အသစ်ဟာ BPF အခြေခံ ဗိသုကာအသစ်ဖြစ်လာပြီး eBPF လို့ ခေါ်ပါတယ်။ VM နှစ်ခုလုံးသည် အချိန်အတန်ကြာ အတူရှိနေခဲ့သည်ဟု ကျွန်တော်ထင်သည်၊ သို့သော် လက်ရှိတွင် packet filtering ကို eBPF ပေါ်အခြေခံ၍ အကောင်အထည်ဖော်ပါသည်။ အမှန်မှာ၊ ခေတ်မီစာရွက်စာတမ်းများ၏နမူနာများစွာတွင် BPF ကို eBPF ဟုနားလည်ကြပြီး classical BPF ကို ယနေ့ cBPF ဟုခေါ်သည်။

eBPF သည် ပုံစံအမျိုးမျိုးဖြင့် classic BPF virtual machine ကို တိုးချဲ့သည်-

  • ခေတ်မီ 64-bit ဗိသုကာများကို အခြေခံထားသည်။ eBPF သည် 64-bit မှတ်ပုံတင်မှုများကို အသုံးပြုပြီး 2 (accumulator နှင့် X) မှ 10 အထိ ရရှိနိုင်သော မှတ်ပုံတင်အရေအတွက်ကို တိုးပေးပါသည်။ eBPF သည် ထပ်ဆောင်း opcode များ (BPF_MOV၊ BPF_JNE၊ BPF_CALL...) ကို ပေးပါသည်။
  • ကွန်ရက်အလွှာခွဲစနစ်မှ ခွဲထုတ်ထားသည်။ BPF သည် batch data model နှင့် ချိတ်ဆက်ထားသည်။ ၎င်းကို packet စစ်ထုတ်ခြင်းအတွက် အသုံးပြုထားသောကြောင့် ၎င်း၏ကုဒ်သည် ကွန်ရက်ဆက်သွယ်မှုများကို ပံ့ပိုးပေးသည့် စနစ်ခွဲတွင် တည်ရှိပါသည်။ သို့သော်လည်း eBPF virtual machine သည် data model နှင့် မချိတ်ဆက်တော့ဘဲ မည်သည့်ရည်ရွယ်ချက်အတွက်မဆို အသုံးပြုနိုင်ပါသည်။ ထို့ကြောင့်၊ ယခု eBPF ပရိုဂရမ်အား tracepoint သို့မဟုတ် kprobe သို့ ချိတ်ဆက်နိုင်ပြီဖြစ်သည်။ ၎င်းသည် eBPF ကိရိယာတန်ဆာပလာ၊ စွမ်းဆောင်ရည်ခွဲခြမ်းစိတ်ဖြာမှုနှင့် အခြားသော kernel ခွဲစနစ်များ၏ ဆက်စပ်မှုတွင် အခြားအသုံးပြုမှုကိစ္စရပ်များစွာအတွက် လမ်းဖွင့်ပေးသည်။ ယခု eBPF ကုဒ်သည် ၎င်း၏ကိုယ်ပိုင်လမ်းကြောင်းတွင် ရှိနေသည်- kernel/bpf။
  • Maps ဟုခေါ်သော ကမ္ဘာလုံးဆိုင်ရာဒေတာစတိုးဆိုင်များ။ Maps များသည် အသုံးပြုသူနေရာနှင့် kernel နေရာတို့အကြား ဒေတာဖလှယ်မှုကို ဖွင့်ပေးသည့် သော့တန်ဖိုးစတိုးဆိုင်များဖြစ်သည်။ eBPF သည် မြေပုံအမျိုးအစားများစွာကို ထောက်ပံ့ပေးသည်။
  • ဆင့်ပွားလုပ်ဆောင်ချက်များ။ အထူးသဖြင့်၊ ပက်ကေ့ဂျ်တစ်ခုကို ပြန်ရေးရန်၊ checksum တွက်ချက်ရန် သို့မဟုတ် ပက်ကေ့ဂျ်တစ်ခုပွားရန်။ ဤလုပ်ဆောင်ချက်များသည် kernel အတွင်းတွင်အလုပ်လုပ်ပြီး user-space ပရိုဂရမ်များမဟုတ်ပါ။ eBPF ပရိုဂရမ်များမှ စနစ်ခေါ်ဆိုမှုများလည်း ပြုလုပ်နိုင်သည်။
  • ခေါ်ဆိုမှုများကို အဆုံးသတ်ပါ။ eBPF ရှိ ပရိုဂရမ်အရွယ်အစားကို 4096 bytes ကန့်သတ်ထားသည်။ အမြီးခေါ်ဆိုမှုအင်္ဂါရပ်သည် eBPF ပရိုဂရမ်အား ထိန်းချုပ်မှုကို eBPF ပရိုဂရမ်အသစ်တစ်ခုသို့ လွှဲပြောင်းရန် ခွင့်ပြုထားပြီး ဤကန့်သတ်ချက်ကို ကျော်လွှားနိုင်သည် (ဤနည်းဖြင့် ပရိုဂရမ် 32 ခုအထိ ချိတ်ဆက်နိုင်သည်)။

eBPF: ဥပမာ

Linux kernel အရင်းအမြစ်များတွင် eBPF အတွက် ဥပမာများစွာရှိသည်။ ၎င်းတို့ကို နမူနာ/bpf/ တွင် ရရှိနိုင်ပါသည်။ ဤဥပမာများကို စုစည်းရန်၊ ရိုးရှင်းစွာ ထည့်သွင်းပါ-

$ sudo make samples/bpf/

eBPF အတွက် နမူနာအသစ်ကို ကျွန်ုပ်ကိုယ်တိုင်ရေးမည်မဟုတ်သော်လည်း samples/bpf/ တွင် ရရှိနိုင်သော နမူနာများထဲမှ တစ်ခုကို အသုံးပြုပါမည်။ ကုဒ်၏ အစိတ်အပိုင်းအချို့ကို ကြည့်ရှုပြီး ၎င်းအလုပ်လုပ်ပုံကို ရှင်းပြပါမည်။ ဥပမာအနေနဲ့၊ ငါ program ကိုရွေးချယ်ခဲ့တယ်။ tracex4.

ယေဘုယျအားဖြင့်၊ နမူနာ/bpf/ ရှိ နမူနာတစ်ခုစီတွင် ဖိုင်နှစ်ခု ပါဝင်သည်။ ဒါဆိုရင်:

  • tracex4_kern.c၊ တွင် eBPF bytecode အဖြစ် kernel တွင် လုပ်ဆောင်ရမည့် အရင်းအမြစ်ကုဒ် ပါရှိသည်။
  • tracex4_user.cအသုံးပြုသူနေရာလွတ်မှ ပရိုဂရမ်တစ်ခုပါရှိသည်။

ဒီနေရာမှာတော့ compile လုပ်ဖို့လိုတယ်။ tracex4_kern.c eBPF bytecode သို့။ လောလောဆယ်မှာ gcc eBPF အတွက် backend မရှိပါ။ ကံအားလျော်စွာ၊ clang eBPF bytecode ထုတ်ပေးနိုင်သည်။ Makefile အသုံးပြုမှု clang စုစည်းမှုအတွက် tracex4_kern.c အရာဝတ္ထုဖိုင်သို့။

eBPF ၏ စိတ်ဝင်စားဖွယ်အကောင်းဆုံးအင်္ဂါရပ်များထဲမှ တစ်ခုသည် မြေပုံများဖြစ်ကြောင်း အထက်တွင် ကျွန်တော်ပြောခဲ့သည်။ tracex4_kern သည် မြေပုံတစ်ခုကို သတ်မှတ်သည်-

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 မှပေးသောကတ်အမျိုးအစားများစွာထဲမှတစ်ခုဖြစ်သည်။ ဤကိစ္စတွင်၊ ၎င်းသည် hash တစ်ခုမျှသာဖြစ်သည်။ ကြော်ငြာတစ်ခုကိုလည်း သင် သတိပြုမိပေမည်။ SEC("maps"). SEC သည် ဒွိဖိုင်တစ်ခု၏ ကဏ္ဍအသစ်တစ်ခုကို ဖန်တီးရန် အသုံးပြုသည့် မက်ခရိုတစ်ခုဖြစ်သည်။ တကယ်တော့ ဥပမာထဲမှာ tracex4_kern နောက်ထပ်အပိုင်းနှစ်ပိုင်းကို သတ်မှတ်ထားသည်-

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

ဤလုပ်ဆောင်ချက်နှစ်ခုသည် သင့်အား မြေပုံမှ entry ကိုဖျက်ရန်ခွင့်ပြုသည် (kprobe/kmem_cache_free) နှင့် မြေပုံသို့ ဝင်ခွင့်အသစ်တစ်ခု ထည့်ပါ (kretprobe/kmem_cache_alloc_node) စာလုံးကြီးများဖြင့် ရေးသားထားသော လုပ်ဆောင်ချက်အမည်များအားလုံးသည် သတ်မှတ်ထားသော မက်ခရိုများနှင့် သက်ဆိုင်ပါသည်။ bpf_helpers.h.

အရာဝတ္ထုဖိုင်၏ အပိုင်းများကို ငါစွန့်ပစ်ပါက၊ ဤကဏ္ဍအသစ်များကို သတ်မှတ်ပြီးဖြစ်ကြောင်း ကျွန်ုပ်တွေ့မြင်ရမည်-

$ 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

လည်းရှိတယ်။ tracex4_user.c၊ အဓိကအစီအစဉ်။ အခြေခံအားဖြင့်၊ ဤအစီအစဉ်သည် အဖြစ်အပျက်များကို နားထောင်သည်။ kmem_cache_alloc_node. ထိုသို့သောဖြစ်ရပ်တစ်ခုဖြစ်ပေါ်လာသောအခါ၊ သက်ဆိုင်ရာ eBPF ကုဒ်ကို လုပ်ဆောင်သည်။ ကုဒ်သည် အရာဝတ္တု၏ IP ရည်ညွှန်းချက်ကို မြေပုံတစ်ခုအဖြစ် သိမ်းဆည်းကာ၊ ထို့နောက် အရာဝတ္ထုကို ပင်မပရိုဂရမ်မှတစ်ဆင့် ကွင်းဆက်သွားမည်ဖြစ်သည်။ ဥပမာ-

$ 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

အသုံးပြုသူအာကာသပရိုဂရမ်နှင့် eBPF ပရိုဂရမ်သည် မည်သို့ဆက်စပ်သနည်း။ စတင်ခြင်းတွင် tracex4_user.c အရာဝတ္ထုဖိုင်တစ်ခုကို တင်သည်။ tracex4_kern.o 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;
}

လုပ်ခြင်းအားဖြင့် load_bpf_file eBPF ဖိုင်တွင် သတ်မှတ်ထားသော စုံစမ်းစစ်ဆေးမှုများကို ထည့်သွင်းထားသည်။ /sys/kernel/debug/tracing/kprobe_events. ယခု ကျွန်ုပ်တို့သည် ဤဖြစ်ရပ်များကို နားထောင်ပြီး ကျွန်ုပ်တို့၏အစီအစဉ်သည် ၎င်းတို့ဖြစ်ပျက်လာသောအခါတွင် တစ်ခုခုလုပ်ဆောင်နိုင်မည်ဖြစ်သည်။

$ 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

နမူနာ/bpf/ ရှိ အခြားသော ပရိုဂရမ်အားလုံးကို အလားတူ တည်ဆောက်ထားသည်။ ၎င်းတို့တွင် ဖိုင်နှစ်ခု အမြဲပါဝင်သည်-

  • XXX_kern.c: eBPF ပရိုဂရမ်။
  • XXX_user.c: အဓိက အစီအစဉ်။

eBPF ပရိုဂရမ်သည် အပိုင်းတစ်ခုနှင့် ဆက်စပ်နေသော မြေပုံများနှင့် လုပ်ဆောင်ချက်များကို ခွဲခြားသတ်မှတ်သည်။ kernel သည် အချို့သောအမျိုးအစားတစ်ခု၏ ဖြစ်ရပ်တစ်ခုကို ထုတ်ပြသောအခါ (ဥပမာ၊ tracepoint) ထုပ်လုပ်ထားသောလုပ်ဆောင်ချက်များကိုလုပ်ဆောင်သည်။ ကတ်များသည် kernel ပရိုဂရမ်နှင့် အသုံးပြုသူအာကာသပရိုဂရမ်အကြား ဆက်သွယ်မှုကို ပေးသည်။

ကောက်ချက်

ဤဆောင်းပါးတွင် BPF နှင့် eBPF တို့ကို ယေဘုယျအသုံးအနှုန်းများဖြင့် ဆွေးနွေးထားသည်။ ယနေ့ eBPF နှင့် ပတ်သက်သော အချက်အလက်များ နှင့် အရင်းအမြစ်များစွာ ရှိသည်ကို ကျွန်ုပ်သိပါသည်၊ ထို့ကြောင့် နောက်ထပ် လေ့လာရန်အတွက် အရင်းအမြစ်အနည်းငယ်ကို ကျွန်ုပ် အကြံပြုပါမည်။

ဖတ်ရန် အကြံပြုလိုပါသည်။

source: www.habr.com

မှတ်ချက် Add