Skip to content

Commit 763c188

Browse files
committed
Implement BpfObject class
1 parent 528a542 commit 763c188

File tree

2 files changed

+260
-2
lines changed

2 files changed

+260
-2
lines changed

src/core/bpf_object.cpp

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
#include "bpf_object.h"
2+
#include "bpf_program.h"
3+
#include "bpf_map.h"
4+
#include "bpf_exception.h"
5+
#include <cerrno>
6+
7+
BpfObject::BpfObject(std::string object_path)
8+
: obj_(nullptr), object_path_(std::move(object_path)), loaded_(false) {
9+
}
10+
11+
BpfObject::~BpfObject() {
12+
// Clear caches first (order matters!)
13+
prog_cache_.clear(); // Detaches programs
14+
maps_cache_.clear(); // Closes maps
15+
16+
// Then close object
17+
if (obj_) {
18+
bpf_object__close(obj_);
19+
obj_ = nullptr;
20+
}
21+
}
22+
23+
BpfObject::BpfObject(BpfObject&& other) noexcept
24+
: obj_(other.obj_),
25+
object_path_(std::move(other.object_path_)),
26+
loaded_(other.loaded_),
27+
prog_cache_(std::move(other.prog_cache_)),
28+
maps_cache_(std::move(other.maps_cache_)) {
29+
30+
other.obj_ = nullptr;
31+
other.loaded_ = false;
32+
}
33+
34+
BpfObject& BpfObject::operator=(BpfObject&& other) noexcept {
35+
if (this != &other) {
36+
prog_cache_.clear();
37+
maps_cache_.clear();
38+
if (obj_) {
39+
bpf_object__close(obj_);
40+
}
41+
42+
obj_ = other.obj_;
43+
object_path_ = std::move(other.object_path_);
44+
loaded_ = other.loaded_;
45+
prog_cache_ = std::move(other.prog_cache_);
46+
maps_cache_ = std::move(other.maps_cache_);
47+
48+
other.obj_ = nullptr;
49+
other.loaded_ = false;
50+
}
51+
return *this;
52+
}
53+
54+
void BpfObject::load() {
55+
if (loaded_) {
56+
throw BpfException("BPF object already loaded");
57+
}
58+
59+
std::string error_msg = "Failed to open BPF object";
60+
obj_ = bpf_object__open_file(object_path_.c_str(), nullptr);
61+
62+
if (!obj_) {
63+
error_msg += " file '" + object_path_ + "': " + std::strerror(errno);
64+
throw BpfException(error_msg);
65+
}
66+
67+
if (bpf_object__load(obj_)) {
68+
std::string error_msg = " object from file '" + object_path_ + "': " + std::strerror(errno);
69+
bpf_object__close(obj_);
70+
obj_ = nullptr;
71+
throw BpfException(error_msg);
72+
}
73+
74+
loaded_ = true;
75+
}
76+
77+
// ==================== Program Methods ====================
78+
79+
py::list BpfObject::get_program_names() const {
80+
if (!loaded_) {
81+
throw BpfException("BPF object not loaded");
82+
}
83+
84+
py::list names;
85+
struct bpf_program *prog = nullptr;
86+
87+
bpf_object__for_each_program(prog, obj_) {
88+
_get_or_create_program(prog); // Ensure cached
89+
names.append(bpf_program__name(prog));
90+
}
91+
92+
return names;
93+
}
94+
95+
std::shared_ptr<BpfProgram> BpfObject::_get_or_create_program(struct bpf_program *prog) {
96+
if (!prog) {
97+
throw BpfException("bpf_program pointer is null");
98+
}
99+
100+
const char *name = bpf_program__name(prog);
101+
std::string prog_name(name ? name : "");
102+
103+
// Check cache
104+
auto it = prog_cache_.find(prog_name);
105+
if (it != prog_cache_.end()) {
106+
return it->second;
107+
}
108+
109+
// Create and cache
110+
auto bpf_prog = std::make_shared<BpfProgram>(this, prog, prog_name);
111+
prog_cache_[prog_name] = bpf_prog;
112+
113+
return bpf_prog;
114+
}
115+
116+
std::shared_ptr<BpfProgram> BpfObject::get_program(const std::string& name) {
117+
if (!loaded_) {
118+
throw BpfException("BPF object not loaded");
119+
}
120+
121+
// Check cache
122+
auto it = prog_cache_.find(name);
123+
if (it != prog_cache_.end()) {
124+
return it->second;
125+
}
126+
127+
// Create and cache
128+
struct bpf_program *raw_prog = find_program_by_name(name);
129+
auto prog = std::make_shared<BpfProgram>(this, raw_prog, name);
130+
prog_cache_[name] = prog;
131+
132+
return prog;
133+
}
134+
135+
struct bpf_program* BpfObject::find_program_by_name(const std::string& name) const {
136+
if (!loaded_) {
137+
throw BpfException("BPF object not loaded");
138+
}
139+
140+
struct bpf_program *prog = bpf_object__find_program_by_name(obj_, name.c_str());
141+
if (!prog) {
142+
throw BpfException("Program '" + name + "' not found");
143+
}
144+
145+
return prog;
146+
}
147+
148+
py::dict BpfObject::get_cached_programs() const {
149+
py::dict programs;
150+
for (const auto& [name, prog] : prog_cache_) {
151+
programs[name] = prog;
152+
}
153+
return programs;
154+
}
155+
156+
py::dict BpfObject::attach_all() {
157+
if (!loaded_) {
158+
throw BpfException("BPF object not loaded");
159+
}
160+
161+
py::dict attached_programs;
162+
struct bpf_program *prog = nullptr;
163+
164+
bpf_object__for_each_program(prog, obj_) {
165+
auto bpf_prog = _get_or_create_program(prog);
166+
167+
if (!bpf_prog->is_attached()) {
168+
bpf_prog->attach();
169+
}
170+
171+
const char *name = bpf_program__name(prog);
172+
attached_programs[name] = bpf_prog;
173+
}
174+
175+
return attached_programs;
176+
}
177+
178+
// ==================== Map Methods ====================
179+
180+
py::list BpfObject::get_map_names() const {
181+
if (!loaded_) {
182+
throw BpfException("BPF object not loaded");
183+
}
184+
185+
py::list names;
186+
struct bpf_map *map = nullptr;
187+
188+
bpf_object__for_each_map(map, obj_) {
189+
_get_or_create_map(map); // Ensure cached
190+
names.append(bpf_map__name(map));
191+
}
192+
193+
return names;
194+
}
195+
196+
std::shared_ptr<BpfMap> BpfObject::get_map(const std::string& name) {
197+
if (!loaded_) {
198+
throw BpfException("BPF object not loaded");
199+
}
200+
201+
// Check cache
202+
auto it = maps_cache_.find(name);
203+
if (it != maps_cache_.end()) {
204+
return it->second;
205+
}
206+
207+
// Create and cache
208+
struct bpf_map *raw_map = find_map_by_name(name);
209+
auto map = std::make_shared<BpfMap>(this, raw_map, name);
210+
maps_cache_[name] = map;
211+
212+
return map;
213+
}
214+
215+
std::shared_ptr<BpfMap> BpfObject::_get_or_create_map(struct bpf_map *map) {
216+
if (!map) {
217+
throw BpfException("bpf_map pointer is null");
218+
}
219+
220+
const char *name = bpf_map__name(map);
221+
std::string map_name(name ? name : "");
222+
223+
// Check cache
224+
auto it = maps_cache_.find(map_name);
225+
if (it != maps_cache_.end()) {
226+
return it->second;
227+
}
228+
229+
// Create and cache
230+
auto bpf_map = std::make_shared<BpfMap>(this, map, map_name);
231+
maps_cache_[map_name] = bpf_map;
232+
233+
return bpf_map;
234+
}
235+
236+
struct bpf_map* BpfObject::find_map_by_name(const std::string& name) const {
237+
if (!loaded_) {
238+
throw BpfException("BPF object not loaded");
239+
}
240+
241+
struct bpf_map *map = bpf_object__find_map_by_name(obj_, name.c_str());
242+
if (!map) {
243+
throw BpfException("Map '" + name + "' not found");
244+
}
245+
246+
return map;
247+
}
248+
249+
py::dict BpfObject::get_cached_maps() const {
250+
py::dict maps;
251+
for (const auto& [name, map] : maps_cache_) {
252+
maps[name] = map;
253+
}
254+
return maps;
255+
}

src/core/bpf_object.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ class BpfObject {
2828
mutable std::unordered_map<std::string, std::shared_ptr<BpfMap>> maps_cache_;
2929
mutable std::unordered_map<std::string, std::shared_ptr<BpfProgram>> prog_cache_;
3030

31+
std::shared_ptr<BpfProgram> _get_or_create_program(struct bpf_program *prog);
32+
std::shared_ptr<BpfMap> _get_or_create_map(struct bpf_map *map);
33+
3134
public:
3235
explicit BpfObject(std::string object_path);
3336
~BpfObject();
@@ -64,13 +67,13 @@ class BpfObject {
6467
[[nodiscard]] py::list get_program_names() const;
6568
[[nodiscard]] std::shared_ptr<BpfProgram> get_program(const std::string& name);
6669
[[nodiscard]] struct bpf_program* find_program_by_name(const std::string& name) const;
67-
[[nodiscard]] py::dict get_programs() const;
70+
[[nodiscard]] py::dict get_cached_programs() const;
6871

6972
// Map access
7073
[[nodiscard]] py::list get_map_names() const;
7174
[[nodiscard]] std::shared_ptr<BpfMap> get_map(const std::string& name);
7275
[[nodiscard]] struct bpf_map* find_map_by_name(const std::string& name) const;
73-
[[nodiscard]] py::dict get_maps() const;
76+
[[nodiscard]] py::dict get_cached_maps() const;
7477
};
7578

7679
#endif // PYLIBBPF_BPF_OBJECT_H

0 commit comments

Comments
 (0)