cc: add BPFTable::get_offline_table (#1978)
authorMauricio Vásquez <mauriciovasquezbernal@gmail.com>
Fri, 21 Sep 2018 15:59:24 +0000 (10:59 -0500)
committeryonghong-song <ys114321@gmail.com>
Fri, 21 Sep 2018 15:59:24 +0000 (08:59 -0700)
get_offline_table is missing in the BPFTable class.

Add it and some test cases.

Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
src/cc/api/BPFTable.cc
src/cc/api/BPFTable.h
tests/cc/test_bpf_table.cc

index 5a3d77e..64fe77c 100644 (file)
@@ -180,6 +180,72 @@ StatusTuple BPFTable::clear_table_non_atomic() {
   return StatusTuple(0);
 }
 
+StatusTuple BPFTable::get_table_offline(
+  std::vector<std::pair<std::string, std::string>> &res) {
+  StatusTuple r(0);
+  int err;
+
+  auto key = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.key_size),
+                                                      ::free);
+  auto value = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.leaf_size),
+                                                      ::free);
+  std::string key_str;
+  std::string value_str;
+
+  if (desc.type == BPF_MAP_TYPE_ARRAY ||
+      desc.type == BPF_MAP_TYPE_PROG_ARRAY ||
+      desc.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
+      desc.type == BPF_MAP_TYPE_PERCPU_ARRAY ||
+      desc.type == BPF_MAP_TYPE_CGROUP_ARRAY ||
+      desc.type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
+      desc.type == BPF_MAP_TYPE_DEVMAP ||
+      desc.type == BPF_MAP_TYPE_CPUMAP ||
+      desc.type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
+    // For arrays, just iterate over all indices
+    for (size_t i = 0; i < desc.max_entries; i++) {
+      err = bpf_lookup_elem(desc.fd, &i, value.get());
+      if (err < 0 && errno == ENOENT) {
+        // Element is not present, skip it
+        continue;
+      } else if (err < 0) {
+        // Other error, abort
+        return StatusTuple(-1, "Error looking up value: %s", std::strerror(errno));
+      }
+
+      r = key_to_string(&i, key_str);
+      if (r.code() != 0)
+        return r;
+
+      r = leaf_to_string(value.get(), value_str);
+      if (r.code() != 0)
+        return r;
+      res.emplace_back(key_str, value_str);
+    }
+  } else {
+    res.clear();
+    // For other maps, try to use the first() and next() interfaces
+    if (!this->first(key.get()))
+      return StatusTuple(0);
+
+    while (true) {
+      if (!this->lookup(key.get(), value.get()))
+        break;
+      r = key_to_string(key.get(), key_str);
+      if (r.code() != 0)
+        return r;
+
+      r = leaf_to_string(value.get(), value_str);
+      if (r.code() != 0)
+        return r;
+      res.emplace_back(key_str, value_str);
+      if (!this->next(key.get(), key.get()))
+        break;
+    }
+  }
+
+  return StatusTuple(0);
+}
+
 size_t BPFTable::get_possible_cpu_count() { return get_possible_cpus().size(); }
 
 BPFStackTable::BPFStackTable(const TableDesc& desc, bool use_debug_file,
index ad3651b..3a183f4 100644 (file)
@@ -104,6 +104,7 @@ class BPFTable : public BPFTableBase<void, void> {
   StatusTuple remove_value(const std::string& key_str);
 
   StatusTuple clear_table_non_atomic();
+  StatusTuple get_table_offline(std::vector<std::pair<std::string, std::string>> &res);
 
   static size_t get_possible_cpu_count();
 };
index 55e8a91..40ee0af 100644 (file)
@@ -28,6 +28,7 @@ TEST_CASE("test bpf table", "[bpf_table]") {
 
   ebpf::BPF *bpf(new ebpf::BPF);
   ebpf::StatusTuple res(0);
+  std::vector<std::pair<std::string, std::string>> elements;
   res = bpf->init(BPF_PROGRAM);
   REQUIRE(res.code() == 0);
 
@@ -37,7 +38,7 @@ TEST_CASE("test bpf table", "[bpf_table]") {
   std::string value;
   res = t.update_value("0x07", "0x42");
   REQUIRE(res.code() == 0);
-  res = t.get_value("0x07", value);
+  res = t.get_value("0x7", value);
   REQUIRE(res.code() == 0);
   REQUIRE(value == "0x42");
 
@@ -54,14 +55,27 @@ TEST_CASE("test bpf table", "[bpf_table]") {
   res = t.get_value("0x11", value);
   REQUIRE(res.code() != 0);
 
-  // clear table
   res = t.update_value("0x15", "0x888");
   REQUIRE(res.code() == 0);
-  auto elements = bpf->get_hash_table<int, int>("myhash").get_table_offline();
+  res = t.get_table_offline(elements);
+  REQUIRE(res.code() == 0);
   REQUIRE(elements.size() == 2);
+
+  // check that elements match what is in the  table
+  for (auto &it : elements) {
+    if (it.first == "0x15") {
+      REQUIRE(it.second == "0x888");
+    } else if (it.first == "0x7") {
+      REQUIRE(it.second == "0x42");
+    } else {
+      FAIL("Element " + it.first + " should not be on the table", it.first);
+    }
+  }
+
   res = t.clear_table_non_atomic();
   REQUIRE(res.code() == 0);
-  elements = bpf->get_hash_table<int, int>("myhash").get_table_offline();
+  res = t.get_table_offline(elements);
+  REQUIRE(res.code() == 0);
   REQUIRE(elements.size() == 0);
 
   // delete bpf_module, call to key/leaf printf/scanf must fail