Skip to content

Commit

Permalink
feature: support create new map and pin it to bpffs as file(BPF_TABLE…
Browse files Browse the repository at this point in the history
…_PINNED) (iovisor#3382)

Support create a new map and pin it if the pinned file is not available.

Co-authored-by: chenyue.zhou <[email protected]>
  • Loading branch information
chenyuezhou and chenyuezhou committed Apr 30, 2021
1 parent 356ab6c commit b209161
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 36 deletions.
5 changes: 3 additions & 2 deletions docs/reference_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -871,8 +871,9 @@ Examples in situ:

#### Pinned Maps

Maps that were pinned to the BPF filesystem can be accessed through an extended syntax: ```BPF_TABLE_PINNED(_table_type, _key_type, _leaf_type, _name, _max_entries, "/sys/fs/bpf/xyz")```
The type information is not enforced and the actual map type depends on the map that got pinned to the location.
Syntax: ```BPF_TABLE_PINNED(_table_type, _key_type, _leaf_type, _name, _max_entries, "/sys/fs/bpf/xyz")```

Create a new map if it doesn't exist and pin it to the bpffs as a FILE, otherwise use the map that was pinned to the bpffs. The type information is not enforced and the actual map type depends on the map that got pinned to the location.

For example:

Expand Down
50 changes: 30 additions & 20 deletions src/cc/bpf_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,9 @@ int BPFModule::create_maps(std::map<std::string, std::pair<int, int>> &map_tids,

for (auto map : fake_fd_map_) {
int fd, fake_fd, map_type, key_size, value_size, max_entries, map_flags;
int pinned_id;
const char *map_name;
unsigned int pinned_id;
const char *pinned;
std::string inner_map_name;
int inner_map_fd = 0;

Expand Down Expand Up @@ -317,26 +318,26 @@ int BPFModule::create_maps(std::map<std::string, std::pair<int, int>> &map_tids,
inner_map_fd = inner_map_fds[inner_map_name];
}

if (pinned_id) {
fd = bpf_map_get_fd_by_id(pinned_id);
} else {
struct bpf_create_map_attr attr = {};
attr.map_type = (enum bpf_map_type)map_type;
attr.name = map_name;
attr.key_size = key_size;
attr.value_size = value_size;
attr.max_entries = max_entries;
attr.map_flags = map_flags;
attr.map_ifindex = ifindex_;
attr.inner_map_fd = inner_map_fd;

if (map_tids.find(map_name) != map_tids.end()) {
attr.btf_fd = btf_->get_fd();
attr.btf_key_type_id = map_tids[map_name].first;
attr.btf_value_type_id = map_tids[map_name].second;
}
if (pinned_id <= 0) {
struct bpf_create_map_attr attr = {};
attr.map_type = (enum bpf_map_type)map_type;
attr.name = map_name;
attr.key_size = key_size;
attr.value_size = value_size;
attr.max_entries = max_entries;
attr.map_flags = map_flags;
attr.map_ifindex = ifindex_;
attr.inner_map_fd = inner_map_fd;

if (map_tids.find(map_name) != map_tids.end()) {
attr.btf_fd = btf_->get_fd();
attr.btf_key_type_id = map_tids[map_name].first;
attr.btf_value_type_id = map_tids[map_name].second;
}

fd = bcc_create_map_xattr(&attr, allow_rlimit_);
fd = bcc_create_map_xattr(&attr, allow_rlimit_);
} else {
fd = bpf_map_get_fd_by_id(pinned_id);
}

if (fd < 0) {
Expand All @@ -345,6 +346,15 @@ int BPFModule::create_maps(std::map<std::string, std::pair<int, int>> &map_tids,
return -1;
}

if (pinned_id == -1) {
pinned = get<8>(map.second).c_str();
if (bpf_obj_pin(fd, pinned)) {
fprintf(stderr, "failed to pin map: %s, error: %s\n",
pinned, strerror(errno));
return -1;
}
}

if (for_inner_map)
inner_map_fds[map_name] = fd;

Expand Down
32 changes: 22 additions & 10 deletions src/cc/frontends/clang/b_frontend_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1392,24 +1392,36 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
++i;
}

std::string section_attr = string(A->getName());
std::string section_attr = string(A->getName()), pinned;
size_t pinned_path_pos = section_attr.find(":");
unsigned int pinned_id = 0; // 0 is not a valid map ID, they start with 1
// 0 is not a valid map ID, -1 is to create and pin it to file
int pinned_id = 0;

if (pinned_path_pos != std::string::npos) {
std::string pinned = section_attr.substr(pinned_path_pos + 1);
pinned = section_attr.substr(pinned_path_pos + 1);
section_attr = section_attr.substr(0, pinned_path_pos);
int fd = bpf_obj_get(pinned.c_str());
struct bpf_map_info info = {};
unsigned int info_len = sizeof(info);
if (fd < 0) {
if (bcc_make_parent_dir(pinned.c_str()) ||
bcc_check_bpffs_path(pinned.c_str())) {
return false;
}

if (bpf_obj_get_info_by_fd(fd, &info, &info_len)) {
error(GET_BEGINLOC(Decl), "map not found: %0") << pinned;
return false;
pinned_id = -1;
} else {
struct bpf_map_info info = {};
unsigned int info_len = sizeof(info);

if (bpf_obj_get_info_by_fd(fd, &info, &info_len)) {
error(GET_BEGINLOC(Decl), "get map info failed: %0")
<< strerror(errno);
return false;
}

pinned_id = info.id;
}

close(fd);
pinned_id = info.id;
}

// Additional map specific information
Expand Down Expand Up @@ -1535,7 +1547,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
fe_.add_map_def(table.fake_fd, std::make_tuple((int)map_type, std::string(table.name),
(int)table.key_size, (int)table.leaf_size,
(int)table.max_entries, table.flags, pinned_id,
inner_map_name));
inner_map_name, pinned));
}

if (!table.is_extern)
Expand Down
3 changes: 2 additions & 1 deletion src/cc/frontends/clang/b_frontend_action.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ class BFrontendAction : public clang::ASTFrontendAction {
// negative fake_fd to be different from real fd in bpf_pseudo_fd.
int get_next_fake_fd() { return next_fake_fd_--; }
void add_map_def(int fd,
std::tuple<int, std::string, int, int, int, int, unsigned int, std::string> map_def) {
std::tuple<int, std::string, int, int, int, int, int, std::string,
std::string> map_def) {
fake_fd_map_[fd] = move(map_def);
}

Expand Down
52 changes: 52 additions & 0 deletions src/cc/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <linux/if_alg.h>

Expand Down Expand Up @@ -93,6 +95,10 @@

#define PERF_UPROBE_REF_CTR_OFFSET_SHIFT 32

#ifndef BPF_FS_MAGIC
#define BPF_FS_MAGIC 0xcafe4a11
#endif

struct bpf_helper {
char *name;
char *required_version;
Expand Down Expand Up @@ -1526,3 +1532,49 @@ int bcc_iter_create(int link_fd)
{
return bpf_iter_create(link_fd);
}

int bcc_make_parent_dir(const char *path) {
int err = 0;
char *dname, *dir;

dname = strdup(path);
if (dname == NULL)
return -ENOMEM;

dir = dirname(dname);
if (mkdir(dir, 0700) && errno != EEXIST)
err = -errno;

free(dname);
if (err)
fprintf(stderr, "failed to mkdir %s: %s\n", path, strerror(-err));

return err;
}

int bcc_check_bpffs_path(const char *path) {
struct statfs st_fs;
char *dname, *dir;
int err = 0;

if (path == NULL)
return -EINVAL;

dname = strdup(path);
if (dname == NULL)
return -ENOMEM;

dir = dirname(dname);
if (statfs(dir, &st_fs)) {
err = -errno;
fprintf(stderr, "failed to statfs %s: %s\n", path, strerror(-err));
}

free(dname);
if (!err && st_fs.f_type != BPF_FS_MAGIC) {
err = -EINVAL;
fprintf(stderr, "specified path %s is not on BPF FS\n", path);
}

return err;
}
2 changes: 2 additions & 0 deletions src/cc/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ int bpf_obj_get_info_by_fd(int prog_fd, void *info, uint32_t *info_len);
int bcc_iter_attach(int prog_fd, union bpf_iter_link_info *link_info,
uint32_t link_info_len);
int bcc_iter_create(int link_fd);
int bcc_make_parent_dir(const char *path);
int bcc_check_bpffs_path(const char *path);

#define LOG_BUF_SIZE 65536

Expand Down
2 changes: 1 addition & 1 deletion src/cc/table_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

namespace ebpf {

typedef std::map<int, std::tuple<int, std::string, int, int, int, int, unsigned int, std::string>>
typedef std::map<int, std::tuple<int, std::string, int, int, int, int, int, std::string, std::string>>
fake_fd_map_def;

class TableStorageImpl;
Expand Down
5 changes: 3 additions & 2 deletions tests/cc/test_pinned_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ TEST_CASE("test pinned table", "[pinned_table]") {
REQUIRE(t[key] == value);
}

// test failure
// test create if not exist
{
const std::string BPF_PROGRAM = R"(
BPF_TABLE_PINNED("hash", u64, u64, ids, 1024, "/sys/fs/bpf/test_pinned_table");
Expand All @@ -76,7 +76,8 @@ TEST_CASE("test pinned table", "[pinned_table]") {
ebpf::BPF bpf;
ebpf::StatusTuple res(0);
res = bpf.init(BPF_PROGRAM);
REQUIRE(res.code() != 0);
REQUIRE(res.code() == 0);
unlink("/sys/fs/bpf/test_pinned_table");
}

if (mounted) {
Expand Down

0 comments on commit b209161

Please sign in to comment.