在Ubuntu 22.04测试ebpf-go入门例子


eBPF-Go是一个使用eBPF的Go库。它不依赖于C、libbpf或除标准库之外的任何其他Go库,这让它成为编写运行在各种体系结构上独立的、可移植工具的绝佳选择。
官网: https://ebpf-go.dev/
GitHub: https://github.com/cilium/ebpf

1、eBPF-Go依赖

  • Linux kernel version 5.7 or later, for bpf_link support
  • LLVM 11 or later 1 (clang and llvm-strip)
  • libbpf headers 2
  • Linux kernel headers 3
  • Go compiler version supported by ebpf-go’s Go module

1.1 Ubuntu安装ssh server

本文例子是在虚拟机装的Ubuntu 22.04
Ubuntu安装ssh server,方便与主机文件传输

# 安装OpenSSH服务器软件包:
sudo apt install openssh-server

# 安装完成后,SSH服务将自动启动。检查SSH服务器的状态:
sudo systemctl status ssh

# 如果SSH服务没有启动,您可以使用以下命令启动它:
sudo systemctl start ssh

#SSH服务在系统启动时自动启动:
sudo systemctl enable ssh

1.2 安装go

wget https://go.dev/dl/go1.22.6.linux-amd64.tar.gz
sudo tar -xzf go1.22.6.linux-amd64.tar.gz -C /usr/local

# 配置环境变量
vim ~/.profile
# ~/.profile文件末尾增加环境变量
export GOPROXY=https://goproxy.cn 
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
# 使配置生效
source ~/.profile

1.3 安装llvm和clang

sudo apt update
sudo apt install llvm-13 clang-13

# 安装完后,配置环境变量
vim ~/.profile
# ~/.profile文件末尾增加环境变量
export PATH=$PATH:/usr/lib/llvm-13/bin
# 使配置生效
source ~/.profile

# 使用以下命令查看版本
llvm-config --version
clang --version

1.4 安装libbpf和Linux kernel headers

# 安装libbpf-dev依赖,避免'bpf/bpf_helpers.h' file not found
sudo apt-get install libbpf-dev 
# 软链接,避免'asm/types.h' file not found错误
ln -sf /usr/include/asm-generic/ /usr/include/asm

2 编写eBPF C程序

编写eBPF C程序,Go将引用C的结构。
counter.c


//go:build ignore

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct {
    __uint(type, BPF_MAP_TYPE_ARRAY); 
    __type(key, __u32);
    __type(value, __u64);
    __uint(max_entries, 1);
} pkt_count SEC(".maps"); 

// count_packets atomically increases a packet counter on every invocation.
// SEC告知BPF虚拟机何时执行些程序
SEC("xdp") 
int count_packets() {
    __u32 key    = 0; 
    __u64 *count = bpf_map_lookup_elem(&pkt_count, &key); 
    if (count) { 
        __sync_fetch_and_add(count, 1); 
    }

    return XDP_PASS; 
}
// 指定程序许可证,因为Linux采用GPL,只能加载GPL许可的程序
char __license[] SEC("license") = "Dual MIT/GPL";

3 使用bpf2go编译eBPF C程序

创建counter.c源文件后,创建另一个名为gen.go的文件,其中包含一个//go:generate语句。当在项目目录中运行go generate时,将使用bpf2go编译eBPF C程序。
文件gen.go

package main
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go counter counter.c

在使用Go工具链之前,Go需要先声明一个Go模块。

go mod init ebpf-test 
go mod tidy

添加bpf2go的依赖:

go get github.com/cilium/ebpf/cmd/bpf2go

运行go generate:
在这里插入图片描述

4 编写Go程序

main.go

package main

import (
	"log"
	"net"
	"os"
	"os/signal"
	"time"

	"github.com/cilium/ebpf/link"
	"github.com/cilium/ebpf/rlimit"
)

func main() {
	// Remove resource limits for kernels <5.11.
	if err := rlimit.RemoveMemlock(); err != nil {
		log.Fatal("Removing memlock:", err)
	}

	// Load the compiled eBPF ELF and load it into the kernel.
	var objs counterObjects
	if err := loadCounterObjects(&objs, nil); err != nil {
		log.Fatal("Loading eBPF objects:", err)
	}
	defer objs.Close()

	ifname := "ens33" // Change this to an interface on your machine.
	iface, err := net.InterfaceByName(ifname)
	if err != nil {
		log.Fatalf("Getting interface %s: %s", ifname, err)
	}

	// Attach count_packets to the network interface.
	link, err := link.AttachXDP(link.XDPOptions{
		Program:   objs.CountPackets,
		Interface: iface.Index,
	})
	if err != nil {
		log.Fatal("Attaching XDP:", err)
	}
	defer link.Close()

	log.Printf("统计虚拟网卡%s数据包..", ifname)

	// Periodically fetch the packet counter from PktCount,
	// exit the program when interrupted.
	tick := time.Tick(time.Second)
	stop := make(chan os.Signal, 5)
	signal.Notify(stop, os.Interrupt)
	for {
		select {
		case <-tick:
			var count uint64
			err := objs.PktCount.Lookup(uint32(0), &count)
			if err != nil {
				log.Fatal("Map lookup:", err)
			}
			log.Printf("收到 %d 数据包", count)
		case <-stop:
			log.Print("收到退出信号..")
			return
		}
	}
}

最终文件目录如下
在这里插入图片描述

5 编译运行Go应用程序

go build && sudo ./ebpf-test

运行效果
在这里插入图片描述

参考自官网英文入门文档:https://ebpf-go.dev/guides/getting-started/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

penngo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值