From 3c8c6deb68caf3c972a31aa4c7dc580829da2b08 Mon Sep 17 00:00:00 2001 From: varun-r-mallya Date: Sun, 21 Sep 2025 14:27:07 +0530 Subject: [PATCH] Add basic class along with exception and attach Signed-off-by: varun-r-mallya --- CMakeLists.txt | 12 ++++---- src/bindings/main.cpp | 44 +++++++++++++++++++++++++++++ src/core/bpf_exception.h | 16 +++++++++++ src/core/bpf_program.cpp | 58 +++++++++++++++++++++++++++++++++++++++ src/core/bpf_program.h | 29 ++++++++++++++++++++ src/main.cpp | 46 ------------------------------- tests/execve2.o | Bin 0 -> 2392 bytes tests/test_basic.py | 4 +-- 8 files changed, 156 insertions(+), 53 deletions(-) create mode 100644 src/bindings/main.cpp create mode 100644 src/core/bpf_exception.h create mode 100644 src/core/bpf_program.cpp create mode 100644 src/core/bpf_program.h delete mode 100644 src/main.cpp create mode 100644 tests/execve2.o diff --git a/CMakeLists.txt b/CMakeLists.txt index 37bbf0a..61d575e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,11 @@ -cmake_minimum_required(VERSION 3.16) # 4.0 does not exist +cmake_minimum_required(VERSION 4.0) project(pylibbpf) # pybind11 +include_directories(${CMAKE_SOURCE_DIR}/src) add_subdirectory(pybind11) -pybind11_add_module(pylibbpf src/main.cpp) +pybind11_add_module(pylibbpf src/core/bpf_program.h src/core/bpf_exception.h + src/bindings/main.cpp src/core/bpf_program.cpp) # --- libbpf build rules --- set(LIBBPF_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libbpf/src) @@ -12,8 +14,8 @@ set(LIBBPF_A ${LIBBPF_BUILD_DIR}/libbpf.a) add_custom_command( OUTPUT ${LIBBPF_A} - COMMAND make BUILD_STATIC_ONLY=1 OBJDIR=${LIBBPF_BUILD_DIR} -C - ${LIBBPF_SRC_DIR} + COMMAND make BUILD_STATIC_ONLY=1 OBJDIR=${LIBBPF_BUILD_DIR} CFLAGS="-fPIC" + LDFLAGS="-fPIC" -C ${LIBBPF_SRC_DIR} WORKING_DIRECTORY ${LIBBPF_SRC_DIR} COMMENT "Building libbpf.a" VERBATIM) @@ -33,7 +35,7 @@ set_target_properties( add_dependencies(libbpf_static libbpf_build) # Link pybind11 module against libbpf -target_link_libraries(pylibbpf PRIVATE libbpf_static) +target_link_libraries(pylibbpf PRIVATE libbpf_static elf) # Version info for Python extension target_compile_definitions(pylibbpf diff --git a/src/bindings/main.cpp b/src/bindings/main.cpp new file mode 100644 index 0000000..4989446 --- /dev/null +++ b/src/bindings/main.cpp @@ -0,0 +1,44 @@ +#include +#define STRINGIFY(x) #x +#define MACRO_STRINGIFY(x) STRINGIFY(x) + +extern "C" { +#include "libbpf.h" +} +#include "core/bpf_program.h" +#include "core/bpf_exception.h" + +namespace py = pybind11; + +PYBIND11_MODULE(pylibbpf, m) { + m.doc() = R"pbdoc( + Pylibbpf - libbpf bindings for Python + ----------------------- + + .. currentmodule:: pylibbpf + + .. autosummary:: + :toctree: _generate + + BpfProgram + BpfException + )pbdoc"; + + // Register the custom exception + py::register_exception(m, "BpfException"); + + py::class_(m, "BpfProgram") + .def(py::init()) + .def(py::init()) + .def("load", &BpfProgram::load) + .def("attach", &BpfProgram::attach) + // .def("detach", &BpfProgram::detach) + .def("is_loaded", &BpfProgram::is_loaded) + .def("is_attached", &BpfProgram::is_attached); + +#ifdef VERSION_INFO + m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO); +#else + m.attr("__version__") = "dev"; +#endif +} diff --git a/src/core/bpf_exception.h b/src/core/bpf_exception.h new file mode 100644 index 0000000..efd95d3 --- /dev/null +++ b/src/core/bpf_exception.h @@ -0,0 +1,16 @@ +#ifndef PYLIBBPF_BPF_EXCEPTION_H +#define PYLIBBPF_BPF_EXCEPTION_H + +#include +#include + +class BpfException final : public std::runtime_error { +public: + explicit BpfException(const std::string& message) + : std::runtime_error(message) {} + + explicit BpfException(const char* message) + : std::runtime_error(message) {} +}; + +#endif // PYLIBBPF_BPF_EXCEPTION_H diff --git a/src/core/bpf_program.cpp b/src/core/bpf_program.cpp new file mode 100644 index 0000000..0b59e60 --- /dev/null +++ b/src/core/bpf_program.cpp @@ -0,0 +1,58 @@ +#include "bpf_program.h" +#include "bpf_exception.h" +#include + +BpfProgram::BpfProgram(const std::string& object_path, const std::string& program_name) + : obj_(nullptr), prog_(nullptr), link_(nullptr), + object_path_(object_path), program_name_(program_name) { +} + +BpfProgram::~BpfProgram() { + //TODO: detach here as well + if (obj_) { + bpf_object__close(obj_); + } +} + +bool BpfProgram::load() { + // Open the eBPF object file + obj_ = bpf_object__open_file(object_path_.c_str(), nullptr); + if (libbpf_get_error(obj_)) { + throw BpfException("Failed to open BPF object file: " + object_path_); + } + + // Find the program by name (if specified) + if (!program_name_.empty()) { + prog_ = bpf_object__find_program_by_name(obj_, program_name_.c_str()); + if (!prog_) { + throw BpfException("Program '" + program_name_ + "' not found in object"); + } + } else { + // Use the first program if no name specified + prog_ = bpf_object__next_program(obj_, nullptr); + if (!prog_) { + throw BpfException("No programs found in object file"); + } + } + + // Load the eBPF object into the kernel + if (bpf_object__load(obj_)) { + throw BpfException("Failed to load BPF object into kernel"); + } + + return true; +} + +bool BpfProgram::attach() { + if (!prog_) { + throw BpfException("Program not loaded"); + } + + link_ = bpf_program__attach(prog_); + if (libbpf_get_error(link_)) { + link_ = nullptr; + throw BpfException("Failed to attach BPF program"); + } + + return true; +} diff --git a/src/core/bpf_program.h b/src/core/bpf_program.h new file mode 100644 index 0000000..c603f89 --- /dev/null +++ b/src/core/bpf_program.h @@ -0,0 +1,29 @@ +#ifndef PYLIBBPF_BPF_PROGRAM_H +#define PYLIBBPF_BPF_PROGRAM_H + +#include "libbpf.h" +#include +#include + +namespace py = pybind11; + +class BpfProgram { +private: + struct bpf_object* obj_; + struct bpf_program* prog_; + struct bpf_link* link_; + std::string object_path_; + std::string program_name_; + +public: + explicit BpfProgram(const std::string& object_path, const std::string& program_name = ""); + ~BpfProgram(); + + bool load(); + bool attach(); + + bool is_loaded() const { return obj_ != nullptr; } + bool is_attached() const { return link_ != nullptr; } +}; + +#endif //PYLIBBPF_BPF_PROGRAM_H diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 98612c7..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#define STRINGIFY(x) #x -#define MACRO_STRINGIFY(x) STRINGIFY(x) - -extern "C" { -#include "libbpf.h" -} - -int add(int i, int j) { - return i + j; -} - -namespace py = pybind11; - -PYBIND11_MODULE(pylibbpf, m) { - m.doc() = R"pbdoc( - Pybind11 example plugin - ----------------------- - - .. currentmodule:: pylibbpf - - .. autosummary:: - :toctree: _generate - - add - subtract - )pbdoc"; - - m.def("add", &add, R"pbdoc( - Add two numbers - - Some other explanation about the add function. - )pbdoc"); - - m.def("subtract", [](int i, int j) { return i - j; }, R"pbdoc( - Subtract two numbers - - Some other explanation about the subtract function. - )pbdoc"); - -#ifdef VERSION_INFO - m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO); -#else - m.attr("__version__") = "dev"; -#endif -} diff --git a/tests/execve2.o b/tests/execve2.o new file mode 100644 index 0000000000000000000000000000000000000000..44d797adece3f4d76bf560b2e50d3aaad22729ab GIT binary patch literal 2392 zcmbVO&1(};5T7Ki)>hhD1Vs?GdJ-h9iXfg=C6!8%&{m{+ShwkG3~n|dyO9P3y$BvW zcoFpE$IYV$5xgk=1s*+#cTak;w>ZDIGuiDLdT?Og%>3Sbyf^bUfXe9%k&rR>J;aHgx}kY&;VQ|5n&e;&jk1ag!)Uyq?($%L`#n2m92c7wR#)LLN_`(f-v-FCax ziO0!oHDc^vt}Y?b%b(m6$@rBe_@>w_iX~p;3WX8Y9cCeH5nqFV!)KD2DeqT=k5F+h zE5{O}fIhj2jvONn>t~sz9-SB6Wx2qNemrEp!i-scX09?bO(GZKt|fAc#bAyOjBXe; z>Y>?i8evSHcVT(?!kV|Tc%$O2u2n0ZmpTNku(?!nt58h5)hHALe2>r5eC+|=qJAxfB=2x&U zFoE?ge-T`5ojJTpwzG-9uHRWfo>>9VU!_tezhaOj+l4Gbbd=4R%sI6W$1RSDCZv6s zVep7^dHe7_69gmhk-n!|y_t z+^mt&CG7ygZ{BY4`ffEK`#k`=&Wvx%WzN#H6mkT_Z=}8*K+}SsVL7b+Q`v8eRFSVg z#~Z`y&kw1OcdGGP{}5xSkF)I{fJ}~E(?#PIdCLl1@r`83k@yo?kad9v=tIHs^%uo4 zKd*fJ`yn}zyef{Dasl~#@7Q-(|El7seZu_4nf3mPKVd9af)V~7A`Nk^l`a~u$YWN9 j)xRb6U2#NxymgJ&`mY(w_Z}hN1Ux5)gFqdP*Wb6ls?@=f literal 0 HcmV?d00001 diff --git a/tests/test_basic.py b/tests/test_basic.py index 1d63b64..9f702b6 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -3,5 +3,5 @@ import pylibbpf as m def test_main(): assert m.__version__ == "0.0.1" - assert m.add(1, 2) == 3 - assert m.subtract(1, 2) == -1 + prog = m.BpfProgram("tests/execve2.o") + print(prog)