From d4202cdc88040c65614f801778c5423074150bff Mon Sep 17 00:00:00 2001 From: Pragyansh Chaturvedi Date: Thu, 27 Nov 2025 03:43:24 +0530 Subject: [PATCH] Add basic userspace support for struct value type for maps --- src/bindings/main.cpp | 4 ++++ src/core/bpf_map.cpp | 24 ++++++++++++++++++++++++ src/core/bpf_map.h | 13 +++++++++++++ 3 files changed, 41 insertions(+) diff --git a/src/bindings/main.cpp b/src/bindings/main.cpp index 023215c..37148ac 100644 --- a/src/bindings/main.cpp +++ b/src/bindings/main.cpp @@ -65,6 +65,10 @@ PYBIND11_MODULE(pylibbpf, m) { .def("get_key_size", &BpfMap::get_key_size) .def("get_value_size", &BpfMap::get_value_size) .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("__setitem__", &BpfMap::update, py::arg("key"), py::arg("value")) .def("__delitem__", &BpfMap::delete_elem, py::arg("key")); diff --git a/src/core/bpf_map.cpp b/src/core/bpf_map.cpp index 794ad3a..2c00ed4 100644 --- a/src/core/bpf_map.cpp +++ b/src/core/bpf_map.cpp @@ -25,6 +25,24 @@ BpfMap::BpfMap(std::shared_ptr parent, struct bpf_map *raw_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 { if (map_fd_ < 0) throw BpfException("Map '" + map_name_ + "' is not initialized properly"); @@ -216,6 +234,12 @@ void BpfMap::python_to_bytes_inplace(const py::object &obj, } py::object BpfMap::bytes_to_python(std::span data) { + // NOTE: Struct parsing for value type + if (struct_parser_ && !value_struct_name_.empty()) { + py::bytes py_data(reinterpret_cast(data.data()), data.size()); + return struct_parser_->parse(value_struct_name_, py_data); + } + if (data.size() == 4) { uint32_t value; std::memcpy(&value, data.data(), 4); diff --git a/src/core/bpf_map.h b/src/core/bpf_map.h index e3d7af3..94bc551 100644 --- a/src/core/bpf_map.h +++ b/src/core/bpf_map.h @@ -9,6 +9,7 @@ #include class BpfObject; +class StructParser; namespace py = pybind11; @@ -20,6 +21,11 @@ private: std::string map_name_; __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 struct_parser_; + std::string value_struct_name_; + template struct BufferManager { std::array stack_buf; std::vector heap_buf; @@ -52,6 +58,7 @@ public: py::dict items() const; py::list keys() const; py::list values() const; + void set_value_struct(const std::string &struct_name); [[nodiscard]] std::string get_name() const { return map_name_; } [[nodiscard]] int get_fd() const { return map_fd_; } @@ -62,6 +69,12 @@ public: [[nodiscard]] std::shared_ptr get_parent() const { 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: static void python_to_bytes_inplace(const py::object &obj,