BPFTable.h 22 KB

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