Support create a new map and pin it if the pinned file is not available.
Co-authored-by: chenyue.zhou <chenyue.zhou@upai.com>
#### 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:
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;
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) {
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;
++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
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)
// 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);
}
#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>
#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;
{
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;
+}
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
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;
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");
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) {