addd example and support for load and attach

This commit is contained in:
2025-09-21 18:02:49 +05:30
parent 9fb3ab3238
commit ec003a2c0a
6 changed files with 84 additions and 18 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ _generate/
build/ build/
*venv/ *venv/
.idea/ .idea/
sudo-python.sh

View File

@ -1,10 +1,13 @@
# Py-libbpf # Py-libbpf
<p align="center">
<a href="https://www.python.org/downloads/release/python-3080/"><img src="https://img.shields.io/badge/python-3.8-blue.svg"></a>
<a href="https://pypi.org/project/pylibbpf"><img src="https://badge.fury.io/py/pylibbpf.svg"></a>
</p>
This library provides Python bindings for libbpf on Linux to make loading of eBPF object files easier. This is meant to This library provides Python bindings for libbpf on Linux to make loading of eBPF object files easier. This is meant to
be used along with `pythonbpf`, the eBPF Python DSL compiler. This library makes it possible to attach these programs to be used along with `pythonbpf`, the eBPF Python DSL compiler. This library makes it possible to attach these programs to
events in the kernel right from inside Python. events in the kernel right from inside Python.
# Warning # IN DEVELOPMENT. DO NOT USE.
IN DEVELOPMENT. DO NOT USE.
## Prerequisites ## Prerequisites
@ -19,6 +22,7 @@ Just clone this repository and pip install. Note the `--recursive` option which
needed for the pybind11 submodule: needed for the pybind11 submodule:
```bash ```bash
sudo apt install libelf-dev
git clone --recursive https://github.com/varun-r-mallya/pylibbpf.git git clone --recursive https://github.com/varun-r-mallya/pylibbpf.git
pip install . pip install .
``` ```
@ -26,5 +30,11 @@ pip install .
With the `setup.py` file included in this example, the `pip install` command will With the `setup.py` file included in this example, the `pip install` command will
invoke CMake and build the pybind11 module as specified in `CMakeLists.txt`. invoke CMake and build the pybind11 module as specified in `CMakeLists.txt`.
## Development
Do this before running to make sure Python can manipulate bpf programs without sudo
```bash
sudo setcap cap_bpf,cap_sys_admin+ep /usr/bin/python3.12
```
## Building the documentation ## Building the documentation
The documentation here is still boilerplate. The documentation here is still boilerplate.

41
examples/execve.py Normal file
View File

@ -0,0 +1,41 @@
from pythonbpf import bpf, map, section, bpfglobal, BPF
from ctypes import c_void_p, c_int64, c_int32, c_uint64
from pythonbpf.helpers import ktime
from pythonbpf.maps import HashMap
import time
@bpf
@map
def last() -> HashMap:
return HashMap(key=c_uint64, value=c_uint64, max_entries=1)
@bpf
@section("tracepoint/syscalls/sys_enter_execve")
def hello(ctx: c_void_p) -> c_int32:
print("entered")
print("multi constant support")
return c_int32(0)
@bpf
@section("tracepoint/syscalls/sys_exit_execve")
def hello_again(ctx: c_void_p) -> c_int64:
print("exited")
key = 0
tsp = last().lookup(key)
print(tsp)
ts = ktime()
return c_int64(0)
@bpf
@bpfglobal
def LICENSE() -> str:
return "GPL"
b = BPF()
b.load_and_attach()
while True:
print("running")
time.sleep(1)

View File

@ -33,6 +33,7 @@ PYBIND11_MODULE(pylibbpf, m) {
.def("load", &BpfProgram::load) .def("load", &BpfProgram::load)
.def("attach", &BpfProgram::attach) .def("attach", &BpfProgram::attach)
// .def("detach", &BpfProgram::detach) // .def("detach", &BpfProgram::detach)
.def("load_and_attach", &BpfProgram::load_and_attach)
.def("is_loaded", &BpfProgram::is_loaded) .def("is_loaded", &BpfProgram::is_loaded)
.def("is_attached", &BpfProgram::is_attached); .def("is_attached", &BpfProgram::is_attached);

View File

@ -1,10 +1,11 @@
#include "bpf_program.h" #include "bpf_program.h"
#include "bpf_exception.h" #include "bpf_exception.h"
#include <filesystem> #include <filesystem>
#include <utility>
BpfProgram::BpfProgram(const std::string& object_path, const std::string& program_name) BpfProgram::BpfProgram(std::string object_path, std::string program_name)
: obj_(nullptr), prog_(nullptr), link_(nullptr), : obj_(nullptr), prog_(nullptr), link_(nullptr),
object_path_(object_path), program_name_(program_name) { object_path_(std::move(object_path)), program_name_(std::move(program_name)) {
} }
BpfProgram::~BpfProgram() { BpfProgram::~BpfProgram() {
@ -28,9 +29,12 @@ bool BpfProgram::load() {
throw BpfException("Program '" + program_name_ + "' not found in object"); throw BpfException("Program '" + program_name_ + "' not found in object");
} }
} else { } else {
// Use the first program if no name specified while ((prog_ = bpf_object__next_program(obj_, prog_)) != nullptr) {
prog_ = bpf_object__next_program(obj_, nullptr); programs.emplace_back(prog_, nullptr);
if (!prog_) { }
// throw if no programs found
if (programs.empty()) {
throw BpfException("No programs found in object file"); throw BpfException("No programs found in object file");
} }
} }
@ -44,15 +48,23 @@ bool BpfProgram::load() {
} }
bool BpfProgram::attach() { bool BpfProgram::attach() {
if (!prog_) { for (auto [prog, link] : programs)
throw BpfException("Program not loaded"); {
} if (!prog) {
throw BpfException("Program not loaded");
}
link_ = bpf_program__attach(prog_); link = bpf_program__attach(prog);
if (libbpf_get_error(link_)) { if (libbpf_get_error(link)) {
link_ = nullptr; link = nullptr;
throw BpfException("Failed to attach BPF program"); throw BpfException("Failed to attach BPF program");
}
} }
return true; return true;
} }
void BpfProgram::load_and_attach() {
load();
attach();
}

View File

@ -14,16 +14,17 @@ private:
struct bpf_link* link_; struct bpf_link* link_;
std::string object_path_; std::string object_path_;
std::string program_name_; std::string program_name_;
std::vector<std::pair<bpf_program*, bpf_link*>> programs;
public: public:
explicit BpfProgram(const std::string& object_path, const std::string& program_name = ""); explicit BpfProgram(std::string object_path, std::string program_name = "");
~BpfProgram(); ~BpfProgram();
bool load(); bool load();
bool attach(); bool attach();
void load_and_attach();
bool is_loaded() const { return obj_ != nullptr; } [[nodiscard]] bool is_loaded() const { return obj_ != nullptr; }
bool is_attached() const { return link_ != nullptr; } [[nodiscard]] bool is_attached() const { return link_ != nullptr; }
}; };
#endif //PYLIBBPF_BPF_PROGRAM_H #endif //PYLIBBPF_BPF_PROGRAM_H