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 #include <fcntl.h>
18 #include <linux/elf.h>
19 #include <linux/perf_event.h>
20 #include <sys/epoll.h>
21 #include <unistd.h>
22 #include <cerrno>
23 #include <cinttypes>
24 #include <cstdint>
25 #include <cstring>
26 #include <iostream>
27 #include <memory>
28
29 #include "BPFTable.h"
30
31 #include "bcc_exception.h"
32 #include "bcc_syms.h"
33 #include "common.h"
34 #include "file_desc.h"
35 #include "libbpf.h"
36 #include "perf_reader.h"
37
38 namespace ebpf {
39
BPFTable(const TableDesc & desc)40 BPFTable::BPFTable(const TableDesc& desc) : BPFTableBase<void, void>(desc) {}
41
get_value(const std::string & key_str,std::string & value_str)42 StatusTuple BPFTable::get_value(const std::string& key_str,
43 std::string& value_str) {
44 char key[desc.key_size];
45 char value[desc.leaf_size];
46
47 StatusTuple r(0);
48
49 r = string_to_key(key_str, key);
50 if (!r.ok())
51 return r;
52
53 if (!lookup(key, value))
54 return StatusTuple(-1, "error getting value");
55
56 return leaf_to_string(value, value_str);
57 }
58
get_value(const std::string & key_str,std::vector<std::string> & value_str)59 StatusTuple BPFTable::get_value(const std::string& key_str,
60 std::vector<std::string>& value_str) {
61 size_t ncpus = get_possible_cpus().size();
62 char key[desc.key_size];
63 char value[desc.leaf_size * ncpus];
64
65 StatusTuple r(0);
66
67 r = string_to_key(key_str, key);
68 if (!r.ok())
69 return r;
70
71 if (!lookup(key, value))
72 return StatusTuple(-1, "error getting value");
73
74 value_str.resize(ncpus);
75
76 for (size_t i = 0; i < ncpus; i++) {
77 r = leaf_to_string(value + i * desc.leaf_size, value_str.at(i));
78 if (!r.ok())
79 return r;
80 }
81 return StatusTuple::OK();
82 }
83
update_value(const std::string & key_str,const std::string & value_str)84 StatusTuple BPFTable::update_value(const std::string& key_str,
85 const std::string& value_str) {
86 char key[desc.key_size];
87 char value[desc.leaf_size];
88
89 StatusTuple r(0);
90
91 r = string_to_key(key_str, key);
92 if (!r.ok())
93 return r;
94
95 r = string_to_leaf(value_str, value);
96 if (!r.ok())
97 return r;
98
99 if (!update(key, value))
100 return StatusTuple(-1, "error updating element");
101
102 return StatusTuple::OK();
103 }
104
update_value(const std::string & key_str,const std::vector<std::string> & value_str)105 StatusTuple BPFTable::update_value(const std::string& key_str,
106 const std::vector<std::string>& value_str) {
107 size_t ncpus = get_possible_cpus().size();
108 char key[desc.key_size];
109 char value[desc.leaf_size * ncpus];
110
111 StatusTuple r(0);
112
113 r = string_to_key(key_str, key);
114 if (!r.ok())
115 return r;
116
117 if (value_str.size() != ncpus)
118 return StatusTuple(-1, "bad value size");
119
120 for (size_t i = 0; i < ncpus; i++) {
121 r = string_to_leaf(value_str.at(i), value + i * desc.leaf_size);
122 if (!r.ok())
123 return r;
124 }
125
126 if (!update(key, value))
127 return StatusTuple(-1, "error updating element");
128
129 return StatusTuple::OK();
130 }
131
remove_value(const std::string & key_str)132 StatusTuple BPFTable::remove_value(const std::string& key_str) {
133 char key[desc.key_size];
134
135 StatusTuple r(0);
136
137 r = string_to_key(key_str, key);
138 if (!r.ok())
139 return r;
140
141 if (!remove(key))
142 return StatusTuple(-1, "error removing element");
143
144 return StatusTuple::OK();
145 }
146
clear_table_non_atomic()147 StatusTuple BPFTable::clear_table_non_atomic() {
148 if (desc.type == BPF_MAP_TYPE_HASH ||
149 desc.type == BPF_MAP_TYPE_LRU_HASH ||
150 desc.type == BPF_MAP_TYPE_PERCPU_HASH ||
151 desc.type == BPF_MAP_TYPE_HASH_OF_MAPS) {
152 // For hash maps, use the first() interface (which uses get_next_key) to
153 // iterate through the map and clear elements
154 auto key = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.key_size),
155 ::free);
156
157 while (this->first(key.get()))
158 if (!this->remove(key.get())) {
159 return StatusTuple(-1,
160 "Failed to delete element when clearing table %s",
161 desc.name.c_str());
162 }
163 } else if (desc.type == BPF_MAP_TYPE_ARRAY ||
164 desc.type == BPF_MAP_TYPE_PERCPU_ARRAY) {
165 return StatusTuple(-1, "Array map %s do not support clearing elements",
166 desc.name.c_str());
167 } else if (desc.type == BPF_MAP_TYPE_PROG_ARRAY ||
168 desc.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
169 desc.type == BPF_MAP_TYPE_STACK_TRACE ||
170 desc.type == BPF_MAP_TYPE_ARRAY_OF_MAPS) {
171 // For Stack-trace and FD arrays, just iterate over all indices
172 for (size_t i = 0; i < desc.max_entries; i++) {
173 this->remove(&i);
174 }
175 } else {
176 return StatusTuple(-1, "Clearing for map type of %s not supported yet",
177 desc.name.c_str());
178 }
179
180 return StatusTuple::OK();
181 }
182
get_table_offline(std::vector<std::pair<std::string,std::string>> & res)183 StatusTuple BPFTable::get_table_offline(
184 std::vector<std::pair<std::string, std::string>> &res) {
185 StatusTuple r(0);
186 int err;
187
188 auto key = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.key_size),
189 ::free);
190 auto value = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.leaf_size),
191 ::free);
192 std::string key_str;
193 std::string value_str;
194
195 if (desc.type == BPF_MAP_TYPE_ARRAY ||
196 desc.type == BPF_MAP_TYPE_PROG_ARRAY ||
197 desc.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
198 desc.type == BPF_MAP_TYPE_PERCPU_ARRAY ||
199 desc.type == BPF_MAP_TYPE_CGROUP_ARRAY ||
200 desc.type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
201 desc.type == BPF_MAP_TYPE_DEVMAP ||
202 desc.type == BPF_MAP_TYPE_CPUMAP ||
203 desc.type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
204 // For arrays, just iterate over all indices
205 for (size_t i = 0; i < desc.max_entries; i++) {
206 err = bpf_lookup_elem(desc.fd, &i, value.get());
207 if (err < 0 && errno == ENOENT) {
208 // Element is not present, skip it
209 continue;
210 } else if (err < 0) {
211 // Other error, abort
212 return StatusTuple(-1, "Error looking up value: %s", std::strerror(errno));
213 }
214
215 r = key_to_string(&i, key_str);
216 if (!r.ok())
217 return r;
218
219 r = leaf_to_string(value.get(), value_str);
220 if (!r.ok())
221 return r;
222 res.emplace_back(key_str, value_str);
223 }
224 } else {
225 res.clear();
226 // For other maps, try to use the first() and next() interfaces
227 if (!this->first(key.get()))
228 return StatusTuple::OK();
229
230 while (true) {
231 if (!this->lookup(key.get(), value.get()))
232 break;
233 r = key_to_string(key.get(), key_str);
234 if (!r.ok())
235 return r;
236
237 r = leaf_to_string(value.get(), value_str);
238 if (!r.ok())
239 return r;
240 res.emplace_back(key_str, value_str);
241 if (!this->next(key.get(), key.get()))
242 break;
243 }
244 }
245
246 return StatusTuple::OK();
247 }
248
get_possible_cpu_count()249 size_t BPFTable::get_possible_cpu_count() { return get_possible_cpus().size(); }
250
BPFStackTable(const TableDesc & desc,bool use_debug_file,bool check_debug_file_crc)251 BPFStackTable::BPFStackTable(const TableDesc& desc, bool use_debug_file,
252 bool check_debug_file_crc)
253 : BPFTableBase<int, stacktrace_t>(desc) {
254 if (desc.type != BPF_MAP_TYPE_STACK_TRACE)
255 throw std::invalid_argument("Table '" + desc.name +
256 "' is not a stack table");
257
258 uint32_t use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC);
259 symbol_option_ = {.use_debug_file = use_debug_file,
260 .check_debug_file_crc = check_debug_file_crc,
261 .lazy_symbolize = 1,
262 .use_symbol_type = use_symbol_type};
263 }
264
BPFStackTable(BPFStackTable && that)265 BPFStackTable::BPFStackTable(BPFStackTable&& that)
266 : BPFTableBase<int, stacktrace_t>(that.desc),
267 symbol_option_(std::move(that.symbol_option_)),
268 pid_sym_(std::move(that.pid_sym_)) {
269 that.pid_sym_.clear();
270 }
271
~BPFStackTable()272 BPFStackTable::~BPFStackTable() {
273 for (auto it : pid_sym_)
274 bcc_free_symcache(it.second, it.first);
275 }
276
free_symcache(int pid)277 void BPFStackTable::free_symcache(int pid) {
278 auto iter = pid_sym_.find(pid);
279 if (iter != pid_sym_.end()) {
280 bcc_free_symcache(iter->second, iter->first);
281 pid_sym_.erase(iter);
282 }
283 }
284
clear_table_non_atomic()285 void BPFStackTable::clear_table_non_atomic() {
286 for (int i = 0; size_t(i) < capacity(); i++) {
287 remove(&i);
288 }
289 }
290
get_stack_addr(int stack_id)291 std::vector<uintptr_t> BPFStackTable::get_stack_addr(int stack_id) {
292 std::vector<uintptr_t> res;
293 stacktrace_t stack;
294 if (stack_id < 0)
295 return res;
296 if (!lookup(&stack_id, &stack))
297 return res;
298 for (int i = 0; (i < BPF_MAX_STACK_DEPTH) && (stack.ip[i] != 0); i++)
299 res.push_back(stack.ip[i]);
300 return res;
301 }
302
get_stack_symbol(int stack_id,int pid)303 std::vector<std::string> BPFStackTable::get_stack_symbol(int stack_id,
304 int pid) {
305 auto addresses = get_stack_addr(stack_id);
306 std::vector<std::string> res;
307 if (addresses.empty())
308 return res;
309 res.reserve(addresses.size());
310
311 if (pid < 0)
312 pid = -1;
313 if (pid_sym_.find(pid) == pid_sym_.end())
314 pid_sym_[pid] = bcc_symcache_new(pid, &symbol_option_);
315 void* cache = pid_sym_[pid];
316
317 bcc_symbol symbol;
318 for (auto addr : addresses)
319 if (bcc_symcache_resolve(cache, addr, &symbol) != 0)
320 res.emplace_back("[UNKNOWN]");
321 else {
322 res.push_back(symbol.demangle_name);
323 bcc_symbol_free_demangle_name(&symbol);
324 }
325
326 return res;
327 }
328
BPFStackBuildIdTable(const TableDesc & desc,bool use_debug_file,bool check_debug_file_crc,void * bsymcache)329 BPFStackBuildIdTable::BPFStackBuildIdTable(const TableDesc& desc, bool use_debug_file,
330 bool check_debug_file_crc,
331 void *bsymcache)
332 : BPFTableBase<int, stacktrace_buildid_t>(desc),
333 bsymcache_(bsymcache) {
334 if (desc.type != BPF_MAP_TYPE_STACK_TRACE)
335 throw std::invalid_argument("Table '" + desc.name +
336 "' is not a stack table");
337
338 symbol_option_ = {.use_debug_file = use_debug_file,
339 .check_debug_file_crc = check_debug_file_crc,
340 .lazy_symbolize = 1,
341 .use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)};
342 }
343
clear_table_non_atomic()344 void BPFStackBuildIdTable::clear_table_non_atomic() {
345 for (int i = 0; size_t(i) < capacity(); i++) {
346 remove(&i);
347 }
348 }
349
get_stack_addr(int stack_id)350 std::vector<bpf_stack_build_id> BPFStackBuildIdTable::get_stack_addr(int stack_id) {
351 std::vector<bpf_stack_build_id> res;
352 struct stacktrace_buildid_t stack;
353 if (stack_id < 0)
354 return res;
355 if (!lookup(&stack_id, &stack))
356 return res;
357 for (int i = 0; (i < BPF_MAX_STACK_DEPTH) && \
358 (stack.trace[i].status == BPF_STACK_BUILD_ID_VALID);
359 i++) {
360 /* End of stack marker is BCC_STACK_BUILD_ID_EMPTY or
361 * BCC_STACK_BUILD_IP(fallback) mechanism.
362 * We do not support fallback mechanism
363 */
364 res.push_back(stack.trace[i]);
365 }
366 return res;
367 }
368
get_stack_symbol(int stack_id)369 std::vector<std::string> BPFStackBuildIdTable::get_stack_symbol(int stack_id)
370 {
371 auto addresses = get_stack_addr(stack_id);
372 std::vector<std::string> res;
373 if (addresses.empty())
374 return res;
375 res.reserve(addresses.size());
376
377 bcc_symbol symbol;
378 struct bpf_stack_build_id trace;
379 for (auto addr : addresses) {
380 memcpy(trace.build_id, addr.build_id, sizeof(trace.build_id));
381 trace.status = addr.status;
382 trace.offset = addr.offset;
383 if (bcc_buildsymcache_resolve(bsymcache_,&trace,&symbol) != 0) {
384 res.emplace_back("[UNKNOWN]");
385 } else {
386 res.push_back(symbol.name);
387 bcc_symbol_free_demangle_name(&symbol);
388 }
389 }
390 return res;
391 }
392
BPFPerfBuffer(const TableDesc & desc)393 BPFPerfBuffer::BPFPerfBuffer(const TableDesc& desc)
394 : BPFTableBase<int, int>(desc), epfd_(-1) {
395 if (desc.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
396 throw std::invalid_argument("Table '" + desc.name +
397 "' is not a perf buffer");
398 }
399
open_on_cpu(perf_reader_raw_cb cb,perf_reader_lost_cb lost_cb,void * cb_cookie,int page_cnt,struct bcc_perf_buffer_opts & opts)400 StatusTuple BPFPerfBuffer::open_on_cpu(perf_reader_raw_cb cb, perf_reader_lost_cb lost_cb,
401 void* cb_cookie, int page_cnt,
402 struct bcc_perf_buffer_opts& opts) {
403 if (cpu_readers_.find(opts.cpu) != cpu_readers_.end())
404 return StatusTuple(-1, "Perf buffer already open on CPU %d", opts.cpu);
405
406 auto reader = static_cast<perf_reader*>(
407 bpf_open_perf_buffer_opts(cb, lost_cb, cb_cookie, page_cnt, &opts));
408 if (reader == nullptr)
409 return StatusTuple(-1, "Unable to construct perf reader");
410
411 int reader_fd = perf_reader_fd(reader);
412 if (!update(&opts.cpu, &reader_fd)) {
413 perf_reader_free(static_cast<void*>(reader));
414 return StatusTuple(-1, "Unable to open perf buffer on CPU %d: %s", opts.cpu,
415 std::strerror(errno));
416 }
417
418 struct epoll_event event = {};
419 event.events = EPOLLIN;
420 event.data.ptr = static_cast<void*>(reader);
421 if (epoll_ctl(epfd_, EPOLL_CTL_ADD, reader_fd, &event) != 0) {
422 perf_reader_free(static_cast<void*>(reader));
423 return StatusTuple(-1, "Unable to add perf_reader FD to epoll: %s",
424 std::strerror(errno));
425 }
426
427 cpu_readers_[opts.cpu] = reader;
428 return StatusTuple::OK();
429 }
430
open_all_cpu(perf_reader_raw_cb cb,perf_reader_lost_cb lost_cb,void * cb_cookie,int page_cnt)431 StatusTuple BPFPerfBuffer::open_all_cpu(perf_reader_raw_cb cb,
432 perf_reader_lost_cb lost_cb,
433 void* cb_cookie, int page_cnt) {
434 return open_all_cpu(cb, lost_cb, cb_cookie, page_cnt, 1);
435 }
436
open_all_cpu(perf_reader_raw_cb cb,perf_reader_lost_cb lost_cb,void * cb_cookie,int page_cnt,int wakeup_events)437 StatusTuple BPFPerfBuffer::open_all_cpu(perf_reader_raw_cb cb,
438 perf_reader_lost_cb lost_cb,
439 void* cb_cookie, int page_cnt,
440 int wakeup_events)
441 {
442 if (cpu_readers_.size() != 0 || epfd_ != -1)
443 return StatusTuple(-1, "Previously opened perf buffer not cleaned");
444
445 std::vector<int> cpus = get_online_cpus();
446 ep_events_.reset(new epoll_event[cpus.size()]);
447 epfd_ = epoll_create1(EPOLL_CLOEXEC);
448
449 for (int i : cpus) {
450 struct bcc_perf_buffer_opts opts = {
451 .pid = -1,
452 .cpu = i,
453 .wakeup_events = wakeup_events,
454 };
455 auto res = open_on_cpu(cb, lost_cb, cb_cookie, page_cnt, opts);
456 if (!res.ok()) {
457 TRY2(close_all_cpu());
458 return res;
459 }
460 }
461 return StatusTuple::OK();
462 }
463
close_on_cpu(int cpu)464 StatusTuple BPFPerfBuffer::close_on_cpu(int cpu) {
465 auto it = cpu_readers_.find(cpu);
466 if (it == cpu_readers_.end())
467 return StatusTuple::OK();
468 perf_reader_free(static_cast<void*>(it->second));
469 if (!remove(const_cast<int*>(&(it->first))))
470 return StatusTuple(-1, "Unable to close perf buffer on CPU %d", it->first);
471 cpu_readers_.erase(it);
472 return StatusTuple::OK();
473 }
474
close_all_cpu()475 StatusTuple BPFPerfBuffer::close_all_cpu() {
476 std::string errors;
477 bool has_error = false;
478
479 if (epfd_ >= 0) {
480 int close_res = close(epfd_);
481 epfd_ = -1;
482 ep_events_.reset();
483 if (close_res != 0) {
484 has_error = true;
485 errors += std::string(std::strerror(errno)) + "\n";
486 }
487 }
488
489 std::vector<int> opened_cpus;
490 for (auto it : cpu_readers_)
491 opened_cpus.push_back(it.first);
492 for (int i : opened_cpus) {
493 auto res = close_on_cpu(i);
494 if (!res.ok()) {
495 errors += "Failed to close CPU" + std::to_string(i) + " perf buffer: ";
496 errors += res.msg() + "\n";
497 has_error = true;
498 }
499 }
500
501 if (has_error)
502 return StatusTuple(-1, errors);
503 return StatusTuple::OK();
504 }
505
poll(int timeout_ms)506 int BPFPerfBuffer::poll(int timeout_ms) {
507 if (epfd_ < 0)
508 return -1;
509 int cnt =
510 epoll_wait(epfd_, ep_events_.get(), cpu_readers_.size(), timeout_ms);
511 for (int i = 0; i < cnt; i++)
512 perf_reader_event_read(static_cast<perf_reader*>(ep_events_[i].data.ptr));
513 return cnt;
514 }
515
consume()516 int BPFPerfBuffer::consume() {
517 if (epfd_ < 0)
518 return -1;
519 for (auto it : cpu_readers_)
520 perf_reader_event_read(it.second);
521 return 0;
522 }
523
~BPFPerfBuffer()524 BPFPerfBuffer::~BPFPerfBuffer() {
525 auto res = close_all_cpu();
526 if (!res.ok())
527 std::cerr << "Failed to close all perf buffer on destruction: " << res.msg()
528 << std::endl;
529 }
530
BPFPerfEventArray(const TableDesc & desc)531 BPFPerfEventArray::BPFPerfEventArray(const TableDesc& desc)
532 : BPFTableBase<int, int>(desc) {
533 if (desc.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
534 throw std::invalid_argument("Table '" + desc.name +
535 "' is not a perf event array");
536 }
537
open_all_cpu(uint32_t type,uint64_t config,int pid)538 StatusTuple BPFPerfEventArray::open_all_cpu(uint32_t type, uint64_t config,
539 int pid) {
540 if (cpu_fds_.size() != 0)
541 return StatusTuple(-1, "Previously opened perf event not cleaned");
542
543 std::vector<int> cpus = get_online_cpus();
544
545 for (int i : cpus) {
546 auto res = open_on_cpu(i, type, config, pid);
547 if (!res.ok()) {
548 TRY2(close_all_cpu());
549 return res;
550 }
551 }
552 return StatusTuple::OK();
553 }
554
close_all_cpu()555 StatusTuple BPFPerfEventArray::close_all_cpu() {
556 std::string errors;
557 bool has_error = false;
558
559 std::vector<int> opened_cpus;
560 for (auto it : cpu_fds_)
561 opened_cpus.push_back(it.first);
562 for (int i : opened_cpus) {
563 auto res = close_on_cpu(i);
564 if (!res.ok()) {
565 errors += "Failed to close CPU" + std::to_string(i) + " perf event: ";
566 errors += res.msg() + "\n";
567 has_error = true;
568 }
569 }
570
571 if (has_error)
572 return StatusTuple(-1, errors);
573 return StatusTuple::OK();
574 }
575
open_on_cpu(int cpu,uint32_t type,uint64_t config,int pid)576 StatusTuple BPFPerfEventArray::open_on_cpu(int cpu, uint32_t type,
577 uint64_t config, int pid) {
578 if (cpu_fds_.find(cpu) != cpu_fds_.end())
579 return StatusTuple(-1, "Perf event already open on CPU %d", cpu);
580 int fd = bpf_open_perf_event(type, config, pid, cpu);
581 if (fd < 0) {
582 return StatusTuple(-1, "Error constructing perf event %" PRIu32 ":%" PRIu64,
583 type, config);
584 }
585 if (!update(&cpu, &fd)) {
586 bpf_close_perf_event_fd(fd);
587 return StatusTuple(-1, "Unable to open perf event on CPU %d: %s", cpu,
588 std::strerror(errno));
589 }
590 cpu_fds_[cpu] = fd;
591 return StatusTuple::OK();
592 }
593
close_on_cpu(int cpu)594 StatusTuple BPFPerfEventArray::close_on_cpu(int cpu) {
595 auto it = cpu_fds_.find(cpu);
596 if (it == cpu_fds_.end()) {
597 return StatusTuple::OK();
598 }
599 bpf_close_perf_event_fd(it->second);
600 cpu_fds_.erase(it);
601 return StatusTuple::OK();
602 }
603
~BPFPerfEventArray()604 BPFPerfEventArray::~BPFPerfEventArray() {
605 auto res = close_all_cpu();
606 if (!res.ok()) {
607 std::cerr << "Failed to close all perf buffer on destruction: " << res.msg()
608 << std::endl;
609 }
610 }
611
BPFProgTable(const TableDesc & desc)612 BPFProgTable::BPFProgTable(const TableDesc& desc)
613 : BPFTableBase<int, int>(desc) {
614 if (desc.type != BPF_MAP_TYPE_PROG_ARRAY)
615 throw std::invalid_argument("Table '" + desc.name +
616 "' is not a prog table");
617 }
618
update_value(const int & index,const int & prog_fd)619 StatusTuple BPFProgTable::update_value(const int& index, const int& prog_fd) {
620 if (!this->update(const_cast<int*>(&index), const_cast<int*>(&prog_fd)))
621 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
622 return StatusTuple::OK();
623 }
624
remove_value(const int & index)625 StatusTuple BPFProgTable::remove_value(const int& index) {
626 if (!this->remove(const_cast<int*>(&index)))
627 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
628 return StatusTuple::OK();
629 }
630
BPFCgroupArray(const TableDesc & desc)631 BPFCgroupArray::BPFCgroupArray(const TableDesc& desc)
632 : BPFTableBase<int, int>(desc) {
633 if (desc.type != BPF_MAP_TYPE_CGROUP_ARRAY)
634 throw std::invalid_argument("Table '" + desc.name +
635 "' is not a cgroup array");
636 }
637
update_value(const int & index,const int & cgroup2_fd)638 StatusTuple BPFCgroupArray::update_value(const int& index,
639 const int& cgroup2_fd) {
640 if (!this->update(const_cast<int*>(&index), const_cast<int*>(&cgroup2_fd)))
641 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
642 return StatusTuple::OK();
643 }
644
update_value(const int & index,const std::string & cgroup2_path)645 StatusTuple BPFCgroupArray::update_value(const int& index,
646 const std::string& cgroup2_path) {
647 FileDesc f(::open(cgroup2_path.c_str(), O_RDONLY | O_CLOEXEC));
648 if ((int)f < 0)
649 return StatusTuple(-1, "Unable to open %s", cgroup2_path.c_str());
650 TRY2(update_value(index, (int)f));
651 return StatusTuple::OK();
652 }
653
remove_value(const int & index)654 StatusTuple BPFCgroupArray::remove_value(const int& index) {
655 if (!this->remove(const_cast<int*>(&index)))
656 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
657 return StatusTuple::OK();
658 }
659
BPFDevmapTable(const TableDesc & desc)660 BPFDevmapTable::BPFDevmapTable(const TableDesc& desc)
661 : BPFTableBase<int, int>(desc) {
662 if(desc.type != BPF_MAP_TYPE_DEVMAP)
663 throw std::invalid_argument("Table '" + desc.name +
664 "' is not a devmap table");
665 }
666
update_value(const int & index,const int & value)667 StatusTuple BPFDevmapTable::update_value(const int& index,
668 const int& value) {
669 if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
670 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
671 return StatusTuple::OK();
672 }
673
get_value(const int & index,int & value)674 StatusTuple BPFDevmapTable::get_value(const int& index,
675 int& value) {
676 if (!this->lookup(const_cast<int*>(&index), &value))
677 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
678 return StatusTuple::OK();
679 }
680
remove_value(const int & index)681 StatusTuple BPFDevmapTable::remove_value(const int& index) {
682 if (!this->remove(const_cast<int*>(&index)))
683 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
684 return StatusTuple::OK();
685 }
686
BPFXskmapTable(const TableDesc & desc)687 BPFXskmapTable::BPFXskmapTable(const TableDesc& desc)
688 : BPFTableBase<int, int>(desc) {
689 if(desc.type != BPF_MAP_TYPE_XSKMAP)
690 throw std::invalid_argument("Table '" + desc.name +
691 "' is not a xskmap table");
692 }
693
update_value(const int & index,const int & value)694 StatusTuple BPFXskmapTable::update_value(const int& index,
695 const int& value) {
696 if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
697 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
698 return StatusTuple::OK();
699 }
700
get_value(const int & index,int & value)701 StatusTuple BPFXskmapTable::get_value(const int& index,
702 int& value) {
703 if (!this->lookup(const_cast<int*>(&index), &value))
704 return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
705 return StatusTuple::OK();
706 }
707
remove_value(const int & index)708 StatusTuple BPFXskmapTable::remove_value(const int& index) {
709 if (!this->remove(const_cast<int*>(&index)))
710 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
711 return StatusTuple::OK();
712 }
713
BPFSockmapTable(const TableDesc & desc)714 BPFSockmapTable::BPFSockmapTable(const TableDesc& desc)
715 : BPFTableBase<int, int>(desc) {
716 if(desc.type != BPF_MAP_TYPE_SOCKMAP)
717 throw std::invalid_argument("Table '" + desc.name +
718 "' is not a sockmap table");
719 }
720
update_value(const int & index,const int & value)721 StatusTuple BPFSockmapTable::update_value(const int& index,
722 const int& value) {
723 if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
724 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
725 return StatusTuple::OK();
726 }
727
remove_value(const int & index)728 StatusTuple BPFSockmapTable::remove_value(const int& index) {
729 if (!this->remove(const_cast<int*>(&index)))
730 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
731 return StatusTuple::OK();
732 }
733
BPFSockhashTable(const TableDesc & desc)734 BPFSockhashTable::BPFSockhashTable(const TableDesc& desc)
735 : BPFTableBase<int, int>(desc) {
736 if(desc.type != BPF_MAP_TYPE_SOCKHASH)
737 throw std::invalid_argument("Table '" + desc.name +
738 "' is not a sockhash table");
739 }
740
update_value(const int & key,const int & value)741 StatusTuple BPFSockhashTable::update_value(const int& key,
742 const int& value) {
743 if (!this->update(const_cast<int*>(&key), const_cast<int*>(&value)))
744 return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
745 return StatusTuple::OK();
746 }
747
remove_value(const int & key)748 StatusTuple BPFSockhashTable::remove_value(const int& key) {
749 if (!this->remove(const_cast<int*>(&key)))
750 return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
751 return StatusTuple::OK();
752 }
753
754 } // namespace ebpf
755