bcc: support BPF_MAP_TYPE_{INODE, TASK}_STORAGE maps
authorHengqi Chen <chenhengqi@outlook.com>
Tue, 4 Jan 2022 16:00:39 +0000 (00:00 +0800)
committeryonghong-song <ys114321@gmail.com>
Wed, 5 Jan 2022 06:43:40 +0000 (22:43 -0800)
Add support for BPF_MAP_TYPE_{INODE, TASK}_STORAGE in BCC.
Like sk local storage, this commit allows creating inode/task
local storage using BPF_{INODE, TASK}_STORAGE macros, and
manipulating maps using map.{inode, task}_storage_get() and
map.{inode, task}_storage_delete() helpers.

Signed-off-by: Hengqi Chen <chenhengqi@outlook.com>
src/cc/api/BPF.h
src/cc/api/BPFTable.h
src/cc/export/helpers.h
src/cc/frontends/clang/b_frontend_action.cc
src/python/bcc/table.py

index c266828e52040fe5cbe3e3b6723dee959b36ad7c..2d401ff7453b87cd778a0aebc719e694938dab7d 100644 (file)
@@ -161,6 +161,22 @@ class BPF {
     return BPFSkStorageTable<ValueType>({});
   }
 
+  template <class ValueType>
+  BPFInodeStorageTable<ValueType> get_inode_storage_table(const std::string& name) {
+    TableStorage::iterator it;
+    if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
+      return BPFInodeStorageTable<ValueType>(it->second);
+    return BPFInodeStorageTable<ValueType>({});
+  }
+
+  template <class ValueType>
+  BPFTaskStorageTable<ValueType> get_task_storage_table(const std::string& name) {
+    TableStorage::iterator it;
+    if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
+      return BPFTaskStorageTable<ValueType>(it->second);
+    return BPFTaskStorageTable<ValueType>({});
+  }
+
   template <class ValueType>
   BPFCgStorageTable<ValueType> get_cg_storage_table(const std::string& name) {
     TableStorage::iterator it;
index ca04cd1f325fba2d3ede2484b446ce8a988e7d30..4b902dcbde5eec68cec5e77c56e6e0ec353c21d6 100644 (file)
@@ -546,6 +546,64 @@ class BPFSkStorageTable : public BPFTableBase<int, ValueType> {
   }
 };
 
+template <class ValueType>
+class BPFInodeStorageTable : public BPFTableBase<int, ValueType> {
+ public:
+  BPFInodeStorageTable(const TableDesc& desc) : BPFTableBase<int, ValueType>(desc) {
+    if (desc.type != BPF_MAP_TYPE_INODE_STORAGE)
+      throw std::invalid_argument("Table '" + desc.name +
+                                  "' is not a inode_storage table");
+  }
+
+  virtual StatusTuple get_value(const int& fd, ValueType& value) {
+    if (!this->lookup(const_cast<int*>(&fd), get_value_addr(value)))
+      return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
+    return StatusTuple::OK();
+  }
+
+  virtual StatusTuple update_value(const int& fd, const ValueType& value) {
+    if (!this->update(const_cast<int*>(&fd),
+                      get_value_addr(const_cast<ValueType&>(value))))
+      return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
+    return StatusTuple::OK();
+  }
+
+  virtual StatusTuple remove_value(const int& fd) {
+    if (!this->remove(const_cast<int*>(&fd)))
+      return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
+    return StatusTuple::OK();
+  }
+};
+
+template <class ValueType>
+class BPFTaskStorageTable : public BPFTableBase<int, ValueType> {
+ public:
+  BPFTaskStorageTable(const TableDesc& desc) : BPFTableBase<int, ValueType>(desc) {
+    if (desc.type != BPF_MAP_TYPE_TASK_STORAGE)
+      throw std::invalid_argument("Table '" + desc.name +
+                                  "' is not a task_storage table");
+  }
+
+  virtual StatusTuple get_value(const int& fd, ValueType& value) {
+    if (!this->lookup(const_cast<int*>(&fd), get_value_addr(value)))
+      return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
+    return StatusTuple::OK();
+  }
+
+  virtual StatusTuple update_value(const int& fd, const ValueType& value) {
+    if (!this->update(const_cast<int*>(&fd),
+                      get_value_addr(const_cast<ValueType&>(value))))
+      return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
+    return StatusTuple::OK();
+  }
+
+  virtual StatusTuple remove_value(const int& fd) {
+    if (!this->remove(const_cast<int*>(&fd)))
+      return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
+    return StatusTuple::OK();
+  }
+};
+
 template <class ValueType>
 class BPFCgStorageTable : public BPFTableBase<int, ValueType> {
  public:
index 91c2d35f8a9b1b09df12ee710587a1fbc7d91444..c1253e29a153d92255016a6c2e0c93fd93a8e295 100644 (file)
@@ -414,6 +414,30 @@ __attribute__((section("maps/sk_storage"))) \
 struct _name##_table_t _name = { .flags = BPF_F_NO_PREALLOC }; \
 BPF_ANNOTATE_KV_PAIR(_name, int, _leaf_type)
 
+#define BPF_INODE_STORAGE(_name, _leaf_type) \
+struct _name##_table_t { \
+  int key; \
+  _leaf_type leaf; \
+  void * (*inode_storage_get) (void *, void *, int); \
+  int (*inode_storage_delete) (void *); \
+  u32 flags; \
+}; \
+__attribute__((section("maps/inode_storage"))) \
+struct _name##_table_t _name = { .flags = BPF_F_NO_PREALLOC }; \
+BPF_ANNOTATE_KV_PAIR(_name, int, _leaf_type)
+
+#define BPF_TASK_STORAGE(_name, _leaf_type) \
+struct _name##_table_t { \
+  int key; \
+  _leaf_type leaf; \
+  void * (*task_storage_get) (void *, void *, int); \
+  int (*task_storage_delete) (void *); \
+  u32 flags; \
+}; \
+__attribute__((section("maps/task_storage"))) \
+struct _name##_table_t _name = { .flags = BPF_F_NO_PREALLOC }; \
+BPF_ANNOTATE_KV_PAIR(_name, int, _leaf_type)
+
 #define BPF_SOCKMAP_COMMON(_name, _max_entries, _kind, _helper_name) \
 struct _name##_table_t { \
   u32 key; \
index 9a6e510ed88513cd9773b4b9509d3f8c64e65325..7bfc4ed799173cb0112cbb8bf897dfc148dcf435 100644 (file)
@@ -1081,6 +1081,18 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
           } else if (memb_name == "sk_storage_delete") {
             prefix = "bpf_sk_storage_delete";
             suffix = ")";
+          } else if (memb_name == "inode_storage_get") {
+            prefix = "bpf_inode_storage_get";
+            suffix = ")";
+          } else if (memb_name == "inode_storage_delete") {
+            prefix = "bpf_inode_storage_delete";
+            suffix = ")";
+          } else if (memb_name == "task_storage_get") {
+            prefix = "bpf_task_storage_get";
+            suffix = ")";
+          } else if (memb_name == "task_storage_delete") {
+            prefix = "bpf_task_storage_delete";
+            suffix = ")";
           } else if (memb_name == "get_local_storage") {
             prefix = "bpf_get_local_storage";
             suffix = ")";
@@ -1510,6 +1522,10 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
       map_type = BPF_MAP_TYPE_ARRAY_OF_MAPS;
     } else if (section_attr == "maps/sk_storage") {
       map_type = BPF_MAP_TYPE_SK_STORAGE;
+    } else if (section_attr == "maps/inode_storage") {
+      map_type = BPF_MAP_TYPE_INODE_STORAGE;
+    } else if (section_attr == "maps/task_storage") {
+      map_type = BPF_MAP_TYPE_TASK_STORAGE;
     } else if (section_attr == "maps/sockmap") {
       map_type = BPF_MAP_TYPE_SOCKMAP;
     } else if (section_attr == "maps/sockhash") {
index 1ff24114c35050dc6eae2b95b524242afcc1b849..f3a0ba474e62e9a7f5451b23ef9e476fb9ebecf5 100644 (file)
@@ -56,34 +56,40 @@ BPF_MAP_TYPE_SK_STORAGE = 24
 BPF_MAP_TYPE_DEVMAP_HASH = 25
 BPF_MAP_TYPE_STRUCT_OPS = 26
 BPF_MAP_TYPE_RINGBUF = 27
-
-map_type_name = {BPF_MAP_TYPE_HASH: "HASH",
-                 BPF_MAP_TYPE_ARRAY: "ARRAY",
-                 BPF_MAP_TYPE_PROG_ARRAY: "PROG_ARRAY",
-                 BPF_MAP_TYPE_PERF_EVENT_ARRAY: "PERF_EVENT_ARRAY",
-                 BPF_MAP_TYPE_PERCPU_HASH: "PERCPU_HASH",
-                 BPF_MAP_TYPE_PERCPU_ARRAY: "PERCPU_ARRAY",
-                 BPF_MAP_TYPE_STACK_TRACE: "STACK_TRACE",
-                 BPF_MAP_TYPE_CGROUP_ARRAY: "CGROUP_ARRAY",
-                 BPF_MAP_TYPE_LRU_HASH: "LRU_HASH",
-                 BPF_MAP_TYPE_LRU_PERCPU_HASH: "LRU_PERCPU_HASH",
-                 BPF_MAP_TYPE_LPM_TRIE: "LPM_TRIE",
-                 BPF_MAP_TYPE_ARRAY_OF_MAPS: "ARRAY_OF_MAPS",
-                 BPF_MAP_TYPE_HASH_OF_MAPS: "HASH_OF_MAPS",
-                 BPF_MAP_TYPE_DEVMAP: "DEVMAP",
-                 BPF_MAP_TYPE_SOCKMAP: "SOCKMAP",
-                 BPF_MAP_TYPE_CPUMAP: "CPUMAP",
-                 BPF_MAP_TYPE_XSKMAP: "XSKMAP",
-                 BPF_MAP_TYPE_SOCKHASH: "SOCKHASH",
-                 BPF_MAP_TYPE_CGROUP_STORAGE: "CGROUP_STORAGE",
-                 BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: "REUSEPORT_SOCKARRAY",
-                 BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: "PERCPU_CGROUP_STORAGE",
-                 BPF_MAP_TYPE_QUEUE: "QUEUE",
-                 BPF_MAP_TYPE_STACK: "STACK",
-                 BPF_MAP_TYPE_SK_STORAGE: "SK_STORAGE",
-                 BPF_MAP_TYPE_DEVMAP_HASH: "DEVMAP_HASH",
-                 BPF_MAP_TYPE_STRUCT_OPS: "STRUCT_OPS",
-                 BPF_MAP_TYPE_RINGBUF: "RINGBUF",}
+BPF_MAP_TYPE_INODE_STORAGE = 28
+BPF_MAP_TYPE_TASK_STORAGE = 29
+
+map_type_name = {
+    BPF_MAP_TYPE_HASH: "HASH",
+    BPF_MAP_TYPE_ARRAY: "ARRAY",
+    BPF_MAP_TYPE_PROG_ARRAY: "PROG_ARRAY",
+    BPF_MAP_TYPE_PERF_EVENT_ARRAY: "PERF_EVENT_ARRAY",
+    BPF_MAP_TYPE_PERCPU_HASH: "PERCPU_HASH",
+    BPF_MAP_TYPE_PERCPU_ARRAY: "PERCPU_ARRAY",
+    BPF_MAP_TYPE_STACK_TRACE: "STACK_TRACE",
+    BPF_MAP_TYPE_CGROUP_ARRAY: "CGROUP_ARRAY",
+    BPF_MAP_TYPE_LRU_HASH: "LRU_HASH",
+    BPF_MAP_TYPE_LRU_PERCPU_HASH: "LRU_PERCPU_HASH",
+    BPF_MAP_TYPE_LPM_TRIE: "LPM_TRIE",
+    BPF_MAP_TYPE_ARRAY_OF_MAPS: "ARRAY_OF_MAPS",
+    BPF_MAP_TYPE_HASH_OF_MAPS: "HASH_OF_MAPS",
+    BPF_MAP_TYPE_DEVMAP: "DEVMAP",
+    BPF_MAP_TYPE_SOCKMAP: "SOCKMAP",
+    BPF_MAP_TYPE_CPUMAP: "CPUMAP",
+    BPF_MAP_TYPE_XSKMAP: "XSKMAP",
+    BPF_MAP_TYPE_SOCKHASH: "SOCKHASH",
+    BPF_MAP_TYPE_CGROUP_STORAGE: "CGROUP_STORAGE",
+    BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: "REUSEPORT_SOCKARRAY",
+    BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: "PERCPU_CGROUP_STORAGE",
+    BPF_MAP_TYPE_QUEUE: "QUEUE",
+    BPF_MAP_TYPE_STACK: "STACK",
+    BPF_MAP_TYPE_SK_STORAGE: "SK_STORAGE",
+    BPF_MAP_TYPE_DEVMAP_HASH: "DEVMAP_HASH",
+    BPF_MAP_TYPE_STRUCT_OPS: "STRUCT_OPS",
+    BPF_MAP_TYPE_RINGBUF: "RINGBUF",
+    BPF_MAP_TYPE_INODE_STORAGE: "INODE_STORAGE",
+    BPF_MAP_TYPE_TASK_STORAGE: "TASK_STORAGE",
+}
 
 stars_max = 40
 log2_index_max = 65
@@ -202,30 +208,32 @@ def get_table_type_name(ttype):
 
 
 def _get_event_class(event_map):
-    ct_mapping = { 'char'              : ct.c_char,
-                   's8'                : ct.c_char,
-                   'unsigned char'     : ct.c_ubyte,
-                   'u8'                : ct.c_ubyte,
-                   'u8 *'              : ct.c_char_p,
-                   'char *'            : ct.c_char_p,
-                   'short'             : ct.c_short,
-                   's16'               : ct.c_short,
-                   'unsigned short'    : ct.c_ushort,
-                   'u16'               : ct.c_ushort,
-                   'int'               : ct.c_int,
-                   's32'               : ct.c_int,
-                   'enum'              : ct.c_int,
-                   'unsigned int'      : ct.c_uint,
-                   'u32'               : ct.c_uint,
-                   'long'              : ct.c_long,
-                   'unsigned long'     : ct.c_ulong,
-                   'long long'         : ct.c_longlong,
-                   's64'               : ct.c_longlong,
-                   'unsigned long long': ct.c_ulonglong,
-                   'u64'               : ct.c_ulonglong,
-                   '__int128'          : (ct.c_longlong * 2),
-                   'unsigned __int128' : (ct.c_ulonglong * 2),
-                   'void *'            : ct.c_void_p }
+    ct_mapping = {
+        'char'              : ct.c_char,
+        's8'                : ct.c_char,
+        'unsigned char'     : ct.c_ubyte,
+        'u8'                : ct.c_ubyte,
+        'u8 *'              : ct.c_char_p,
+        'char *'            : ct.c_char_p,
+        'short'             : ct.c_short,
+        's16'               : ct.c_short,
+        'unsigned short'    : ct.c_ushort,
+        'u16'               : ct.c_ushort,
+        'int'               : ct.c_int,
+        's32'               : ct.c_int,
+        'enum'              : ct.c_int,
+        'unsigned int'      : ct.c_uint,
+        'u32'               : ct.c_uint,
+        'long'              : ct.c_long,
+        'unsigned long'     : ct.c_ulong,
+        'long long'         : ct.c_longlong,
+        's64'               : ct.c_longlong,
+        'unsigned long long': ct.c_ulonglong,
+        'u64'               : ct.c_ulonglong,
+        '__int128'          : (ct.c_longlong * 2),
+        'unsigned __int128' : (ct.c_ulonglong * 2),
+        'void *'            : ct.c_void_p,
+    }
 
     # handle array types e.g. "int [16]" or "char[16]"
     array_type = re.compile(r"([^ ]+) ?\[([0-9]+)\]$")