跳转到主要内容

基于bcc的Python eBPF(扩展伯克利包过滤器)包装器

项目描述

PyEBPF

一个基于bcc的Python eBPF(扩展伯克利包过滤器)包装器。

注意:使用此库需要安装BCC,请参阅此指南

此小型库有两个主要目的

  1. 它允许您在不编写本地代码的情况下附加BPF内核探测
  2. 它允许您在Python中编写BPF例程回调 [1]

如果您需要该功能,您仍然可以像使用bcc的BPF库一样编写、编译和使用本地例程。

[1] 请参阅下面的 '此库是如何工作的?'

什么是eBPF

扩展伯克利包过滤器是BPF过滤器(传统上用于包过滤)的超集,它允许您使用专用eBPF指令集编写小的内核例程。

要使用eBPF,需要编译一个例程,调用bpf(2)系统调用,并附加一个内核探测。

bpf(2)将确保取您的编译后的例程,静态分析并JIT它,然后将其复制到内核空间以供以后使用。

您将一个探测附加到内核跟踪事件(例如系统调用调用),一旦您的探测附加,您的eBPF例程将被适当地调用。

通过eBPF映射(在FD之上操作,允许在这些两端之间通信)在eBPF例程之间或eBPF例程与用户空间之间共享数据是可能的。

什么是IOVisor/BCC

BCC(BPF编译器集合)是一个工具包,可以帮助您以用户友好的方式生成和使用BPF例程。

它通过C宏抽象了一些eBPF功能(例如BPF共享数据结构),让您专注于例程的逻辑和收集适当的指标。

代码生成由LLVM管理,因此您需要安装适当的版本。

更多关于项目的信息,请访问此处

这个库是如何工作的?

给定一个需要附加内核探针的事件,这个库将(按顺序)

  1. 尝试隐式猜测事件传递给您的例程的任何额外参数。这是通过尽力阅读/sys/kernel/debug/tracing/events/syscalls/sys_enter_/format文件来完成的。该文件包含事件跟踪可能包含的参数的文本描述。

  2. 然后它将生成一个精心设计的本地数据结构,其中将包含相关上下文,包括

    • 当前时间(以纳秒为单位)(通过bpf_ktime_get_ns)
    • PID和TID(通过bpf_get_current_pid_tgid)
    • GID和UID(通过bpf_get_current_uid_gid)
    • 进程名称(通过bpf_get_current_comm)
    • 任何隐式猜测的事件跟踪参数,例如对于bind系统调用,数据结构将还包含:套接字FD、套接字地址和地址长度
  3. 它将创建一个eBPF共享数据结构(使用BPF_PERF_OUTPUT宏),用作与用户模式例程的通信网关

  4. 将启动一个专用的轮询守护进程线程,并且对于共享结构上的每个输出,您的Python回调将被调用,并通过ctypes类传递表示本地数据结构

因此,对于任何内核探针附加的事件,将调用一个内部BPF例程,然后它将所有相关成员通过构造的数据结构复制回用户模式,通过BPF结构。然后,一个内部Python线程将轮询该结构,并调用已注册的Python回调。

有效地使用此包装器

首先,通过以下命令安装库

$> pip install pyebpf

然后,导入EBPFWrapper对象,实例化它,并将函数附加到事件上。

# trace_fields.py bcc example, using pyebpf


b = EBPFWrapper()
print 'PID MESSAGE'

def hello(data, **kwargs):
    print '{pid} Hello, World!'.format(pid=data.process_id)

b.attach_kprobe(event=b.get_syscall_fnname('clone'), fn=hello)

while True:
    try:
        time.sleep(1)
    except KeyboardInterrupt:
        print 'Bye !'
        break

b = EBPFWrapper()
print 'COMM PID SOCKETFD'

def on_bind(data, **kwargs):
    print '{comm} {pid} {fd}'.format(comm=data.process_name, pid=data.process_id, fd=data.fd, addr=data.umyaddr)

b.attach_kprobe(event=b.get_syscall_fnname('bind'), fn=on_bind)

# Will print 'python <pid> <fd>'
s = socket()
s.bind(('0.0.0.0', 31337))

while True:
    try:
        time.sleep(1)
    except KeyboardInterrupt:
        print 'Bye !'
        break

# Supplying a native route

from pyebpf.ebpf_wrapper import EBPFWrapper

prog = '''
int hello(struct pt_regs* ctx) {
    bpf_trace_printk("Hello from eBPF routine!\\n");
    return 0;
}
'''
b = EBPFWrapper(text=prog)
b.attach_kprobe(event='sys_open', fn_name='hello')

while True:
    try:
        print b.trace_fields()
    except KeyboardInterrupt:
        print 'Bye !'
        break

EBPF相关资源

以下是我在编写此库时找到的一些有用的eBPF相关资源

  1. http://www.brendangregg.com/ebpf.html
  2. https://bolinfest.github.io/opensnoop-native
  3. https://github.com/iovisor/bcc
  4. https://lwn.net/Articles/740157/

项目详情


下载文件

下载适用于您平台的应用程序。如果您不确定要选择哪个,请了解更多关于安装包的信息。

源分布

pyebpf-1.0.4.tar.gz (12.7 kB 查看哈希值)

上传时间 源代码

构建分布

pyebpf-1.0.4-py2-none-any.whl (10.9 kB 查看哈希值)

上传时间 Python 2

由以下支持

AWSAWS云计算和安全赞助商DatadogDatadog监控FastlyFastlyCDNGoogleGoogle下载分析MicrosoftMicrosoftPSF赞助商PingdomPingdom监控SentrySentry错误日志StatusPageStatusPage状态页面