<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      eBPF筆記(四)—— eBPF的簡單刨析

      eBPF “Hello World” for a Network Interface

      ????該程序在網(wǎng)絡(luò)數(shù)據(jù)包到達(dá)時會寫入一行跟蹤

      #include <linux/bpf.h>
      #include <bpf/bpf_helpers.h>
      
      int counter = 0;
      
      SEC("xdp")
      int hello(struct xdp_md *ctx) {
          bpf_printk("Hello World %d", counter);
          counter++; 
          return XDP_PASS;
      }
      
      char LICENSE[] SEC("license") = "Dual BSD/GPL";
      
      • ????宏SEC()為ebpf程序定義了一個xdp類型
      • ????返回值XPD_PASS是向內(nèi)核指示它應(yīng)正常處理此數(shù)據(jù)包的標(biāo)志。
      • ????BCC 的版本稱為 bpf_trace_printk(),libbpf 的版本是 bpf_printk(),但兩者都是內(nèi)核函數(shù) bpf_trace_printk() 的封裝。

      Compiling an eBPF Object File

      ????eBPF 源代碼需要編譯成 eBPF 虛擬機可以理解的機器指令:eBPF 字節(jié)碼。如果指定 -target bpf,則 LLVM 項目中的 Clang 編譯器將執(zhí)行此操作。以下是將執(zhí)行編譯的 Makefile 的摘錄:

      hello.bpf.o: %.o: %.c
         clang \
             -target bpf \
             -I/usr/include/$(shell uname -m)-linux-gnu \
             -g \
             -O2 -c $< -o $@
      

      Inspecting an eBPF Object File

      make后可以檢查一下生成的hello.bpf.o

         $ file hello.bpf.o
         hello.bpf.o: ELF 64-bit LSB relocatable, eBPF, version 1 (SYSV), with debug_info,
       not stripped
      

      This shows it’s an ELF (Executable and Linkable Format) file, containing eBPF code,
      for a 64-bit platform with LSB (least significant bit) architecture. It includes debug
      information if you used the -g flag at the compilation step.

      Loading the Program into the Kernel

      ????在此示例中,我們將使用名為 bpftool 的實用程序。您還可以load programs programmatical.

      ????使用 bpftool 將程序加載到內(nèi)核中:

      $ bpftool prog load hello.bpf.o /sys/fs/bpf/hello

      ????這會從我們編譯的目標(biāo)文件中加載 eBPF 程序,并將其“固定”到位置 /sys/fs/bpf/hello.4 對此命令沒有輸出響應(yīng)表示成功。可以使用ls /sys/fs/bpf來查看加載的bpf程序。

      Inspecting the Loaded Program

      ????運行以下命令列出已被加載的ebpf程序列表:

      $ bpftool prog list
      .....
      160: xdp  name hello  tag d35b94b4c0c10efb  gpl
              loaded_at 2024-05-19T19:22:03+0800  uid 0
              xlated 96B  jited 64B  memlock 4096B  map_ids 16,17
              btf_id 109
      

      ????可以運行以下命令使用json格式輸出:

      $ bpftool prog show id 160 --pretty
      {
          "id": 160,
          "type": "xdp",
          "name": "hello",
          "tag": "d35b94b4c0c10efb",
          "gpl_compatible": true,
          "loaded_at": 1716117723,
          "uid": 0,
          "orphaned": false,
          "bytes_xlated": 96,
          "jited": true,
          "bytes_jited": 64,
          "bytes_memlock": 4096,
          "map_ids": [16,17
          ],
          "btf_id": 109
      }
      

      The BPF Program Tag

      ????tag是程序指令的 SHA(安全哈希算法)總和,可用作程序的另一個標(biāo)識符。每次加載或卸載程序時,ID 可能會有所不同,但標(biāo)記將保持不變。bpftool 實用程序接受按 ID、名稱、tag或pinned path對 BPF 程序的引用,因此在此示例中,以下所有內(nèi)容都將提供相同的輸出

      ? bpftool prog show id 160
      ? bpftool prog show name hello
      ? bpftool prog show tag d35b94b4c0c10efb
      ? bpftool prog show pinned /sys/fs/bpf/hello

      ????可以有多個具有相同名稱的程序,甚至可以具有相同標(biāo)記的多個程序?qū)嵗?ID 和固定路徑將始終是唯一的。

      The Translated Bytecode

      ????bytes_xlated 字段告訴我們有多少字節(jié)的“翻譯”eBPF 代碼。這是 eBPF 通過驗證程序后的字節(jié)碼

       $ bpftool prog dump xlated name hello 
      int hello(struct xdp_md * ctx):
       ; bpf_printk("Hello World %d", counter);
         0: (18) r6 = map[id:165][0]+0
         2: (61) r3 = *(u32 *)(r6 +0)
         3: (18) r1 = map[id:166][0]+0
         5: (b7) r2 = 15
         6: (85) call bpf_trace_printk#-78032
       ; counter++; 
         7: (61) r1 = *(u32 *)(r6 +0)
         8: (07) r1 += 1
         9: (63) *(u32 *)(r6 +0) = r1
       ; return XDP_PASS;
        10: (b7) r0 = 2
        11: (95) exit
      

      ????這看起來與您之前在 llvm-objdump 的輸出中看到的反匯編代碼非常相似。偏移地址相同,指令看起來相似,例如,我們可以看到偏移量 5 處的指令為 r2=15。

      The JIT-Compiled Machine Code

      ????翻譯后的字節(jié)碼是相當(dāng)?shù)图壍模€不是機器代碼。eBPF 使用 JIT 編譯器將 eBPF 字節(jié)碼轉(zhuǎn)換為在目標(biāo) CPU 上本機運行的機器代碼。bytes_jited 字段顯示,在此對話之后,程序的長度為 64 字節(jié)

      為了獲得更高的性能,eBPF 程序通常采用 JIT 編譯。另一種方法是在運行時解釋 eBPF 字節(jié)碼。eBPF 指令集和寄存器被設(shè)計為與本機指令相當(dāng)接近,使這種交互變得簡單明了,因此速度相對較快,但編譯程序會更快,而且大多數(shù)架構(gòu)現(xiàn)在都支持 JIT.5

      ????bpftool 實用程序可以用匯編語言生成此 JIT 代碼的轉(zhuǎn)儲

      # bpftool prog dump jited name hello 
      int hello(struct xdp_md * ctx):
      bpf_prog_d35b94b4c0c10efb_hello:
      ; bpf_printk("Hello World %d", counter);
         0:   nopl    (%rax,%rax)
         5:   nop
         7:   pushq   %rbp
         8:   movq    %rsp, %rbp
         b:   pushq   %rbx
         c:   movabsq $-81287619428352, %rbx
        16:   movl    (%rbx), %edx
        19:   movabsq $-110636984554736, %rdi
        23:   movl    $15, %esi
        28:   callq   0xffffffffc9c90eb0
      ; counter++; 
        2d:   movl    (%rbx), %edi
        30:   addq    $1, %rdi
        34:   movl    %edi, (%rbx)
      ; return XDP_PASS;
        37:   movl    $2, %eax
        3c:   popq    %rbx
        3d:   leave
        3e:   retq
        3f:   int3
      

      Attaching to an Event

      ????程序類型必須與它所附加的事件類型相匹配。在本例中,它是一個 XDP 程序,可以使用 bpftool 將示例 eBPF 程序附加到網(wǎng)絡(luò)接口上的 XDP 事件,如下所示:
      # bpftool net attach xdp id 160 dev ens33 這里我的網(wǎng)卡名稱是ens33,因機器而異。

      使用ip link 查看網(wǎng)絡(luò)接口:

      root@wp-virtual-machine:~# ip link
      1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 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
      2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdpgeneric qdisc fq_codel state UP mode DEFAULT group default qlen 1000
          link/ether 00:0c:29:fc:0c:b3 brd ff:ff:ff:ff:ff:ff
          prog/xdp id 160 tag d35b94b4c0c10efb jited 
          altname enp2s1
      

      你可以使用bpftool查看network-attached eBPF programs:

      root@wp-virtual-machine:~# bpftool net list 
      xdp:
      ens33(2) generic id 160
      
      tc:
      
      flow_dissector:
      
      netfilter:
      

      ????此輸出還提供了有關(guān)網(wǎng)絡(luò)堆棧中其他一些潛在事件的一些線索,您可以將 eBPF 程序附加到這些事件:tc 和 flow_dissector

      ????此時,hello eBPF 程序應(yīng)該在每次收到網(wǎng)絡(luò)數(shù)據(jù)包時生成跟蹤輸出。您可以通過運行 cat /sys/kernel/ debug/tracing/trace_pipe 來檢查這一點。這應(yīng)該顯示許多類似于以下內(nèi)容的輸出:

      
      wp@wp-virtual-machine:~$ sudo cat /sys/kernel/debug/tracing/trace_pipe
      ...
                <idle>-0       [007] ..s21 21514.466911: bpf_trace_printk: Hello World 1741
                <idle>-0       [007] ..s21 21514.513357: bpf_trace_printk: Hello World 1742
                <idle>-0       [007] ..s21 21514.574762: bpf_trace_printk: Hello World 1743
                <idle>-0       [007] ..s21 21514.620769: bpf_trace_printk: Hello World 1744
                <idle>-0       [007] ..s21 21514.666429: bpf_trace_printk: Hello World 1745
                <idle>-0       [007] ..s21 21514.712155: bpf_trace_printk: Hello World 1746
                <idle>-0       [007] ..s21 21514.759256: bpf_trace_printk: Hello World 1747
                <idle>-0       [007] ..s21 21514.767923: bpf_trace_printk: Hello World 1748
      ...
      

      ????如果您難以記住跟蹤管道的位置,可以使用命令 bpftool prog tracelog 獲得相同的輸出。

      root@wp-virtual-machine:~# bpftool prog tracelog

      這次沒有與這些事件相關(guān)的命令或進程ID;相反,你在每行跟蹤的開始看到的是 -0。在第2章中,每個系統(tǒng)調(diào)用事件都是因為一個在用戶空間執(zhí)行命令的進程調(diào)用了系統(tǒng)調(diào)用API。那個進程ID和命令是eBPF程序執(zhí)行時的上下文的一部分。但在這里的例子中,XDP事件是由于網(wǎng)絡(luò)包的到來而發(fā)生的。這個包沒有關(guān)聯(lián)的用戶空間進程——在hello eBPF程序被觸發(fā)的那一刻,系統(tǒng)除了將包接收到內(nèi)存中外,還沒有對其進行任何處理,而且它不知道這個包是什么或者它要去哪里。

      Global Variables

      正如你在前一章中了解到的,eBPF map是一種數(shù)據(jù)結(jié)構(gòu),可以從eBPF程序或用戶空間訪問。由于同一個map可以在同一程序的不同運行中重復(fù)訪問,它可以用于保存一次執(zhí)行到下一次執(zhí)行的狀態(tài)。多個程序也可以訪問同一個map。由于這些特性,map語義可以重新用于作為全局變量。

      在 2019 年添加對全局變量的支持之前,eBPF 程序語法必須顯式編寫map才能執(zhí)行相同的任務(wù)。

      root@wp-virtual-machine:~# bpftool map list
      2: prog_array  name hid_jmp_table  flags 0x0
              key 4B  value 4B  max_entries 1024  memlock 8512B
              owner_prog_type tracing  owner jited
      3: hash  flags 0x0
              key 9B  value 1B  max_entries 500  memlock 59360B
      16: array  name hello.bss  flags 0x400
              key 4B  value 4B  max_entries 1  memlock 8192B
              btf_id 109
      17: array  name hello.rodata  flags 0x80
              key 4B  value 15B  max_entries 1  memlock 336B
              btf_id 109  frozen
      32: array  name libbpf_global  flags 0x0
              key 4B  value 32B  max_entries 1  memlock 352B
      33: array  name pid_iter.rodata  flags 0x480
              key 4B  value 4B  max_entries 1  memlock 8192B
              btf_id 149  frozen
              pids bpftool(22268)
      34: array  name libbpf_det_bind  flags 0x0
              key 4B  value 32B  max_entries 1  memlock 352B
      

      ????我們選擇hello.bss

      root@wp-virtual-machine:~# bpftool map dump name hello.bss
      [{
              "value": {
                  ".bss": [{
                          "counter": 4238
                      }
                  ]
              }
          }
      ]
      

      ????可以看到counter已經(jīng)增長到了4238.

      正如你將在第5章中學(xué)到的,bpftool 只有在BTF信息可用的情況下才能漂亮地打印出map的字段名稱(這里是變量名稱counter)。只有在編譯時使用-g標(biāo)志,才會包含這些信息。如果在編譯步驟中省略了該標(biāo)志,你將看到類似以下內(nèi)容的輸出:
      $ bpftool map dump name hello.bss
      key: 00 00 00 00 value: 8E 10 00 00
      Found 1 element

      ????map還用于保存靜態(tài)數(shù)據(jù):

      root@wp-virtual-machine:~# bpftool map dump name hello.rodata
      [{
              "value": {
                  ".rodata": [{
                          "hello.____fmt": "Hello World %d"
                      }
                  ]
              }
          }
      ]
      

      ????現(xiàn)在我們已經(jīng)檢查完這個程序及其maps,是時候清理它了。我們將從將其從觸發(fā)事件中分離出來開始。

      Detaching the Program

      可以按照如下方法detach eBPF程序

      root@wp-virtual-machine:~# bpftool net detach xdp dev ens33(注意你之前綁定的網(wǎng)卡名稱,這里是我機器上的網(wǎng)卡名稱ens33)

      此時執(zhí)行ip link 和bpftool net list 你將會發(fā)現(xiàn)已經(jīng)成功分離。

      但是,該程序仍加載到內(nèi)核中:

      root@wp-virtual-machine:~# bpftool prog show name hello 
      160: xdp  name hello  tag d35b94b4c0c10efb  gpl
              loaded_at 2024-05-19T19:22:03+0800  uid 0
              xlated 96B  jited 64B  memlock 4096B  map_ids 16,17
              btf_id 109
      

      Unloading the Program

      目前(至少在撰寫本文時)沒有與bpftool prog load相對應(yīng)的命令,但是你可以通過刪除固定的偽文件來從內(nèi)核中移除程序:

       $ rm /sys/fs/bpf/hello
       $ bpftool prog show name hello
      

      BPF to BPF Calls

      在前一章中,你看到了尾調(diào)用的示例,并且我提到現(xiàn)在也有能力在eBPF程序中調(diào)用函數(shù)。讓我們看一個簡單的例子,與尾調(diào)用示例類似,可以將其附加到sys_enter跟蹤點,但這次它將跟蹤系統(tǒng)調(diào)用的操作碼。你會在第3章的hello-func.bpf.c中找到這段代碼。

      ????完整代碼:

      點擊查看完整代碼代碼
      #include <linux/bpf.h>
      #include <bpf/bpf_helpers.h>
      
      static __attribute((noinline)) int get_opcode(struct bpf_raw_tracepoint_args *ctx) {
          return ctx->args[1];
      }
      
      SEC("raw_tp/")
      int hello(struct bpf_raw_tracepoint_args *ctx) {
          int opcode = get_opcode(ctx);
          bpf_printk("Syscall: %d", opcode);
          return 0;
      }
      
      char LICENSE[] SEC("license") = "Dual BSD/GPL";
      
      

      ????以下函數(shù)從跟蹤點參數(shù)中提取系統(tǒng)調(diào)用操作碼:

      static __attribute((noinline)) int get_opcode(struct bpf_raw_tracepoint_args *ctx) {
          return ctx->args[1];
      }
      

      如果有選擇的話,編譯器可能會將這個非常簡單的函數(shù)內(nèi)聯(lián),而我只會從一個地方調(diào)用它。由于這樣做會破壞這個例子的目的,我添加了__attribute((noinline))來強制編譯器不進行內(nèi)聯(lián)。在正常情況下,你可能應(yīng)該省略這一屬性,讓編譯器根據(jù)需要進行優(yōu)化。

      ????調(diào)用此函數(shù)的 eBPF 函數(shù)如下所示:

      SEC("raw_tp/")
      int hello(struct bpf_raw_tracepoint_args *ctx) {
          int opcode = get_opcode(ctx);
          bpf_printk("Syscall: %d", opcode);
          return 0;
      }
      

      make后執(zhí)行如下命令
      bpftool prog load hello-func.bpf.o /sys/fs/bpf/hello
      查看程序:

      root@wp-virtual-machine:~# bpftool prog list name hello 
      216: raw_tracepoint  name hello  tag 3d9eb0c23d4ab186  gpl
              loaded_at 2024-05-19T20:37:14+0800  uid 0
              xlated 80B  jited 62B  memlock 4096B  map_ids 45
              btf_id 179
      
      $ bpftool prog dump xlated name hello 
      int hello(struct bpf_raw_tracepoint_args * ctx):
       ; int opcode = get_opcode(ctx);                            
         0: (85) call pc+7#bpf_prog_cbacc90865b1b9a5_get_opcode
       ; bpf_printk("Syscall: %d", opcode);
         1: (18) r1 = map[id:193][0]+0
         3: (b7) r2 = 12
         4: (bf) r3 = r0
         5: (85) call bpf_trace_printk#-73584
       ; return 0;
         6: (b7) r0 = 0
         7: (95) exit
       int get_opcode(struct bpf_raw_tracepoint_args * ctx):      
      ; return ctx->args[1];
         8: (79) r0 = *(u64 *)(r1 +8)
       ; return ctx->args[1];
         9: (95) exit
      

      在這里,你可以看到hello() eBPF程序調(diào)用了get_opcode()。偏移量為0的eBPF指令是0x85,根據(jù)指令集文檔,對應(yīng)著“函數(shù)調(diào)用”。執(zhí)行不會繼續(xù)執(zhí)行下一條指令,而是會跳過七條指令(pc+7),也就是偏移量為8的指令。

      函數(shù)調(diào)用指令需要將當(dāng)前狀態(tài)放在 eBPF 虛擬機的堆棧上,以便當(dāng)被調(diào)用的函數(shù)退出時,可以在調(diào)用函數(shù)中繼續(xù)執(zhí)行。由于堆棧大小限制為 512 字節(jié),因此 BPF 到 BPF 調(diào)用不能非常深入地嵌套。

      posted @ 2025-07-26 15:30  Darkexpeller  閱讀(55)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 天堂网av成人在线观看| 清徐县| 精品久久亚洲中文无码| 亚洲日韩久热中文字幕| 日韩av影院在线观看| 一区二区不卡99精品日韩| 久久综合久中文字幕青草| 四平市| 欧美一区二区三区欧美日韩亚洲 | 成人资源网亚洲精品在线| 狠狠色狠狠综合久久| AV无码免费不卡在线观看 | 亚洲人妻一区二区精品| 在线观看成人av天堂不卡| 日韩人妻无码精品久久| 无码国内精品久久人妻蜜桃| 四虎永久精品免费视频| 农村老熟妇乱子伦视频| 精品婷婷色一区二区三区| 久久精品人妻少妇一区二| 无码熟妇人妻av在线电影| 国产精品国产三级国av| 少妇人妻偷人免费观看| 亚洲色婷婷久久精品av蜜桃久久 | 亚洲国产日韩一区三区| 国产av综合色高清自拍| 男同精品视频免费观看网站| 肉色丝袜足j视频国产| 中日韩黄色基地一二三区| 性欧美VIDEOFREE高清大喷水| 东丰县| 69精品丰满人妻无码视频a片| 国产精品美女AV免费观看| 玩弄放荡人妻少妇系列| 国产日韩乱码精品一区二区 | 凸凹人妻人人澡人人添| 亚洲av伦理一区二区| 乱码中字在线观看一二区| 中文字幕国产精品自拍| 69精品无人区国产一区| 99精品人妻少妇一区|