• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)538 StatusTuple BPFPerfEventArray::open_all_cpu(uint32_t type, uint64_t config) {
539   if (cpu_fds_.size() != 0)
540     return StatusTuple(-1, "Previously opened perf event not cleaned");
541 
542   std::vector<int> cpus = get_online_cpus();
543 
544   for (int i : cpus) {
545     auto res = open_on_cpu(i, type, config);
546     if (!res.ok()) {
547       TRY2(close_all_cpu());
548       return res;
549     }
550   }
551   return StatusTuple::OK();
552 }
553 
close_all_cpu()554 StatusTuple BPFPerfEventArray::close_all_cpu() {
555   std::string errors;
556   bool has_error = false;
557 
558   std::vector<int> opened_cpus;
559   for (auto it : cpu_fds_)
560     opened_cpus.push_back(it.first);
561   for (int i : opened_cpus) {
562     auto res = close_on_cpu(i);
563     if (!res.ok()) {
564       errors += "Failed to close CPU" + std::to_string(i) + " perf event: ";
565       errors += res.msg() + "\n";
566       has_error = true;
567     }
568   }
569 
570   if (has_error)
571     return StatusTuple(-1, errors);
572   return StatusTuple::OK();
573 }
574 
open_on_cpu(int cpu,uint32_t type,uint64_t config)575 StatusTuple BPFPerfEventArray::open_on_cpu(int cpu, uint32_t type,
576                                            uint64_t config) {
577   if (cpu_fds_.find(cpu) != cpu_fds_.end())
578     return StatusTuple(-1, "Perf event already open on CPU %d", cpu);
579   int fd = bpf_open_perf_event(type, config, -1, cpu);
580   if (fd < 0) {
581     return StatusTuple(-1, "Error constructing perf event %" PRIu32 ":%" PRIu64,
582                        type, config);
583   }
584   if (!update(&cpu, &fd)) {
585     bpf_close_perf_event_fd(fd);
586     return StatusTuple(-1, "Unable to open perf event on CPU %d: %s", cpu,
587                        std::strerror(errno));
588   }
589   cpu_fds_[cpu] = fd;
590   return StatusTuple::OK();
591 }
592 
close_on_cpu(int cpu)593 StatusTuple BPFPerfEventArray::close_on_cpu(int cpu) {
594   auto it = cpu_fds_.find(cpu);
595   if (it == cpu_fds_.end()) {
596     return StatusTuple::OK();
597   }
598   bpf_close_perf_event_fd(it->second);
599   cpu_fds_.erase(it);
600   return StatusTuple::OK();
601 }
602 
~BPFPerfEventArray()603 BPFPerfEventArray::~BPFPerfEventArray() {
604   auto res = close_all_cpu();
605   if (!res.ok()) {
606     std::cerr << "Failed to close all perf buffer on destruction: " << res.msg()
607               << std::endl;
608   }
609 }
610 
BPFProgTable(const TableDesc & desc)611 BPFProgTable::BPFProgTable(const TableDesc& desc)
612     : BPFTableBase<int, int>(desc) {
613   if (desc.type != BPF_MAP_TYPE_PROG_ARRAY)
614     throw std::invalid_argument("Table '" + desc.name +
615                                 "' is not a prog table");
616 }
617 
update_value(const int & index,const int & prog_fd)618 StatusTuple BPFProgTable::update_value(const int& index, const int& prog_fd) {
619   if (!this->update(const_cast<int*>(&index), const_cast<int*>(&prog_fd)))
620     return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
621   return StatusTuple::OK();
622 }
623 
remove_value(const int & index)624 StatusTuple BPFProgTable::remove_value(const int& index) {
625   if (!this->remove(const_cast<int*>(&index)))
626     return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
627   return StatusTuple::OK();
628 }
629 
BPFCgroupArray(const TableDesc & desc)630 BPFCgroupArray::BPFCgroupArray(const TableDesc& desc)
631     : BPFTableBase<int, int>(desc) {
632   if (desc.type != BPF_MAP_TYPE_CGROUP_ARRAY)
633     throw std::invalid_argument("Table '" + desc.name +
634                                 "' is not a cgroup array");
635 }
636 
update_value(const int & index,const int & cgroup2_fd)637 StatusTuple BPFCgroupArray::update_value(const int& index,
638                                          const int& cgroup2_fd) {
639   if (!this->update(const_cast<int*>(&index), const_cast<int*>(&cgroup2_fd)))
640     return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
641   return StatusTuple::OK();
642 }
643 
update_value(const int & index,const std::string & cgroup2_path)644 StatusTuple BPFCgroupArray::update_value(const int& index,
645                                          const std::string& cgroup2_path) {
646   FileDesc f(::open(cgroup2_path.c_str(), O_RDONLY | O_CLOEXEC));
647   if ((int)f < 0)
648     return StatusTuple(-1, "Unable to open %s", cgroup2_path.c_str());
649   TRY2(update_value(index, (int)f));
650   return StatusTuple::OK();
651 }
652 
remove_value(const int & index)653 StatusTuple BPFCgroupArray::remove_value(const int& index) {
654   if (!this->remove(const_cast<int*>(&index)))
655     return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
656   return StatusTuple::OK();
657 }
658 
BPFDevmapTable(const TableDesc & desc)659 BPFDevmapTable::BPFDevmapTable(const TableDesc& desc)
660     : BPFTableBase<int, int>(desc) {
661     if(desc.type != BPF_MAP_TYPE_DEVMAP)
662       throw std::invalid_argument("Table '" + desc.name +
663                                   "' is not a devmap table");
664 }
665 
update_value(const int & index,const int & value)666 StatusTuple BPFDevmapTable::update_value(const int& index,
667                                          const int& value) {
668     if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
669       return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
670     return StatusTuple::OK();
671 }
672 
get_value(const int & index,int & value)673 StatusTuple BPFDevmapTable::get_value(const int& index,
674                                       int& value) {
675     if (!this->lookup(const_cast<int*>(&index), &value))
676       return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
677     return StatusTuple::OK();
678 }
679 
remove_value(const int & index)680 StatusTuple BPFDevmapTable::remove_value(const int& index) {
681     if (!this->remove(const_cast<int*>(&index)))
682       return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
683     return StatusTuple::OK();
684 }
685 
BPFXskmapTable(const TableDesc & desc)686 BPFXskmapTable::BPFXskmapTable(const TableDesc& desc)
687     : BPFTableBase<int, int>(desc) {
688     if(desc.type != BPF_MAP_TYPE_XSKMAP)
689       throw std::invalid_argument("Table '" + desc.name +
690                                   "' is not a xskmap table");
691 }
692 
update_value(const int & index,const int & value)693 StatusTuple BPFXskmapTable::update_value(const int& index,
694                                          const int& value) {
695     if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
696       return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
697     return StatusTuple::OK();
698 }
699 
get_value(const int & index,int & value)700 StatusTuple BPFXskmapTable::get_value(const int& index,
701                                       int& value) {
702     if (!this->lookup(const_cast<int*>(&index), &value))
703       return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
704     return StatusTuple::OK();
705 }
706 
remove_value(const int & index)707 StatusTuple BPFXskmapTable::remove_value(const int& index) {
708     if (!this->remove(const_cast<int*>(&index)))
709       return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
710     return StatusTuple::OK();
711 }
712 
BPFSockmapTable(const TableDesc & desc)713 BPFSockmapTable::BPFSockmapTable(const TableDesc& desc)
714     : BPFTableBase<int, int>(desc) {
715     if(desc.type != BPF_MAP_TYPE_SOCKMAP)
716       throw std::invalid_argument("Table '" + desc.name +
717                                   "' is not a sockmap table");
718 }
719 
update_value(const int & index,const int & value)720 StatusTuple BPFSockmapTable::update_value(const int& index,
721                                          const int& value) {
722     if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
723       return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
724     return StatusTuple::OK();
725 }
726 
remove_value(const int & index)727 StatusTuple BPFSockmapTable::remove_value(const int& index) {
728     if (!this->remove(const_cast<int*>(&index)))
729       return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
730     return StatusTuple::OK();
731 }
732 
BPFSockhashTable(const TableDesc & desc)733 BPFSockhashTable::BPFSockhashTable(const TableDesc& desc)
734     : BPFTableBase<int, int>(desc) {
735     if(desc.type != BPF_MAP_TYPE_SOCKHASH)
736       throw std::invalid_argument("Table '" + desc.name +
737                                   "' is not a sockhash table");
738 }
739 
update_value(const int & key,const int & value)740 StatusTuple BPFSockhashTable::update_value(const int& key,
741                                          const int& value) {
742     if (!this->update(const_cast<int*>(&key), const_cast<int*>(&value)))
743       return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
744     return StatusTuple::OK();
745 }
746 
remove_value(const int & key)747 StatusTuple BPFSockhashTable::remove_value(const int& key) {
748     if (!this->remove(const_cast<int*>(&key)))
749       return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
750     return StatusTuple::OK();
751 }
752 
753 }  // namespace ebpf
754