8 Commits

Author SHA1 Message Date
ecd94057b7 bump version
Signed-off-by: varun-r-mallya <varunrmallya@gmail.com>
2025-11-30 05:46:16 +05:30
68f2bc4b9b Merge pull request #8 from pythonbpf/test-workflow
Add support for using struct as value_type in hashmap
2025-11-28 15:52:48 +05:30
ccce772b51 Merge pull request #7 from pythonbpf/dependabot/github_actions/actions-c546836014
Bump the actions group across 1 directory with 5 updates
2025-11-27 14:06:17 +05:30
8ac2d67a76 Make bytes_to_python const non-static 2025-11-27 03:55:58 +05:30
d4202cdc88 Add basic userspace support for struct value type for maps 2025-11-27 03:43:24 +05:30
13554e9da9 Bump the actions group across 1 directory with 5 updates
Bumps the actions group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `5` | `6` |
| [actions/setup-python](https://github.com/actions/setup-python) | `5` | `6` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4` | `5` |
| [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) | `3.2` | `3.3` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `5` | `6` |



Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

Updates `actions/setup-python` from 5 to 6
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

Updates `actions/upload-artifact` from 4 to 5
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

Updates `pypa/cibuildwheel` from 3.2 to 3.3
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v3.2...v3.3)

Updates `actions/download-artifact` from 5 to 6
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: pypa/cibuildwheel
  dependency-version: '3.3'
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 01:39:00 +00:00
9a54aedb37 Update Python version link in README 2025-11-11 17:35:48 +05:30
270f4337d3 Merge pull request #6 from pythonbpf/test-workflow
Fix GH Actions, make Python3.12 the oldest supported version
2025-11-11 17:34:13 +05:30
10 changed files with 57 additions and 15 deletions

View File

@ -15,7 +15,7 @@ jobs:
name: Format name: Format
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
with: with:
python-version: "3.x" python-version: "3.x"

View File

@ -18,7 +18,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v5 uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
@ -32,7 +32,7 @@ jobs:
ls -la libbpf/src/ || echo "libbpf/src not found!" ls -la libbpf/src/ || echo "libbpf/src not found!"
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5 uses: actions/setup-python@v6
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}

View File

@ -15,7 +15,7 @@ jobs:
name: Build SDist name: Build SDist
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
@ -25,7 +25,7 @@ jobs:
- name: Check metadata - name: Check metadata
run: pipx run twine check dist/* run: pipx run twine check dist/*
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v5
with: with:
name: cibw-sdist name: cibw-sdist
path: dist/*.tar.gz path: dist/*.tar.gz
@ -39,12 +39,12 @@ jobs:
arch: [x86_64] arch: [x86_64]
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.2 uses: pypa/cibuildwheel@v3.3
env: env:
CIBW_PLATFORM: linux CIBW_PLATFORM: linux
CIBW_ARCHS_LINUX: ${{ matrix.arch }} CIBW_ARCHS_LINUX: ${{ matrix.arch }}
@ -65,7 +65,7 @@ jobs:
shell: bash shell: bash
- name: Upload wheels - name: Upload wheels
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: cibw-wheels-linux-${{ matrix.arch }} name: cibw-wheels-linux-${{ matrix.arch }}
path: wheelhouse/*.whl path: wheelhouse/*.whl
@ -82,7 +82,7 @@ jobs:
steps: steps:
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v5 uses: actions/download-artifact@v6
with: with:
pattern: cibw-* pattern: cibw-*
path: dist path: dist

View File

@ -11,7 +11,7 @@
</picture> </picture>
<p align="center"> <p align="center">
<!-- PyPI --> <!-- PyPI -->
<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://www.python.org/downloads/release/python-3120/"><img src="https://img.shields.io/badge/python-3.12-blue.svg"></a>
<a href="https://pypi.org/project/pylibbpf"><img src="https://badge.fury.io/py/pylibbpf.svg"></a> <a href="https://pypi.org/project/pylibbpf"><img src="https://badge.fury.io/py/pylibbpf.svg"></a>
<!-- <a href="https://pypi.org/project/pythonbpf/"><img src="https://img.shields.io/pypi/status/pythonbpf" alt="PyPI Status"></a> --> <!-- <a href="https://pypi.org/project/pythonbpf/"><img src="https://img.shields.io/pypi/status/pythonbpf" alt="PyPI Status"></a> -->
<a href="https://pepy.tech/project/pylibbpf"><img src="https://pepy.tech/badge/pylibbpf" alt="Downloads"></a> <a href="https://pepy.tech/project/pylibbpf"><img src="https://pepy.tech/badge/pylibbpf" alt="Downloads"></a>

View File

@ -43,4 +43,4 @@ __all__ = [
"BpfException", "BpfException",
] ]
__version__ = "0.0.6" __version__ = "0.0.7"

View File

@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "pylibbpf" name = "pylibbpf"
version = "0.0.6" version = "0.0.7"
description = "Python Bindings for Libbpf" description = "Python Bindings for Libbpf"
authors = [ authors = [
{ name = "r41k0u", email = "pragyanshchaturvedi18@gmail.com" }, { name = "r41k0u", email = "pragyanshchaturvedi18@gmail.com" },

View File

@ -65,6 +65,10 @@ PYBIND11_MODULE(pylibbpf, m) {
.def("get_key_size", &BpfMap::get_key_size) .def("get_key_size", &BpfMap::get_key_size)
.def("get_value_size", &BpfMap::get_value_size) .def("get_value_size", &BpfMap::get_value_size)
.def("get_max_entries", &BpfMap::get_max_entries) .def("get_max_entries", &BpfMap::get_max_entries)
.def("set_value_struct", &BpfMap::set_value_struct,
py::arg("struct_name"))
.def("get_value_struct_name", &BpfMap::get_value_struct_name)
.def("has_struct_value", &BpfMap::has_struct_value)
.def("__getitem__", &BpfMap::lookup, py::arg("key")) .def("__getitem__", &BpfMap::lookup, py::arg("key"))
.def("__setitem__", &BpfMap::update, py::arg("key"), py::arg("value")) .def("__setitem__", &BpfMap::update, py::arg("key"), py::arg("value"))
.def("__delitem__", &BpfMap::delete_elem, py::arg("key")); .def("__delitem__", &BpfMap::delete_elem, py::arg("key"));

View File

@ -1,6 +1,7 @@
#include "core/bpf_map.h" #include "core/bpf_map.h"
#include "core/bpf_exception.h" #include "core/bpf_exception.h"
#include "core/bpf_object.h" #include "core/bpf_object.h"
#include "utils/struct_parser.h"
#include <algorithm> #include <algorithm>
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
@ -25,6 +26,24 @@ BpfMap::BpfMap(std::shared_ptr<BpfObject> parent, struct bpf_map *raw_map,
value_size_ = bpf_map__value_size(map_); value_size_ = bpf_map__value_size(map_);
} }
void BpfMap::set_value_struct(const std::string &struct_name) {
auto parent = parent_obj_.lock();
if (!parent) {
throw BpfException("Parent BpfObject no longer exists");
}
struct_parser_ = parent->get_struct_parser();
if (!struct_parser_) {
throw BpfException("No struct definitions available in BpfObject");
}
if (!struct_parser_->has_struct(struct_name)) {
throw BpfException("Unknown struct: " + struct_name);
}
value_struct_name_ = struct_name;
}
py::object BpfMap::lookup(const py::object &key) const { py::object BpfMap::lookup(const py::object &key) const {
if (map_fd_ < 0) if (map_fd_ < 0)
throw BpfException("Map '" + map_name_ + "' is not initialized properly"); throw BpfException("Map '" + map_name_ + "' is not initialized properly");
@ -215,7 +234,13 @@ void BpfMap::python_to_bytes_inplace(const py::object &obj,
} }
} }
py::object BpfMap::bytes_to_python(std::span<const uint8_t> data) { py::object BpfMap::bytes_to_python(std::span<const uint8_t> data) const {
// NOTE: Struct parsing for value type
if (struct_parser_ && !value_struct_name_.empty()) {
py::bytes py_data(reinterpret_cast<const char *>(data.data()), data.size());
return struct_parser_->parse(value_struct_name_, py_data);
}
if (data.size() == 4) { if (data.size() == 4) {
uint32_t value; uint32_t value;
std::memcpy(&value, data.data(), 4); std::memcpy(&value, data.data(), 4);

View File

@ -9,6 +9,7 @@
#include <vector> #include <vector>
class BpfObject; class BpfObject;
class StructParser;
namespace py = pybind11; namespace py = pybind11;
@ -20,6 +21,11 @@ private:
std::string map_name_; std::string map_name_;
__u32 key_size_, value_size_; __u32 key_size_, value_size_;
// TODO: For now, we'll only support struct parsing for value types
// later we can extend this to keys
std::shared_ptr<StructParser> struct_parser_;
std::string value_struct_name_;
template <size_t StackSize = 64> struct BufferManager { template <size_t StackSize = 64> struct BufferManager {
std::array<uint8_t, StackSize> stack_buf; std::array<uint8_t, StackSize> stack_buf;
std::vector<uint8_t> heap_buf; std::vector<uint8_t> heap_buf;
@ -52,6 +58,7 @@ public:
py::dict items() const; py::dict items() const;
py::list keys() const; py::list keys() const;
py::list values() const; py::list values() const;
void set_value_struct(const std::string &struct_name);
[[nodiscard]] std::string get_name() const { return map_name_; } [[nodiscard]] std::string get_name() const { return map_name_; }
[[nodiscard]] int get_fd() const { return map_fd_; } [[nodiscard]] int get_fd() const { return map_fd_; }
@ -62,11 +69,17 @@ public:
[[nodiscard]] std::shared_ptr<BpfObject> get_parent() const { [[nodiscard]] std::shared_ptr<BpfObject> get_parent() const {
return parent_obj_.lock(); return parent_obj_.lock();
} }
[[nodiscard]] std::string get_value_struct_name() const {
return value_struct_name_;
}
[[nodiscard]] bool has_struct_value() const {
return !value_struct_name_.empty();
}
private: private:
static void python_to_bytes_inplace(const py::object &obj, static void python_to_bytes_inplace(const py::object &obj,
std::span<uint8_t> buffer); std::span<uint8_t> buffer);
static py::object bytes_to_python(std::span<const uint8_t> data); py::object bytes_to_python(std::span<const uint8_t> data) const;
}; };
#endif // PYLIBBPF_BPF_MAP_H #endif // PYLIBBPF_BPF_MAP_H

View File

@ -2,6 +2,6 @@ import pylibbpf as m
def test_main(): def test_main():
assert m.__version__ == "0.0.6" assert m.__version__ == "0.0.7"
prog = m.BpfObject("tests/execve2.o", structs={}) prog = m.BpfObject("tests/execve2.o", structs={})
print(prog) print(prog)