add support for bpf map flags
authorHuapeng Zhou <hzhou@fb.com>
Wed, 7 Dec 2016 02:10:38 +0000 (18:10 -0800)
committerHuapeng Zhou <hzhou@fb.com>
Thu, 8 Dec 2016 06:30:23 +0000 (22:30 -0800)
15 files changed:
src/cc/bpf_common.cc
src/cc/bpf_common.h
src/cc/bpf_module.cc
src/cc/bpf_module.h
src/cc/export/helpers.h
src/cc/frontends/b/codegen_llvm.cc
src/cc/frontends/clang/b_frontend_action.cc
src/cc/frontends/clang/loader.h
src/cc/libbpf.c
src/cc/libbpf.h
src/cc/table_desc.h
src/lua/bcc/libbcc.lua
src/python/bcc/libbcc.py
src/python/bcc/table.py
tests/python/test_flags.py [new file with mode: 0644]

index 15f5602..4a71197 100644 (file)
@@ -146,6 +146,18 @@ size_t bpf_table_max_entries_id(void *program, size_t id) {
   return mod->table_max_entries(id);
 }
 
+int bpf_table_flags(void *program, const char *table_name) {
+  auto mod = static_cast<ebpf::BPFModule *>(program);
+  if (!mod) return -1;
+  return mod->table_flags(table_name);
+}
+
+int bpf_table_flags_id(void *program, size_t id) {
+  auto mod = static_cast<ebpf::BPFModule *>(program);
+  if (!mod) return -1;
+  return mod->table_flags(id);
+}
+
 const char * bpf_table_name(void *program, size_t id) {
   auto mod = static_cast<ebpf::BPFModule *>(program);
   if (!mod) return nullptr;
index 2b3ea54..0abdbd4 100644 (file)
@@ -44,6 +44,8 @@ int bpf_table_type(void *program, const char *table_name);
 int bpf_table_type_id(void *program, size_t id);
 size_t bpf_table_max_entries(void *program, const char *table_name);
 size_t bpf_table_max_entries_id(void *program, size_t id);
+int bpf_table_flags(void *program, const char *table_name);
+int bpf_table_flags_id(void *program, size_t id);
 const char * bpf_table_name(void *program, size_t id);
 const char * bpf_table_key_desc(void *program, const char *table_name);
 const char * bpf_table_key_desc_id(void *program, size_t id);
index d9700b3..be0a524 100644 (file)
@@ -542,6 +542,15 @@ size_t BPFModule::table_max_entries(size_t id) const {
   return (*tables_)[id].max_entries;
 }
 
+int BPFModule::table_flags(const string &name) const {
+  return table_flags(table_id(name));
+}
+
+int BPFModule::table_flags(size_t id) const {
+  if (id >= tables_->size()) return -1;
+  return (*tables_)[id].flags;
+}
+
 const char * BPFModule::table_name(size_t id) const {
   if (id >= tables_->size()) return nullptr;
   return (*tables_)[id].name.c_str();
index 86fbdcf..aca8633 100644 (file)
@@ -72,6 +72,8 @@ class BPFModule {
   int table_type(size_t id) const;
   size_t table_max_entries(const std::string &name) const;
   size_t table_max_entries(size_t id) const;
+  int table_flags(const std::string &name) const;
+  int table_flags(size_t id) const;
   const char * table_key_desc(size_t id) const;
   const char * table_key_desc(const std::string &name) const;
   size_t table_key_size(size_t id) const;
index 6530dd3..c140851 100644 (file)
@@ -38,7 +38,7 @@ R"********(
 #define SEC(NAME) __attribute__((section(NAME), used))
 
 // Changes to the macro require changes in BFrontendAction classes
-#define BPF_TABLE(_table_type, _key_type, _leaf_type, _name, _max_entries) \
+#define BPF_F_TABLE(_table_type, _key_type, _leaf_type, _name, _max_entries, _flags) \
 struct _name##_table_t { \
   _key_type key; \
   _leaf_type leaf; \
@@ -50,9 +50,13 @@ struct _name##_table_t { \
   void (*increment) (_key_type); \
   int (*get_stackid) (void *, u64); \
   _leaf_type data[_max_entries]; \
+  int flags; \
 }; \
 __attribute__((section("maps/" _table_type))) \
-struct _name##_table_t _name
+struct _name##_table_t _name = { .flags = (_flags) }
+
+#define BPF_TABLE(_table_type, _key_type, _leaf_type, _name, _max_entries) \
+BPF_F_TABLE(_table_type, _key_type, _leaf_type, _name, _max_entries, 0);
 
 // define a table same as above but allow it to be referenced by other modules
 #define BPF_TABLE_PUBLIC(_table_type, _key_type, _leaf_type, _name, _max_entries) \
index 3b4f36b..410bfd6 100644 (file)
@@ -1100,7 +1100,7 @@ StatusTuple CodegenLLVM::visit_table_decl_stmt_node(TableDeclStmtNode *n) {
     decl_gvar->setSection("maps");
     tables_[n] = decl_gvar;
 
-    int map_fd = bpf_create_map(map_type, key->bit_width_ / 8, leaf->bit_width_ / 8, n->size_);
+    int map_fd = bpf_create_map(map_type, key->bit_width_ / 8, leaf->bit_width_ / 8, n->size_, 0);
     if (map_fd >= 0)
       table_fds_[n] = map_fd;
   } else {
@@ -1244,6 +1244,7 @@ StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) {
       table.first->key_type_->bit_width_ >> 3,
       table.first->leaf_type_->bit_width_ >> 3,
       table.first->size_,
+      0,
       "", "",
     });
   }
index 57d8454..9370386 100644 (file)
@@ -599,13 +599,6 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
     }
     const RecordDecl *RD = R->getDecl()->getDefinition();
 
-    int major = 0, minor = 0;
-    struct utsname un;
-    if (uname(&un) == 0) {
-      // release format: <major>.<minor>.<revision>[-<othertag>]
-      sscanf(un.release, "%d.%d.", &major, &minor);
-    }
-
     TableDesc table = {};
     table.name = Decl->getName();
 
@@ -630,9 +623,18 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
         visitor.TraverseType(F->getType());
       } else if (F->getName() == "data") {
         table.max_entries = sz / table.leaf_size;
+      } else if (F->getName() == "flags") {
+        unsigned idx = F->getFieldIndex();
+        if (auto I = dyn_cast_or_null<InitListExpr>(Decl->getInit())) {
+          llvm::APSInt res;
+          if (I->getInit(idx)->EvaluateAsInt(res, C)) {
+            table.flags = res.getExtValue();
+          }
+        }
       }
       ++i;
     }
+
     bool is_extern = false;
     bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
     if (A->getName() == "maps/hash") {
@@ -695,7 +697,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
       }
 
       table.type = map_type;
-      table.fd = bpf_create_map(map_type, table.key_size, table.leaf_size, table.max_entries);
+      table.fd = bpf_create_map(map_type, table.key_size, table.leaf_size, table.max_entries, table.flags);
     }
     if (table.fd < 0) {
       error(Decl->getLocStart(), "could not open bpf map: %0\nis %1 map type enabled in your kernel?") <<
index 67b9969..5e7c490 100644 (file)
@@ -30,11 +30,6 @@ namespace ebpf {
 
 struct TableDesc;
 
-namespace cc {
-class Parser;
-class CodegenLLVM;
-}
-
 class ClangLoader {
  public:
   explicit ClangLoader(llvm::LLVMContext *ctx, unsigned flags);
index 6df35d2..24967b9 100644 (file)
@@ -68,7 +68,7 @@ static __u64 ptr_to_u64(void *ptr)
   return (__u64) (unsigned long) ptr;
 }
 
-int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries)
+int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries, int map_flags)
 {
   union bpf_attr attr;
   memset(&attr, 0, sizeof(attr));
@@ -76,6 +76,7 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int
   attr.key_size = key_size;
   attr.value_size = value_size;
   attr.max_entries = max_entries;
+  attr.map_flags = map_flags;
 
   int ret = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
   if (ret < 0 && errno == EPERM) {
@@ -171,7 +172,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
   }
 
   ret = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
-   
+
   if (ret < 0 && errno == EPERM) {
     // When EPERM is returned, two reasons are possible:
     //  1. user has no permissions for bpf()
@@ -221,7 +222,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
 
     fprintf(stderr, "bpf: %s\n%s\n", strerror(errno), bpf_log_buffer);
 
-    free(bpf_log_buffer); 
+    free(bpf_log_buffer);
   }
   return ret;
 }
index f55fa33..cc4e0f3 100644 (file)
@@ -25,7 +25,7 @@ extern "C" {
 #endif
 
 int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
-                  int max_entries);
+                  int max_entries, int map_flags);
 int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
 int bpf_lookup_elem(int fd, void *key, void *value);
 int bpf_delete_elem(int fd, void *key);
index 2161c09..a5196e2 100644 (file)
@@ -32,6 +32,7 @@ struct TableDesc {
   size_t key_size;  // sizes are in bytes
   size_t leaf_size;
   size_t max_entries;
+  int flags;
   std::string key_desc;
   std::string leaf_desc;
   llvm::Function *key_sscanf;
index db356a8..2628445 100644 (file)
@@ -24,7 +24,7 @@ enum bpf_prog_type {
   BPF_PROG_TYPE_SCHED_ACT,
 };
 
-int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries);
+int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries, int map_flags);
 int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
 int bpf_lookup_elem(int fd, void *key, void *value);
 int bpf_delete_elem(int fd, void *key);
@@ -72,6 +72,8 @@ int bpf_table_type(void *program, const char *table_name);
 int bpf_table_type_id(void *program, size_t id);
 size_t bpf_table_max_entries(void *program, const char *table_name);
 size_t bpf_table_max_entries_id(void *program, size_t id);
+int bpf_table_flags(void *program, const char *table_name);
+int bpf_table_flags_id(void *program, size_t id);
 const char * bpf_table_name(void *program, size_t id);
 const char * bpf_table_key_desc(void *program, const char *table_name);
 const char * bpf_table_key_desc_id(void *program, size_t id);
index 04563c1..f03a1b7 100644 (file)
@@ -47,6 +47,8 @@ lib.bpf_table_type_id.restype = ct.c_int
 lib.bpf_table_type_id.argtypes = [ct.c_void_p, ct.c_ulonglong]
 lib.bpf_table_max_entries_id.restype = ct.c_ulonglong
 lib.bpf_table_max_entries_id.argtypes = [ct.c_void_p, ct.c_ulonglong]
+lib.bpf_table_flags_id.restype = ct.c_int
+lib.bpf_table_flags_id.argtypes = [ct.c_void_p, ct.c_ulonglong]
 lib.bpf_table_key_desc.restype = ct.c_char_p
 lib.bpf_table_key_desc.argtypes = [ct.c_void_p, ct.c_char_p]
 lib.bpf_table_leaf_desc.restype = ct.c_char_p
index 49bf2a2..516cfa1 100644 (file)
@@ -118,6 +118,7 @@ class TableBase(MutableMapping):
         self.Key = keytype
         self.Leaf = leaftype
         self.ttype = lib.bpf_table_type_id(self.bpf.module, self.map_id)
+        self.flags = lib.bpf_table_flags_id(self.bpf.module, self.map_id)
         self._cbs = {}
 
     def key_sprintf(self, key):
diff --git a/tests/python/test_flags.py b/tests/python/test_flags.py
new file mode 100644 (file)
index 0000000..a5d2b42
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# Copyright (c) PLUMgrid, Inc.
+# Licensed under the Apache License, Version 2.0 (the "License")
+
+import unittest
+from bcc import BPF
+
+class TestLru(unittest.TestCase):
+    def test_lru_map_flags(self):
+        test_prog1 = """
+        BPF_F_TABLE("lru_hash", int, u64, lru, 1024, BPF_F_NO_COMMON_LRU);
+        """
+        b = BPF(text=test_prog1)
+        t = b["lru"]
+        self.assertEqual(t.flags, 2);
+
+    def test_hash_map_flags(self):
+        test_prog1 = """
+        BPF_F_TABLE("hash", int, u64, hash, 1024, BPF_F_NO_PREALLOC);
+        """
+        b = BPF(text=test_prog1)
+        t = b["hash"]
+        self.assertEqual(t.flags, 1);
+
+if __name__ == "__main__":
+    unittest.main()