首页 > 其他分享 >eBPF 用户态和内核态基于ringbuf交互

eBPF 用户态和内核态基于ringbuf交互

时间:2024-07-11 09:09:09浏览次数:14  
标签:err bpf cmd ebpf eBPF 内核 ringbuf go

相比于perf_event_array,ringbuf优势在于
1. 读取数据是有序的,即提交顺序和消费顺序保持一致。
2. 避免数据复制,即提交数据到map和传递到用户态都不需要拷贝。

内核态 ringbuf/ringbuf.c

#include "../headers/vmlinux.h"
#include "../headers/bpf_endian.h"
#include "../headers/bpf_helpers.h"

#define TC_ACT_OK 0

struct {
	__uint(type, BPF_MAP_TYPE_RINGBUF);
	__uint(max_entries, 100);
    __uint(pinning, LIBBPF_PIN_BY_NAME);
} events SEC(".maps");

#ifndef memcpy
#define memcpy(dest, src, n)   __builtin_memcpy((dest), (src), (n))
#endif

char __license[] SEC("license") = "Dual MIT/GPL";

SEC("tc")
int test_ringbuf(struct __sk_buff *skb) {
    char str[10] = "abc";
    char *res = bpf_ringbuf_reserve(&events, 10, BPF_ANY);
    if (res) {
        memcpy(res, str, 10);
        bpf_ringbuf_submit(res, BPF_ANY);
    }
    return TC_ACT_OK;
}

用户态cmd/main.go

package main

import (
	"os"
	"os/exec"
	"os/signal"
	"syscall"

	"github.com/cilium/ebpf"
	"github.com/cilium/ebpf/ringbuf"
	"github.com/cilium/ebpf/rlimit"
	"k8s.io/klog/v2"
)

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go bpf ../ringbuf/ringbuf.c

func SetupSignalHandler() (stopCh <-chan struct{}) {
	stop := make(chan struct{})
	c := make(chan os.Signal, 2)
	signal.Notify(c, []os.Signal{os.Interrupt, syscall.SIGTERM}...)
	go func() {
		<-c
		close(c)
		close(stop)
	}()

	return stop
}

func DelTcEbpf() {
	cmds := []string{
		"tc qdisc del dev ens33 clsact",
	}
	for _, cmd := range cmds {
		exec.Command("bash", "-c", cmd).CombinedOutput()
	}
}

func main() {
	stopCh := SetupSignalHandler()

	DelTcEbpf()
	defer DelTcEbpf()

	// eBPF先删再加
	cmds := []string{
		"tc qdisc add dev ens33 clsact",
		"tc filter add dev ens33 egress bpf da obj ringbuf/ringbuf.o sec tc",
	}
	for i, cmd := range cmds {
		if _, err := exec.Command("bash", "-c", cmd).CombinedOutput(); err != nil && i > 0 {
			klog.Errorf("exec %s failed, err is %v", cmd, err)
			return
		}
	}

	// Allow the current process to lock memory for eBPF resources.
	if err := rlimit.RemoveMemlock(); err != nil {
		klog.Errorf("rlimit remove memory lock failed, err is %v", err)
		return
	}

	eventsMap, err := ebpf.LoadPinnedMap("/sys/fs/bpf/tc/globals/events", nil)
	if err != nil {
		klog.Errorf("load pinned map events failed, err is %v", err)
		return
	}
	defer eventsMap.Close()

	reader, err := ringbuf.NewReader(eventsMap)
	if err != nil {
		klog.Errorf("new ringbuf reader failed, err is %v", err)
		return
	}
	defer reader.Close()

	go func() {
		for {
			if record, err := reader.Read(); err != nil {
				klog.Errorf("reader read failed, err is %v", err)
				return
			} else {
				klog.Infof("reader read %s", record.RawSample)
			}
		}
	}()

	<-stopCh
}

bash run-ebpf-test.sh

rm -f ringbuf/ringbuf.o
rm -f cmd/bpf_bpfeb.go cmd/bpf_bpfeb.o cmd/bpf_bpfel.go cmd/bpf_bpfel.o cmd/ebpf-test
clang -c ringbuf/ringbuf.c -o ringbuf/ringbuf.o -target bpf -O2 -g
go generate ./cmd
go build -o ./cmd/ebpf-test ./cmd/.
./cmd/ebpf-test

标签:err,bpf,cmd,ebpf,eBPF,内核,ringbuf,go
From: https://www.cnblogs.com/WJQ2017/p/18295349

相关文章

  • Liunx内核的作用
    liunx内核的作用主要包含了五大作用管理进程:内核负责创建和销毁进程,并处理它们与外部世界的联系(输入和输出),不同进程间通讯(通过信号,管道,或者进程间通讯原语)对整个系统功能来说是基本的,也由内核处理。另外,调度器,控制进程如何共享CPU,是进程管理的一部分。更通常地,内核的......
  • CentOS 7升级内核的三种方式(yum/rpm/源码)
    原文作者: NesteaLin 文章链接: https://nestealin.com/8bab8c2c/背景在CentOS使用过程中,难免需要升级内核,但有时候因为源码编译依赖问题,不一定所有程序都支持最新内核版本,所以以下将介绍两种升级内核方式。注意事项关于内核种类:kernel-mlkernel-ml中的ml......
  • 09 为内核支持函数调用
    在[[08内核第一条指令|上一节]]我们使用了编写entry.asm函数中编写了内核的第一条指令,但是我们使用的汇编.这里注意我们仍然是嵌入了这段asm代码到我们的rust代码之中,然后进行编译.但是即使连使用fnmain都不被允许,因此我们如果希望使用rust来编写内核代码,因此我们最好为内核......
  • 08 内核第一条指令
    了解QEMU启动指令qemu-system-riscv64\-machinevirt\-nographic\-bios../bootloader/rustsbi-qemu.bin\-deviceloader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000-machine virt 表示将模拟的64位RISC-V计算机......
  • 内核参数优化
    linux内核参数优化(网络模块)在Linux下调整内核参数,可以直接编辑配置文件/etc/sysctl.conf,然后执行sysctl-p命令生效文件内容如下:net.ipv4.ip_forward=1net.ipv4.conf.default.rp_filter=1net.ipv4.conf.default.accept_source_route=0kernel.sysrq=0kernel.core_......
  • 基于eBPF的procstat软件追踪等待锁和持有锁的时间
    在并发编程中,锁的使用是保证线程安全的重要手段。然而,过度使用锁或者锁竞争可能导致性能瓶颈。为了分析程序中锁的使用情况,我们可以借助procstat软件来追踪程序加锁时间和等待锁的时间。procstat是一个基于eBPF(extendedBerkeleyPacketFilter)的软件,能够对系统的各种行为进......
  • 应用程序会不会导致linux内核崩溃?
    应用程序有可能导致Linux内核崩溃,但这种情况并不是绝对的,它取决于多种因素。应用程序或Linux内核本身都可能存在bug。当应用程序的某部分逻辑与内核的某部分逻辑发生冲突时,有可能导致内核崩溃。例如,应用程序可能尝试访问非法的内存地址,或者触发内核中的某个未修复的错误。这......
  • Franka Linux 设置实时内核 PREEMPT_RT
    为了使用控制您的机器人libfranka,工作站PC上的控制器程序必须在内核下以实时优先级PREEMPT_RT运行。本节介绍了修补内核以支持 PREEMPT_RT并创建安装包的过程。内核不支持NVIDIA二进制驱动程序PREEMPT_RT。 sudoapt-getinstallbuild-essentialbccurlca-certific......
  • RockyLinux9.4升级Linux内核6.X️
    RockyLinux9.4升级Linux内核6.X......
  • 【0295】Posgres内核 dynahash table 之 hash_search 实现原理(2)
    相关文章:【0294】Postgres内核dynahash之hash_search实现原理(1)0.前言在【0294】Postgres内核dynahash之hash_search实现原理(1)一文中,从Postgres内核源码角度详细讲解了dynamichashtable中hashsearch的实现原理。具体内容:如何确定segment位置如何确定bu......