<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<atom:link href="http://gentoo-zh.org/extern.php?action=feed&amp;tid=869&amp;type=rss" rel="self" type="application/rss+xml" />
		<title><![CDATA[Gentoo中文社区 / Gentoo伯克利子系统之三:BPF示例程序]]></title>
		<link>http://www.gentoo-zh.org/viewtopic.php?id=869</link>
		<description><![CDATA[Gentoo伯克利子系统之三:BPF示例程序 最近发表的帖子。]]></description>
		<lastBuildDate>Sun, 23 Jun 2024 14:08:52 +0000</lastBuildDate>
		<generator>FluxBB</generator>
		<item>
			<title><![CDATA[Gentoo伯克利子系统之三:BPF示例程序]]></title>
			<link>http://www.gentoo-zh.org/viewtopic.php?pid=989#p989</link>
			<description><![CDATA[<p>上一篇文章中BPF的例子是以BCC的整体框架为基础，本篇介绍一下基于libbpf库函数为基础，结合内核中的bpf的sample为基础编写一个BPF的程序，本篇介绍是以《linux-observability-with-bpf》这本书第二章的例子为基础，由于内核版本的不同，本篇介绍是以Linux5.16内核为基础，Linux5.16内核中的接口函数与书中的给到的程序案例有较大的差别。<br />1. 下载并编译内核<br />1) 确定和编译内核版本<br />下载需要编译的内核版本，本次使用的内核版本为：Linux-5.16.11版本。<br />2) 修改内核的配置文件，设置CONFIG_DEBUG_INFO_BTF=y,编译调试，<br />3) 编译内核<br />make olddefconfig<br />make -j 4<br />make modules_install<br />make install<br />通过命令grub2-set-default 设置启动的内核<br />4) 重启机器使用安装的新内核版本：5.16.11.frank+<br />5) 确定/sys/kernel/btf/vmlinux文件是否存在。<br />2. 编译安装libbpf库<br />1） 进入目录tools/lib/bpf&#160; 在该目录下执行make install</p><p>2） 修改/etc/ld.so.conf 文件，添加/usr/local/lib64&#160; 执行ldconfig，查看ldconfig&#160; -v 2&gt; /dev/null | grep libbpf<br />如果没有编译libbpf库，在编译bpf程序中会出现，下面的错误信息<br />上述准备工作完毕后，有以下两种方式编译bpf的例子，第一种方式，把编写的bpf程序放到sample/bpf目录下，首先编译sample/bpf，<br />1. 编译内核下samples/bpf目录下的bpf<br />1） 在编译之前安装必要的工具：<br />yum -y install binutils-devel<br />yum -y install readline-devel<br />yum -y install&#160; dwarves&#160; libdwarves1&#160; libdwarves1-devel（dwarves版本号最好大于1.17）<br />yum -y install libcap-devel&#160; <br />2） 在sample/bpf目录下&#160; make <br />在编译的过程中，确定vmlinux的位置，<br />make VMLINUX_BTF=/sys/kernel/btf/vmlinux -C samples/bpf<br />使用vmlinux产生vmlinux.h头文件，CO:RE开发需要vmlinux.h文件，（Compile once, run everywhere）<br />bpftool btf dump file /sys/kernel/btf/vmlinux format c &gt; vmlinux.h<br />2. 编译自己编写的bpf程序<br />1)编译通过完成后，修改sample/bpf的目录下的Makefile文件，添加下面的三行代码：<br />hello-objs := hello_user.o<br />always-y += hello_kern.o<br />tprogs-y += hello<br />hello_user 为我们用户空间的程序名，hello_kern为我们的内核空间程序名。<br />2）Kernel hello_kern.c程序：</p><div class="codebox"><pre><code>#include &lt;linux/ptrace.h&gt;
#include &lt;linux/version.h&gt;
#include &lt;uapi/linux/bpf.h&gt;
#include &lt;bpf/bpf_helpers.h&gt;
#include &quot;trace_common.h&quot;
SEC(&quot;tracepoint/syscalls/sys_enter_execve&quot;)
 int bpf_prog(struct pt_regs *ctx) {
    char msg[] = &quot;Hello, BPF World!&quot;;
    bpf_trace_printk(msg, sizeof(msg));
    return 0;
  }
char _license[] SEC(&quot;license&quot;) = &quot;GPL&quot;;
   u32 _version SEC(&quot;version&quot;) = LINUX_VERSION_CODE;</code></pre></div><p>kernel程序比较简单，意思是在执行到内核中的execve函数时，打印 Hello BPF World！</p><p>3） 应用程序 hello_user.c</p><div class="codebox"><pre class="vscroll"><code>#include &lt;bpf/bpf.h&gt;
#include &lt;bpf/libbpf.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
 
#define DEBUGFS &quot;/sys/kernel/debug/tracing/&quot;
int load_bpf_file(char *filename);
 
int load_bpf_file(char *path)
{
    struct bpf_object *obj;
    struct bpf_program *prog;
    struct bpf_link *link = NULL;
    int progs_fd;
    printf(&quot;%s\n&quot;,path);
 
    obj = bpf_object__open_file(path, NULL);
    if (libbpf_get_error(obj))
    {
        fprintf(stderr, &quot;ERROR: opening BPF object file failed\n&quot;);
        return 0;
    }
 
   if (bpf_object__load(obj))
    {
        fprintf(stderr, &quot;ERROR: loading BPF object file failed\n&quot;);
        goto cleanup;
    }
 
    prog = bpf_object__find_program_by_name(obj, &quot;bpf_prog&quot;);
    if (!prog) {
        printf(&quot;finding a prog in obj file failed\n&quot;);
        goto cleanup;
    }
 
    link = bpf_program__attach(prog);
    if (libbpf_get_error(link)) {
        fprintf(stderr, &quot;ERROR: bpf_program__attach failed\n&quot;);
        link = NULL;
        goto cleanup;
    }
 
 read_trace_pipe();
 
cleanup:
    bpf_link__destroy(link);
    bpf_object__close(obj);
    return 0;
}
 
void read_trace_pipe(void)
{
       int trace_fd;
 
       trace_fd = open(DEBUGFS &quot;trace_pipe&quot;, O_RDONLY, 0);
       if (trace_fd &lt; 0)
               return;
 
       while (1) {
               static char buf[4096];
               ssize_t sz;
 
               sz = read(trace_fd, buf, sizeof(buf) - 1);
               if (sz &gt; 0) {
                       buf[sz] = 0;
                       puts(buf);
               }
       }
}
 
int main(int argc, char **argv) {
   if (load_bpf_file(&quot;hello_kern.o&quot;) != 0) {
       printf(&quot;The kernel didn&#039;t load the BPF program\n&quot;);
       return -1;
   }
}</code></pre></div><p>执行上面的程序输出如下结果：<br /><span class="postimg"><img src="https://www.batsom.net/usr/uploads/2024/05/195980284.png" alt="FluxBB bbcode 测试" /></span></p><p>第二种方法:&#160; 如果不把编写的bpf示例程序放到，samples/bpf目录下，可以单独写一个makefile文件，内容如下：</p><div class="codebox"><pre class="vscroll"><code>CLANG = clang
 
EXECABLE = monitor-exec
 
BPFCODE = bpf_program
 
BPFTOOLS = /data/kernel/v1/linux-stable/samples/bpf
 
CCINCLUDE += -I/data/kernel/v1/linux-stable/tools/testing/selftests/bpf
 
LOADINCLUDE += -I/data/kernel/v1/linux-stable/samples/bpf
LOADINCLUDE += -I/data/kernel/v1/linux-stable//tools/lib
LOADINCLUDE += -I/data/kernel/v1/linux-stable/tools/perf
LOADINCLUDE += -I/data/kernel/v1/linux-stable/tools/include
LIBRARY_PATH = -L/usr/local/lib64
BPFSO = -lbpf
 
CFLAGS += $(shell grep -q &quot;define HAVE_ATTR_TEST 1&quot; /data/kernel/v1/linux-stable/tools/perf/perf-sys.h \
                 &amp;&amp; echo &quot;-DHAVE_ATTR_TEST=0&quot;)
 
.PHONY: clean $(CLANG) bpfload build
 
clean:
       rm -f *.o *.so $(EXECABLE)
 
build: ${BPFCODE.c}
       $(CLANG) -O2 -target bpf -c $(BPFCODE:=.c) $(CCINCLUDE) -o ${BPFCODE:=.o}
 
bpfload: build
       clang $(CFLAGS) -o $(EXECABLE) -lelf $(LOADINCLUDE) $(LIBRARY_PATH) $(BPFSO) \
       loader.c
 
$(EXECABLE): bpfload
 
.DEFAULT_GOAL := $(EXECABLE)</code></pre></div><p>1）本程序虽然以《linux-observability-with-bpf》第2章的程序为基础，但是随着内核的更新，采用5.16版本内核时load_bpf_file函数已经被移除了，需要重新调用函数实现load_bpf_file函数。<br />2）随着bpf和内核版本的不断变化，参考本文时需要重点关注不同的内核版本、bpftool、gcc等各类工具的版本。<br />3） 内核源代码中的samples/bpf目录下有大量的bpf的示例程序可以参考。<br />4）使用bcc框架版本的bpf程序和使用libbpf库bpf程序在编写方式上会有所不同，注意不同的接口函数。<br />5）centos安装libbpf -devel</p><br /><div class="codebox"><pre><code>sed -i -e &quot;s|mirrorlist=|#mirrorlist=|g&quot; /etc/yum.repos.d/CentOS-*

sed -i -e &quot;s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g&quot; /etc/yum.repos.d/CentOS-*

dnf --enablerepo=PowerTools install libbpf-devel</code></pre></div><br /><p>参考文献：https://blog.aquasec.com/vmlinux.h-ebpf-programs</p>]]></description>
			<author><![CDATA[dummy@example.com (batsom)]]></author>
			<pubDate>Sun, 23 Jun 2024 14:08:52 +0000</pubDate>
			<guid>http://www.gentoo-zh.org/viewtopic.php?pid=989#p989</guid>
		</item>
	</channel>
</rss>
