<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          運(yùn)行第一個(gè) eBPF 程序

          共 7515字,需瀏覽 16分鐘

           ·

          2022-02-20 10:22

          b526ba94a47cb77433d515648428834c.webp

          上手 ebpf

          一直想學(xué)習(xí)一下 ebpf 這個(gè)東東,最近買了本《Linux 內(nèi)核觀測(cè)技術(shù) BPF》,準(zhǔn) 備系統(tǒng)的研究一下。

          原以為有了書之后學(xué)起來(lái)就相當(dāng)輕松了,可以我發(fā)現(xiàn)書上的第一個(gè)例子就編譯不 過(guò)。

          書上只給了部分的源碼,還需要去下載配套的 github 項(xiàng)目,這也沒(méi)啥關(guān)系,不過(guò)下 載后編譯也是編譯不過(guò)。

          編譯不過(guò)的報(bào)錯(cuò)也不過(guò)是 types.h 頭文件找不到,解決了頭文件找不到的問(wèn)題 后發(fā)現(xiàn)又有新的問(wèn)題。

          網(wǎng)上搜索了下發(fā)現(xiàn)基本上都是在介紹 ebpf xxx,沒(méi)有看到一篇講如何上手 ebpf, 只能自己搞搞嘍,在這里記錄下遇到的問(wèn)題。

          安裝必要的程序

          ebpf 程序的編譯依賴 llvm 與 clang,需要安裝這兩個(gè)程序。debian like 系 統(tǒng)可以執(zhí)行如下命令進(jìn)行安裝:

          sudo?apt-get?install?clang?llvm

          如果你要使用 python 作為 BCC 工具的前端來(lái)編寫代碼,你可能會(huì)遇到如下報(bào) 錯(cuò)信息:

          ImportError:?No?module?named?bcc

          可以執(zhí)行如下命令安裝之:

          sudo?apt-get?install?python-bpfcc

          克隆項(xiàng)目代碼

          linux-observability-with-bpf?項(xiàng)目中能夠找到《Linux內(nèi)核觀測(cè)技術(shù) BPF》一 書中的配套代碼,它的 git 項(xiàng)目地址如下:

          https://github.com/bpftools/linux-observability-with-bpf.git

          直接使用 git 進(jìn)行克隆即可,克隆完成后進(jìn)入到源碼目錄中,發(fā)現(xiàn)它有如下的 目錄結(jié)構(gòu):

          LICENSE  README.md  Vagrantfile  code  img

          從 README.md 開始

          在直接使用?code?目錄前,一定要先閱讀?README.md!一定要先閱讀?README.md

          README.md?文件中描述了使用這個(gè)項(xiàng)目需要預(yù)先執(zhí)行的步驟,具體過(guò)程如下:

          安裝必要的工具

          debian like 系統(tǒng)中可以執(zhí)行如下命令:

          $?sudo?apt?update
          $?sudo?apt?install?build-essential?git?make?libelf-dev?clang?strace?tar
          $?bpfcc-tools?linux-headers-$(uname?-r)?gcc-multilib?llvm

          獲取內(nèi)核源碼

          首先執(zhí)行?uname -r?查看內(nèi)核版本信息,然后下載相應(yīng)的內(nèi)核源碼,這里需要注 意的是內(nèi)核版本不能過(guò)低,至少要是 5.0.0 的內(nèi)核。

          進(jìn)入到內(nèi)核源碼的?tools/lib/bpf?目錄中,編譯并安裝

          配置 libbpf.so

          進(jìn)入到項(xiàng)目源碼的?code/chapter-x?中執(zhí)行?make

          注意這一步可能需要根據(jù)實(shí)際情況修改?Makefile?中的路徑配置。

          第一個(gè)問(wèn)題:升級(jí)內(nèi)核

          我使用的是 debian 10 系統(tǒng),它使用的內(nèi)核版本是 4.19,要運(yùn)行一些 ebpf 的例子 至少需要 5.0.0 的內(nèi)核版本,這樣我需要升級(jí)個(gè)內(nèi)核先。

          我已經(jīng)預(yù)先克隆了內(nèi)核的 git 倉(cāng)庫(kù),這樣我只需要檢出 v5.0 版本的內(nèi)核代碼 就行了。

          執(zhí)行如下命令來(lái)完成:

          $ git checkout -b v5.0 v5.0

          這里的兩個(gè)?v5.0,第一個(gè)?v5.0?表示的是新創(chuàng)建的分支名,第二個(gè)?v5.0?表示 的是項(xiàng)目的?tag?名稱。

          內(nèi)核?config?仍然使用我之前裁剪過(guò)的?config?文件,其下載地址如下:

          https://download.csdn.net/download/Longyu_wlz/12900957

          直接拷貝為?.config?后,然后執(zhí)行?make oldconfig,然后繼續(xù)執(zhí)行?make -j,發(fā)現(xiàn)需要重新設(shè)定其它的內(nèi)核選項(xiàng),一路 Enter 選擇使用默認(rèn)值。

          編譯完成后執(zhí)行如下命令安裝內(nèi)核及內(nèi)核模塊:

          $ sudo make modules_install
          $ sudo make install

          make install?的時(shí)候會(huì)自動(dòng)生成?initrd?并更新引導(dǎo)。

          重啟系統(tǒng),在?grub?中選擇使用?5.0?版本的內(nèi)核引導(dǎo)系統(tǒng),進(jìn)入系統(tǒng)后,執(zhí) 行?uname -a?查看內(nèi)核信息,確定使用的是?5.0?版本的內(nèi)核。相關(guān)操作記錄 如下:

          $?linux-git?$?uname?-a
          Linux?debian-10?5.0.0+?#9?SMP?Sun?Nov?15?22:05:48?CST?2020?x86_64?GNU/Linux

          第二個(gè)問(wèn)題:編譯 libbpf.so

          libbpf.so?源碼位于內(nèi)核源碼樹的?tools/lib/bpf?目錄中,直接進(jìn)入到這個(gè)目 錄中編譯即可。

          編譯過(guò)程記錄如下:

          $ make 

          Auto-detecting system features:
          ... libelf: [ on ]
          ... bpf: [ on ]

          CC libbpf.o
          CC bpf.o
          CC nlattr.o
          CC btf.o
          CC libbpf_errno.o
          CC str_error.o
          CC netlink.o
          CC bpf_prog_linfo.o
          LD libbpf-in.o
          LINK libbpf.a
          LINK libbpf.so
          LINK test_libbpf

          編譯完成后會(huì)生成?libbpf.so?文件,執(zhí)行?sudo make install?安裝此動(dòng)態(tài)庫(kù)。在我的系統(tǒng)中,它被安裝到了?/usr/local/lib64?目錄中,這個(gè)目錄并不會(huì)被動(dòng) 態(tài)庫(kù)鏈接器搜索,這樣直接運(yùn)行使用了這個(gè)動(dòng)態(tài)庫(kù)的?ebpf?程序就會(huì)有如下報(bào) 錯(cuò):

          error while loading shared libraries: libbpf.so: cannot open shared object file: No such file or directory

          解決方法如下:

          在?/etc/ld.so.conf?中添加?/usr/local/lib64?這一行,運(yùn)行?sudo ldconfig?重新生成動(dòng)態(tài)庫(kù)配置信息 成功執(zhí)行的示例信息如下:

          $ ld.so.conf.d $ sudo ldconfig -v  2>/dev/null | grep libbpf
          libbpf.so -> libbpf.so

          編譯運(yùn)行 hello world ebpf 程序

          完成上面的配置過(guò)程后就可以編譯?hello world ebpf?程序了,它位于項(xiàng)目源碼 的?code/chapter-2/hello_world?中,其源碼如下:

          #include?
          #define?SEC(NAME)?__attribute__((section(NAME),?used))

          static?int?(*bpf_trace_printk)(const?char?*fmt,?int?fmt_size,
          ???????????????????????????????...)
          ?
          =?(void?*)BPF_FUNC_trace_printk;

          SEC("tracepoint/syscalls/sys_enter_execve")
          int?bpf_prog(void?*ctx)?{
          ??char?msg[]?=?"Hello,?BPF?World!";
          ??bpf_trace_printk(msg,?sizeof(msg));
          ??return?0;
          }

          char?_license[]?SEC("license")?=?"GPL";

          這個(gè)程序,聲明監(jiān)控調(diào)用?execve?的事件,每監(jiān)控到一個(gè)事件就調(diào)用?bpf_trace_printk?來(lái)打印 Hello, BPF World! 字符串,其細(xì) 節(jié)我就不進(jìn)一步描述了,感興趣的讀者可以閱讀《Linux內(nèi)核觀測(cè)技術(shù)BPF》的第 二章。

          在編譯之前還需要修改下 Makefile 中的內(nèi)核源碼路徑,它默認(rèn)是在?/kernel-src?目錄下的,需要根據(jù)實(shí)際情況修改為真實(shí)的路徑。

          我執(zhí)行如下 sed 命令將 Makefile 中的內(nèi)核源碼路徑修改為我系統(tǒng)中的真實(shí)路 徑:

          $ sed -i 's;/kernel-src;/home/longyu/linux-git;' ./Makefile

          修改完 Makefile 后直接執(zhí)行 make 編譯即可,相關(guān)過(guò)程記錄如下:

          $ make 
          clang -O2 -target bpf -c bpf_program.c -I/home/longyu/linux-git/tools/testing/selftests/bpf -o bpf_program.o
          clang -o monitor-exec -lelf -I/home/longyu/linux-git/samples/bpf -I/home/longyu/linux-git/tools/lib -I/home/longyu/linux-git/tools/perf -I/home/longyu/linux-git/tools/include -L/usr/local/lib64 -lbpf \
          /home/longyu/linux-git/samples/bpf/bpf_load.c loader.c

          編譯完成后會(huì)生成一個(gè)?monitor-exec?程序,需要以?root?權(quán)限來(lái)運(yùn)行。使用普 通用戶執(zhí)行將會(huì)報(bào)如下錯(cuò)誤信息:

          $ ./monitor-exec 
          bpf_load_program() err=1
          The kernel didn't load the BPF program

          使用 root 用戶執(zhí)行后過(guò)一會(huì)就會(huì)打印 Hello,BPF World!,示例信息如下;

          $ sudo ./monitor-exec 
          sogou-qimpanel-31885 [004] .... 11022.245597: 0: Hello, BPF World!
          sh-31886 [005] .... 11022.247254: 0: Hello, BPF World!
          sogou-qimpanel-31887 [005] .... 11022.249711: 0: Hello, BPF World!
          sh-31889 [004] .... 11022.251231: 0: Hello, BPF World!
          sh-31891 [007] .... 11022.251429: 0: Hello, BPF World!

          這個(gè)程序使用了內(nèi)核的?tracepoint?來(lái)監(jiān)控執(zhí)行?execve?的事件,當(dāng)此事件發(fā)生 后,它會(huì)打印出?Hello,xxx?的信息,這個(gè)?execve?事件代表了一個(gè)新進(jìn)程的執(zhí) 行,我們?cè)谏厦娴氖纠锌吹降牡谝涣芯褪浅绦蛎c其?pid?號(hào)。

          這個(gè) hello world 程序的編譯過(guò)程分為兩個(gè)步驟:

          使用 clang 編譯生成 bpf 機(jī)器碼

          使用?clang?編譯?loader.c?生成加載第一步生成的機(jī)器碼的程序?loader.c?函數(shù)的源碼如下所示:

          #include?"bpf_load.h"
          #include?

          int?main(int?argc,?char?**argv)?{
          ??if?(load_bpf_file("bpf_program.o")?!=?0)?{
          ????printf("The?kernel?didn't?load?the?BPF?program\n");
          ????return?-1;
          ??}

          ??read_trace_pipe();

          ??return?0;
          }

          上述代碼其實(shí)只調(diào)用了?load_bpf_file?來(lái)加載第一步編譯生成的?ebpf?程序,?load_bpf_file?是?libbpf.so?中提供的接口。

          strace 跟蹤 hello world ebpf 程序

          使用 strace 跟蹤 hello world ebpf 程序能夠看到如下關(guān)鍵的系統(tǒng)調(diào)用:

          bpf(BPF_PROG_LOAD,?{prog_type=BPF_PROG_TYPE_TRACEPOINT,?insn_cnt=14,?insns=0xd04c80,?license="GPL",?log_level=0,?log_size=0,?log_buf=NULL,?kern_version=KERNEL_VERSION(0,?0,?0),?prog_flags=0,?prog_name="",?prog_ifindex=0,?expected_attach_type=BPF_CGROUP_INET_INGRESS},?112)?=?4

          其實(shí)?bpf?系統(tǒng)調(diào)用就是用戶態(tài)程序與內(nèi)核中的?ebpf?虛擬機(jī)交互的接口,libbpf.so?中提供的 api 實(shí)際上是對(duì) bpf 系統(tǒng)調(diào)用的封裝,可以想到?load_bpf_file?其實(shí)就是 指定?BPF_PROG_LOAD?等參數(shù)調(diào)用 bpf 系統(tǒng)調(diào)用來(lái)是實(shí)現(xiàn)的。

          吐槽吐槽《Linux內(nèi)核觀測(cè)技術(shù)BPF》

          一開始我并沒(méi)有下載該書的配套源碼,直接按照書中的描述編譯 hello world 程序,命令行信息如下:

          $?clang?-O2?-target?bpf?-c?hello.c?-o?bpf_program.o?

          結(jié)果就報(bào)了?asm/types.h cannot find?的錯(cuò)誤,整了一下發(fā)現(xiàn)它使用的是我系 統(tǒng)中?/usr/include/?目錄中的內(nèi)核頭文件,看來(lái)應(yīng)該就是個(gè)版本問(wèn)題。

          我想應(yīng)該可以通過(guò)安裝內(nèi)核頭文件來(lái)解決這個(gè)問(wèn)題。

          首先在內(nèi)核源碼樹根目錄中執(zhí)行?make help?中找到如下內(nèi)容:

            headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH
          (default: ./usr)

          可以看到它默認(rèn)是使用 ./usr 目錄,可以通過(guò)設(shè)定 INSTALL_HDR_PATH 來(lái)指定 其它安裝目錄。

          我執(zhí)行如下命令將這些頭文件安裝到指定目錄中,示例過(guò)程如下:

          $ make INSTALL_HDR_PATH="/home/longyu/ebpf/" headers_install
          INSTALL include/asm-generic (36 files)
          INSTALL include/drm (26 files)
          ......

          安裝后?ls?查看,確定?asm/types.h?存在,相關(guān)信息如下:

          $?ls?/home/longyu/ebpf/include/asm/types.h?
          /home/longyu/ebpf/include/asm/types.h

          執(zhí)行?clang -O2 -target bpf -I /home/longyu/ebpf/include -c bpf_program.c -o bpf_program.o?后成功編譯。

          我覺(jué)得這個(gè)問(wèn)題不應(yīng)該遇到,但是確實(shí)遇到了,書里面也沒(méi)有相關(guān)的描述信息, 不得不吐槽這本書的內(nèi)容,這些最為基本的東西為啥不能寫的清楚一些?也不差 那幾頁(yè)么?

          第二、三章內(nèi)容看描述還行,但是一嘗試編譯就會(huì)遇到問(wèn)題,還是有點(diǎn)垃圾歐。

          其它的 ebpf 組件

          內(nèi)核源碼樹的?tools/bpf?這個(gè)目錄中存放了了?ebpf?的匯 編,反匯編,調(diào)試程序源碼。

          在編譯的過(guò)程中我遇到了如下幾個(gè)問(wèn)題:

          找不到 bfd.h

          報(bào)錯(cuò)信息如下:

          /home/longyu/linux-git/tools/bpf/bpf_jit_disasm.c:23:10: fatal error: bfd.h: 沒(méi)有那個(gè)文件或目錄
          #include
          ^~~~~~~

          解決方案如下:

          $ apt-get install binutils-dev

          找不到 radline/readline.h

          報(bào)錯(cuò)信息如下:

          /home/longyu/linux-git/tools/bpf/bpf_dbg.c:43:10: fatal error: readline/readline.h: 沒(méi)有那個(gè)文件或目錄
          #include

          解決方案如下:

          $ sudo apt-get install libreadline-dev

          安裝了這幾個(gè)開發(fā)包后能夠成功編譯,編譯生成的文件信息如下:

          bpf_asm  bpf_dbg  bpf_jit_disasm bpftool/bpftool

          這幾個(gè)程序目前還沒(méi)有用起來(lái),后面用起來(lái)了在描述吧。

          內(nèi)核源碼樹中?tools/testing/selftests/bpf?目錄中中放了?ebpf?功能的相關(guān)測(cè)試 用例程序,在編譯時(shí)遇到了如下問(wèn)題:

          test_verifier.c:28:10: fatal error: sys/capability.h: 沒(méi)有那個(gè)文件或目錄
          #include

          可以通過(guò)執(zhí)行如下命令解決:

          $ sudo apt-get install libcap-dev

          這個(gè)目錄中的測(cè)試用例程序可以作為編寫 ebpf 程序的參考,這要比文檔資料更 有價(jià)值。

          samples/bpf?目錄中也有一些 ebpf demo 程序,也是很好的參考資料。

          內(nèi)核源碼樹中與 ebpf 相關(guān)的一手資料

          內(nèi)核源碼樹中,除了上面說(shuō)過(guò)的源碼資料外,還有幾個(gè)目錄中有一些文檔資料。

          tools/bpf/bpftool/Documentation?中有?bpftool?命令的資料?Documentation/bpf?中有?bpf?的一些描述資料

          總結(jié)

          紙上得來(lái)終覺(jué)淺,絕知此事要躬行。書上的知識(shí)一定要經(jīng)過(guò)實(shí)踐的檢驗(yàn)才能確定 它是否正確,學(xué)習(xí)從來(lái)都不只是閱讀與記憶這么簡(jiǎn)單!

          原文:

          https://blog.csdn.net/Longyu_wlz/article/details/109900096


          瀏覽 176
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青娱乐91精品 | 人人操碰人人 | 美女网站黄| 菲儿操逼视频播放 | 国产乱码一区二区三区的区别 |