1 /*
2 * Copyright (c) 2016 Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 #include <errno.h>
20 #include <sys/epoll.h>
21 #include <cstring>
22 #include <exception>
23 #include <map>
24 #include <memory>
25 #include <string>
26 #include <utility>
27 #include <vector>
28
29 #include "bcc_exception.h"
30 #include "bcc_syms.h"
31 #include "bpf_module.h"
32 #include "libbpf.h"
33 #include "perf_reader.h"
34 #include "table_desc.h"
35 #include "linux/bpf.h"
36
37 namespace ebpf {
38
39 template<class ValueType>
40 class BPFQueueStackTableBase {
41 public:
capacity()42 size_t capacity() const { return desc.max_entries; }
43
string_to_leaf(const std::string & value_str,ValueType * value)44 StatusTuple string_to_leaf(const std::string& value_str, ValueType* value) {
45 return desc.leaf_sscanf(value_str.c_str(), value);
46 }
47
leaf_to_string(const ValueType * value,std::string & value_str)48 StatusTuple leaf_to_string(const ValueType* value, std::string& value_str) {
49 char buf[8 * desc.leaf_size];
50 StatusTuple rc = desc.leaf_snprintf(buf, sizeof(buf), value);
51 if (rc.ok())
52 value_str.assign(buf);
53 return rc;
54 }
55
get_fd()56 int get_fd() { return desc.fd; }
57
58 protected:
BPFQueueStackTableBase(const TableDesc & desc)59 explicit BPFQueueStackTableBase(const TableDesc& desc) : desc(desc) {}
60
pop(void * value)61 bool pop(void *value) {
62 return bpf_lookup_and_delete(desc.fd, nullptr, value) >= 0;
63 }
64 // Flags are extremely useful, since they completely changes extraction behaviour
65 // (eg. if flag BPF_EXIST, then if the queue/stack is full remove the oldest one)
push(void * value,unsigned long long int flags)66 bool push(void *value, unsigned long long int flags) {
67 return bpf_update_elem(desc.fd, nullptr, value, flags) >= 0;
68 }
69
peek(void * value)70 bool peek(void *value) {
71 return bpf_lookup_elem(desc.fd, nullptr, value) >= 0;
72 }
73
74 const TableDesc& desc;
75 };
76
77 template <class KeyType, class ValueType>
78 class BPFTableBase {
79 public:
capacity()80 size_t capacity() { return desc.max_entries; }
81
string_to_key(const std::string & key_str,KeyType * key)82 StatusTuple string_to_key(const std::string& key_str, KeyType* key) {
83 return desc.key_sscanf(key_str.c_str(), key);
84 }
85
string_to_leaf(const std::string & value_str,ValueType * value)86 StatusTuple string_to_leaf(const std::string& value_str, ValueType* value) {
87 return desc.leaf_sscanf(value_str.c_str(), value);
88 }
89
key_to_string(const KeyType * key,std::string & key_str)90 StatusTuple key_to_string(const KeyType* key, std::string& key_str) {
91 char buf[8 * desc.key_size];
92 StatusTuple rc = desc.key_snprintf(buf, sizeof(buf), key);
93 if (rc.ok())
94 key_str.assign(buf);
95 return rc;
96 }
97
leaf_to_string(const ValueType * value,std::string & value_str)98 StatusTuple leaf_to_string(const ValueType* value, std::string& value_str) {
99 char buf[8 * desc.leaf_size];
100 StatusTuple rc = desc.leaf_snprintf(buf, sizeof(buf), value);
101 if (rc.ok())
102 value_str.assign(buf);
103 return rc;
104 }
105
get_fd()106 int get_fd() {
107 return desc.fd;
108 }
109
110 protected:
BPFTableBase(const TableDesc & desc)111 explicit BPFTableBase(const TableDesc& desc) : desc(desc) {}
112
lookup(void * key,void * value)113 bool lookup(void* key, void* value) {
114 return bpf_lookup_elem(desc.fd, key, value) >= 0;
115 }
116
first(void * key)117 bool first(void* key) {
118 return bpf_get_first_key(desc.fd, key, desc.key_size) >= 0;
119 }
120
next(void * key,void * next_key)121 bool next(void* key, void* next_key) {
122 return bpf_get_next_key(desc.fd, key, next_key) >= 0;
123 }
124
update(void * key,void * value)125 bool update(void* key, void* value) {
126 return bpf_update_elem(desc.fd, key, value, 0) >= 0;
127 }
128
remove(void * key)129 bool remove(void* key) { return bpf_delete_elem(desc.fd, key) >= 0; }
130
131 const TableDesc& desc;
132 };
133
134 class BPFTable : public BPFTableBase<void, void> {
135 public:
136 BPFTable(const TableDesc& desc);
137
138 StatusTuple get_value(const std::string& key_str, std::string& value);
139 StatusTuple get_value(const std::string& key_str,
140 std::vector<std::string>& value);
141
142 StatusTuple update_value(const std::string& key_str,
143 const std::string& value_str);
144 StatusTuple update_value(const std::string& key_str,
145 const std::vector<std::string>& value_str);
146
147 StatusTuple remove_value(const std::string& key_str);
148
149 StatusTuple clear_table_non_atomic();
150 StatusTuple get_table_offline(std::vector<std::pair<std::string, std::string>> &res);
151
152 static size_t get_possible_cpu_count();
153 };
154
155 template <class ValueType>
get_value_addr(ValueType & t)156 void* get_value_addr(ValueType& t) {
157 return &t;
158 }
159
160 template <class ValueType>
get_value_addr(std::vector<ValueType> & t)161 void* get_value_addr(std::vector<ValueType>& t) {
162 return t.data();
163 }
164
165 template<class ValueType>
166 class BPFQueueStackTable : public BPFQueueStackTableBase<void> {
167 public:
BPFQueueStackTable(const TableDesc & desc)168 explicit BPFQueueStackTable(const TableDesc& desc) : BPFQueueStackTableBase(desc) {
169 if (desc.type != BPF_MAP_TYPE_QUEUE &&
170 desc.type != BPF_MAP_TYPE_STACK)
171 throw std::invalid_argument("Table '" + desc.name +
172 "' is not a queue/stack table");
173 }
174
pop_value(ValueType & value)175 virtual StatusTuple pop_value(ValueType& value) {
176 if (!this->pop(get_value_addr(value)))
177 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
178 return StatusTuple::OK();
179 }
180
181 virtual StatusTuple push_value(const ValueType& value, unsigned long long int flags = 0) {
182 if (!this->push(get_value_addr(const_cast<ValueType&>(value)), flags))
183 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
184 return StatusTuple::OK();
185 }
186
get_head(const ValueType & value)187 virtual StatusTuple get_head(const ValueType& value) {
188 if (!this->peek(get_value_addr(const_cast<ValueType&>(value))))
189 return StatusTuple(-1, "Error peeking value: %s", std::strerror(errno));
190 return StatusTuple::OK();
191 }
192 };
193
194 template <class ValueType>
195 class BPFArrayTable : public BPFTableBase<int, ValueType> {
196 public:
BPFArrayTable(const TableDesc & desc)197 BPFArrayTable(const TableDesc& desc) : BPFTableBase<int, ValueType>(desc) {
198 if (desc.type != BPF_MAP_TYPE_ARRAY &&
199 desc.type != BPF_MAP_TYPE_PERCPU_ARRAY)
200 throw std::invalid_argument("Table '" + desc.name +
201 "' is not an array table");
202 }
203
get_value(const int & index,ValueType & value)204 virtual StatusTuple get_value(const int& index, ValueType& value) {
205 if (!this->lookup(const_cast<int*>(&index), get_value_addr(value)))
206 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
207 return StatusTuple::OK();
208 }
209
update_value(const int & index,const ValueType & value)210 virtual StatusTuple update_value(const int& index, const ValueType& value) {
211 if (!this->update(const_cast<int*>(&index),
212 get_value_addr(const_cast<ValueType&>(value))))
213 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
214 return StatusTuple::OK();
215 }
216
217 ValueType operator[](const int& key) {
218 ValueType value;
219 get_value(key, value);
220 return value;
221 }
222
get_table_offline()223 std::vector<ValueType> get_table_offline() {
224 std::vector<ValueType> res(this->capacity());
225
226 for (int i = 0; i < (int)this->capacity(); i++) {
227 get_value(i, res[i]);
228 }
229
230 return res;
231 }
232 };
233
234 template <class ValueType>
235 class BPFPercpuArrayTable : public BPFArrayTable<std::vector<ValueType>> {
236 public:
BPFPercpuArrayTable(const TableDesc & desc)237 BPFPercpuArrayTable(const TableDesc& desc)
238 : BPFArrayTable<std::vector<ValueType>>(desc),
239 ncpus(BPFTable::get_possible_cpu_count()) {
240 if (desc.type != BPF_MAP_TYPE_PERCPU_ARRAY)
241 throw std::invalid_argument("Table '" + desc.name +
242 "' is not a percpu array table");
243 // leaf structures have to be aligned to 8 bytes as hardcoded in the linux
244 // kernel.
245 if (sizeof(ValueType) % 8)
246 throw std::invalid_argument("leaf must be aligned to 8 bytes");
247 }
248
get_value(const int & index,std::vector<ValueType> & value)249 StatusTuple get_value(const int& index, std::vector<ValueType>& value) {
250 value.resize(ncpus);
251 return BPFArrayTable<std::vector<ValueType>>::get_value(index, value);
252 }
253
update_value(const int & index,const std::vector<ValueType> & value)254 StatusTuple update_value(const int& index,
255 const std::vector<ValueType>& value) {
256 if (value.size() != ncpus)
257 return StatusTuple(-1, "bad value size");
258 return BPFArrayTable<std::vector<ValueType>>::update_value(index, value);
259 }
260
261 private:
262 unsigned int ncpus;
263 };
264
265 template <class KeyType, class ValueType>
266 class BPFHashTable : public BPFTableBase<KeyType, ValueType> {
267 public:
BPFHashTable(const TableDesc & desc)268 explicit BPFHashTable(const TableDesc& desc)
269 : BPFTableBase<KeyType, ValueType>(desc) {
270 if (desc.type != BPF_MAP_TYPE_HASH &&
271 desc.type != BPF_MAP_TYPE_PERCPU_HASH &&
272 desc.type != BPF_MAP_TYPE_LRU_HASH &&
273 desc.type != BPF_MAP_TYPE_LRU_PERCPU_HASH)
274 throw std::invalid_argument("Table '" + desc.name +
275 "' is not a hash table");
276 }
277
get_value(const KeyType & key,ValueType & value)278 virtual StatusTuple get_value(const KeyType& key, ValueType& value) {
279 if (!this->lookup(const_cast<KeyType*>(&key), get_value_addr(value)))
280 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
281 return StatusTuple::OK();
282 }
283
update_value(const KeyType & key,const ValueType & value)284 virtual StatusTuple update_value(const KeyType& key, const ValueType& value) {
285 if (!this->update(const_cast<KeyType*>(&key),
286 get_value_addr(const_cast<ValueType&>(value))))
287 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
288 return StatusTuple::OK();
289 }
290
remove_value(const KeyType & key)291 virtual StatusTuple remove_value(const KeyType& key) {
292 if (!this->remove(const_cast<KeyType*>(&key)))
293 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
294 return StatusTuple::OK();
295 }
296
297 ValueType operator[](const KeyType& key) {
298 ValueType value;
299 get_value(key, value);
300 return value;
301 }
302
get_table_offline()303 std::vector<std::pair<KeyType, ValueType>> get_table_offline() {
304 std::vector<std::pair<KeyType, ValueType>> res;
305 KeyType cur;
306 ValueType value;
307
308 StatusTuple r(0);
309
310 if (!this->first(&cur))
311 return res;
312
313 while (true) {
314 r = get_value(cur, value);
315 if (!r.ok())
316 break;
317 res.emplace_back(cur, value);
318 if (!this->next(&cur, &cur))
319 break;
320 }
321
322 return res;
323 }
324
clear_table_non_atomic()325 StatusTuple clear_table_non_atomic() {
326 KeyType cur;
327 while (this->first(&cur))
328 TRY2(remove_value(cur));
329
330 return StatusTuple::OK();
331 }
332 };
333
334 template <class KeyType, class ValueType>
335 class BPFPercpuHashTable
336 : public BPFHashTable<KeyType, std::vector<ValueType>> {
337 public:
BPFPercpuHashTable(const TableDesc & desc)338 explicit BPFPercpuHashTable(const TableDesc& desc)
339 : BPFHashTable<KeyType, std::vector<ValueType>>(desc),
340 ncpus(BPFTable::get_possible_cpu_count()) {
341 if (desc.type != BPF_MAP_TYPE_PERCPU_HASH &&
342 desc.type != BPF_MAP_TYPE_LRU_PERCPU_HASH)
343 throw std::invalid_argument("Table '" + desc.name +
344 "' is not a percpu hash table");
345 // leaf structures have to be aligned to 8 bytes as hardcoded in the linux
346 // kernel.
347 if (sizeof(ValueType) % 8)
348 throw std::invalid_argument("leaf must be aligned to 8 bytes");
349 }
350
get_value(const KeyType & key,std::vector<ValueType> & value)351 StatusTuple get_value(const KeyType& key, std::vector<ValueType>& value) {
352 value.resize(ncpus);
353 return BPFHashTable<KeyType, std::vector<ValueType>>::get_value(key, value);
354 }
355
update_value(const KeyType & key,const std::vector<ValueType> & value)356 StatusTuple update_value(const KeyType& key,
357 const std::vector<ValueType>& value) {
358 if (value.size() != ncpus)
359 return StatusTuple(-1, "bad value size");
360 return BPFHashTable<KeyType, std::vector<ValueType>>::update_value(key,
361 value);
362 }
363
364 private:
365 unsigned int ncpus;
366 };
367
368 // From src/cc/export/helpers.h
369 static const int BPF_MAX_STACK_DEPTH = 127;
370 struct stacktrace_t {
371 uintptr_t ip[BPF_MAX_STACK_DEPTH];
372 };
373
374 class BPFStackTable : public BPFTableBase<int, stacktrace_t> {
375 public:
376 BPFStackTable(const TableDesc& desc, bool use_debug_file,
377 bool check_debug_file_crc);
378 BPFStackTable(BPFStackTable&& that);
379 ~BPFStackTable();
380
381 void free_symcache(int pid);
382 void clear_table_non_atomic();
383 std::vector<uintptr_t> get_stack_addr(int stack_id);
384 std::vector<std::string> get_stack_symbol(int stack_id, int pid);
385
386 private:
387 bcc_symbol_option symbol_option_;
388 std::map<int, void*> pid_sym_;
389 };
390
391 // from src/cc/export/helpers.h
392 struct stacktrace_buildid_t {
393 struct bpf_stack_build_id trace[BPF_MAX_STACK_DEPTH];
394 };
395
396 class BPFStackBuildIdTable : public BPFTableBase<int, stacktrace_buildid_t> {
397 public:
398 BPFStackBuildIdTable(const TableDesc& desc, bool use_debug_file,
399 bool check_debug_file_crc, void *bsymcache);
400 ~BPFStackBuildIdTable() = default;
401
402 void clear_table_non_atomic();
403 std::vector<bpf_stack_build_id> get_stack_addr(int stack_id);
404 std::vector<std::string> get_stack_symbol(int stack_id);
405
406 private:
407 void *bsymcache_;
408 bcc_symbol_option symbol_option_;
409 };
410
411 class BPFPerfBuffer : public BPFTableBase<int, int> {
412 public:
413 BPFPerfBuffer(const TableDesc& desc);
414 ~BPFPerfBuffer();
415
416 StatusTuple open_all_cpu(perf_reader_raw_cb cb, perf_reader_lost_cb lost_cb,
417 void* cb_cookie, int page_cnt);
418 StatusTuple open_all_cpu(perf_reader_raw_cb cb, perf_reader_lost_cb lost_cb,
419 void* cb_cookie, int page_cnt, int wakeup_events);
420 StatusTuple close_all_cpu();
421 int poll(int timeout_ms);
422 int consume();
423
424 private:
425 StatusTuple open_on_cpu(perf_reader_raw_cb cb, perf_reader_lost_cb lost_cb,
426 void* cb_cookie, int page_cnt, struct bcc_perf_buffer_opts& opts);
427 StatusTuple close_on_cpu(int cpu);
428
429 std::map<int, perf_reader*> cpu_readers_;
430
431 int epfd_;
432 std::unique_ptr<epoll_event[]> ep_events_;
433 };
434
435 class BPFPerfEventArray : public BPFTableBase<int, int> {
436 public:
437 BPFPerfEventArray(const TableDesc& desc);
438 ~BPFPerfEventArray();
439
440 StatusTuple open_all_cpu(uint32_t type, uint64_t config);
441 StatusTuple close_all_cpu();
442
443 private:
444 StatusTuple open_on_cpu(int cpu, uint32_t type, uint64_t config);
445 StatusTuple close_on_cpu(int cpu);
446
447 std::map<int, int> cpu_fds_;
448 };
449
450 class BPFProgTable : public BPFTableBase<int, int> {
451 public:
452 BPFProgTable(const TableDesc& desc);
453
454 StatusTuple update_value(const int& index, const int& prog_fd);
455 StatusTuple remove_value(const int& index);
456 };
457
458 class BPFCgroupArray : public BPFTableBase<int, int> {
459 public:
460 BPFCgroupArray(const TableDesc& desc);
461
462 StatusTuple update_value(const int& index, const int& cgroup2_fd);
463 StatusTuple update_value(const int& index, const std::string& cgroup2_path);
464 StatusTuple remove_value(const int& index);
465 };
466
467 class BPFDevmapTable : public BPFTableBase<int, int> {
468 public:
469 BPFDevmapTable(const TableDesc& desc);
470
471 StatusTuple update_value(const int& index, const int& value);
472 StatusTuple get_value(const int& index, int& value);
473 StatusTuple remove_value(const int& index);
474 };
475
476 class BPFXskmapTable : public BPFTableBase<int, int> {
477 public:
478 BPFXskmapTable(const TableDesc& desc);
479
480 StatusTuple update_value(const int& index, const int& value);
481 StatusTuple get_value(const int& index, int& value);
482 StatusTuple remove_value(const int& index);
483 };
484
485 template <class KeyType>
486 class BPFMapInMapTable : public BPFTableBase<KeyType, int> {
487 public:
BPFMapInMapTable(const TableDesc & desc)488 BPFMapInMapTable(const TableDesc& desc) : BPFTableBase<KeyType, int>(desc) {
489 if (desc.type != BPF_MAP_TYPE_ARRAY_OF_MAPS &&
490 desc.type != BPF_MAP_TYPE_HASH_OF_MAPS)
491 throw std::invalid_argument("Table '" + desc.name +
492 "' is not a map-in-map table");
493 }
update_value(const KeyType & key,const int & inner_map_fd)494 virtual StatusTuple update_value(const KeyType& key, const int& inner_map_fd) {
495 if (!this->update(const_cast<KeyType*>(&key),
496 const_cast<int*>(&inner_map_fd)))
497 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
498 return StatusTuple::OK();
499 }
remove_value(const KeyType & key)500 virtual StatusTuple remove_value(const KeyType& key) {
501 if (!this->remove(const_cast<KeyType*>(&key)))
502 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
503 return StatusTuple::OK();
504 }
505 };
506
507 class BPFSockmapTable : public BPFTableBase<int, int> {
508 public:
509 BPFSockmapTable(const TableDesc& desc);
510
511 StatusTuple update_value(const int& index, const int& value);
512 StatusTuple remove_value(const int& index);
513 };
514
515 class BPFSockhashTable : public BPFTableBase<int, int> {
516 public:
517 BPFSockhashTable(const TableDesc& desc);
518
519 StatusTuple update_value(const int& key, const int& value);
520 StatusTuple remove_value(const int& key);
521 };
522
523 template <class ValueType>
524 class BPFSkStorageTable : public BPFTableBase<int, ValueType> {
525 public:
BPFSkStorageTable(const TableDesc & desc)526 BPFSkStorageTable(const TableDesc& desc) : BPFTableBase<int, ValueType>(desc) {
527 if (desc.type != BPF_MAP_TYPE_SK_STORAGE)
528 throw std::invalid_argument("Table '" + desc.name +
529 "' is not a sk_storage table");
530 }
531
get_value(const int & sock_fd,ValueType & value)532 virtual StatusTuple get_value(const int& sock_fd, ValueType& value) {
533 if (!this->lookup(const_cast<int*>(&sock_fd), get_value_addr(value)))
534 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
535 return StatusTuple::OK();
536 }
537
update_value(const int & sock_fd,const ValueType & value)538 virtual StatusTuple update_value(const int& sock_fd, const ValueType& value) {
539 if (!this->update(const_cast<int*>(&sock_fd),
540 get_value_addr(const_cast<ValueType&>(value))))
541 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
542 return StatusTuple::OK();
543 }
544
remove_value(const int & sock_fd)545 virtual StatusTuple remove_value(const int& sock_fd) {
546 if (!this->remove(const_cast<int*>(&sock_fd)))
547 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
548 return StatusTuple::OK();
549 }
550 };
551
552 template <class ValueType>
553 class BPFInodeStorageTable : public BPFTableBase<int, ValueType> {
554 public:
BPFInodeStorageTable(const TableDesc & desc)555 BPFInodeStorageTable(const TableDesc& desc) : BPFTableBase<int, ValueType>(desc) {
556 if (desc.type != BPF_MAP_TYPE_INODE_STORAGE)
557 throw std::invalid_argument("Table '" + desc.name +
558 "' is not a inode_storage table");
559 }
560
get_value(const int & fd,ValueType & value)561 virtual StatusTuple get_value(const int& fd, ValueType& value) {
562 if (!this->lookup(const_cast<int*>(&fd), get_value_addr(value)))
563 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
564 return StatusTuple::OK();
565 }
566
update_value(const int & fd,const ValueType & value)567 virtual StatusTuple update_value(const int& fd, const ValueType& value) {
568 if (!this->update(const_cast<int*>(&fd),
569 get_value_addr(const_cast<ValueType&>(value))))
570 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
571 return StatusTuple::OK();
572 }
573
remove_value(const int & fd)574 virtual StatusTuple remove_value(const int& fd) {
575 if (!this->remove(const_cast<int*>(&fd)))
576 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
577 return StatusTuple::OK();
578 }
579 };
580
581 template <class ValueType>
582 class BPFTaskStorageTable : public BPFTableBase<int, ValueType> {
583 public:
BPFTaskStorageTable(const TableDesc & desc)584 BPFTaskStorageTable(const TableDesc& desc) : BPFTableBase<int, ValueType>(desc) {
585 if (desc.type != BPF_MAP_TYPE_TASK_STORAGE)
586 throw std::invalid_argument("Table '" + desc.name +
587 "' is not a task_storage table");
588 }
589
get_value(const int & fd,ValueType & value)590 virtual StatusTuple get_value(const int& fd, ValueType& value) {
591 if (!this->lookup(const_cast<int*>(&fd), get_value_addr(value)))
592 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
593 return StatusTuple::OK();
594 }
595
update_value(const int & fd,const ValueType & value)596 virtual StatusTuple update_value(const int& fd, const ValueType& value) {
597 if (!this->update(const_cast<int*>(&fd),
598 get_value_addr(const_cast<ValueType&>(value))))
599 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
600 return StatusTuple::OK();
601 }
602
remove_value(const int & fd)603 virtual StatusTuple remove_value(const int& fd) {
604 if (!this->remove(const_cast<int*>(&fd)))
605 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
606 return StatusTuple::OK();
607 }
608 };
609
610 template <class ValueType>
611 class BPFCgStorageTable : public BPFTableBase<int, ValueType> {
612 public:
BPFCgStorageTable(const TableDesc & desc)613 BPFCgStorageTable(const TableDesc& desc) : BPFTableBase<int, ValueType>(desc) {
614 if (desc.type != BPF_MAP_TYPE_CGROUP_STORAGE)
615 throw std::invalid_argument("Table '" + desc.name +
616 "' is not a cgroup_storage table");
617 }
618
get_value(struct bpf_cgroup_storage_key & key,ValueType & value)619 virtual StatusTuple get_value(struct bpf_cgroup_storage_key& key,
620 ValueType& value) {
621 if (!this->lookup(const_cast<struct bpf_cgroup_storage_key*>(&key),
622 get_value_addr(value)))
623 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
624 return StatusTuple::OK();
625 }
626
update_value(struct bpf_cgroup_storage_key & key,const ValueType & value)627 virtual StatusTuple update_value(struct bpf_cgroup_storage_key& key, const ValueType& value) {
628 if (!this->update(const_cast<struct bpf_cgroup_storage_key*>(&key),
629 get_value_addr(const_cast<ValueType&>(value))))
630 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
631 return StatusTuple::OK();
632 }
633 };
634
635 template <class ValueType>
636 class BPFPercpuCgStorageTable : public BPFTableBase<int, std::vector<ValueType>> {
637 public:
BPFPercpuCgStorageTable(const TableDesc & desc)638 BPFPercpuCgStorageTable(const TableDesc& desc)
639 : BPFTableBase<int, std::vector<ValueType>>(desc) {
640 if (desc.type != BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
641 throw std::invalid_argument("Table '" + desc.name +
642 "' is not a percpu_cgroup_storage table");
643 if (sizeof(ValueType) % 8)
644 throw std::invalid_argument("leaf must be aligned to 8 bytes");
645 ncpus = BPFTable::get_possible_cpu_count();
646 }
647
get_value(struct bpf_cgroup_storage_key & key,std::vector<ValueType> & value)648 virtual StatusTuple get_value(struct bpf_cgroup_storage_key& key,
649 std::vector<ValueType>& value) {
650 value.resize(ncpus);
651 if (!this->lookup(const_cast<struct bpf_cgroup_storage_key*>(&key),
652 get_value_addr(value)))
653 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
654 return StatusTuple::OK();
655 }
656
update_value(struct bpf_cgroup_storage_key & key,std::vector<ValueType> & value)657 virtual StatusTuple update_value(struct bpf_cgroup_storage_key& key,
658 std::vector<ValueType>& value) {
659 value.resize(ncpus);
660 if (!this->update(const_cast<struct bpf_cgroup_storage_key*>(&key),
661 get_value_addr(const_cast<std::vector<ValueType>&>(value))))
662 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
663 return StatusTuple::OK();
664 }
665 private:
666 unsigned int ncpus;
667 };
668
669 } // namespace ebpf
670