|
@@ -22,6 +22,7 @@
|
|
|
* License along with this program; if not, see <http://www.gnu.org/licenses>
|
|
|
*/
|
|
|
|
|
|
+#define _GNU_SOURCE
|
|
|
#include <stdlib.h>
|
|
|
#include <stdio.h>
|
|
|
#include <stdarg.h>
|
|
@@ -41,6 +42,7 @@
|
|
|
#include <sys/stat.h>
|
|
|
#include <sys/types.h>
|
|
|
#include <sys/vfs.h>
|
|
|
+#include <tools/libc_compat.h>
|
|
|
#include <libelf.h>
|
|
|
#include <gelf.h>
|
|
|
|
|
@@ -95,54 +97,6 @@ void libbpf_set_print(libbpf_print_fn_t warn,
|
|
|
|
|
|
#define STRERR_BUFSIZE 128
|
|
|
|
|
|
-#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
|
|
|
-#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
|
|
|
-#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
|
|
|
-
|
|
|
-static const char *libbpf_strerror_table[NR_ERRNO] = {
|
|
|
- [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf",
|
|
|
- [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid",
|
|
|
- [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost",
|
|
|
- [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch",
|
|
|
- [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf",
|
|
|
- [ERRCODE_OFFSET(RELOC)] = "Relocation failed",
|
|
|
- [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
|
|
|
- [ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
|
|
|
- [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
|
|
|
- [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
|
|
|
- [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
|
|
|
- [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
|
|
|
-};
|
|
|
-
|
|
|
-int libbpf_strerror(int err, char *buf, size_t size)
|
|
|
-{
|
|
|
- if (!buf || !size)
|
|
|
- return -1;
|
|
|
-
|
|
|
- err = err > 0 ? err : -err;
|
|
|
-
|
|
|
- if (err < __LIBBPF_ERRNO__START) {
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = strerror_r(err, buf, size);
|
|
|
- buf[size - 1] = '\0';
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- if (err < __LIBBPF_ERRNO__END) {
|
|
|
- const char *msg;
|
|
|
-
|
|
|
- msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
|
|
|
- snprintf(buf, size, "%s", msg);
|
|
|
- buf[size - 1] = '\0';
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- snprintf(buf, size, "Unknown libbpf error %d", err);
|
|
|
- buf[size - 1] = '\0';
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
#define CHECK_ERR(action, err, out) do { \
|
|
|
err = action; \
|
|
|
if (err) \
|
|
@@ -369,7 +323,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
|
|
|
progs = obj->programs;
|
|
|
nr_progs = obj->nr_programs;
|
|
|
|
|
|
- progs = realloc(progs, sizeof(progs[0]) * (nr_progs + 1));
|
|
|
+ progs = reallocarray(progs, nr_progs + 1, sizeof(progs[0]));
|
|
|
if (!progs) {
|
|
|
/*
|
|
|
* In this case the original obj->programs
|
|
@@ -870,8 +824,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- reloc = realloc(reloc,
|
|
|
- sizeof(*obj->efile.reloc) * nr_reloc);
|
|
|
+ reloc = reallocarray(reloc, nr_reloc,
|
|
|
+ sizeof(*obj->efile.reloc));
|
|
|
if (!reloc) {
|
|
|
pr_warning("realloc failed\n");
|
|
|
err = -ENOMEM;
|
|
@@ -1081,6 +1035,53 @@ static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int bpf_map__reuse_fd(struct bpf_map *map, int fd)
|
|
|
+{
|
|
|
+ struct bpf_map_info info = {};
|
|
|
+ __u32 len = sizeof(info);
|
|
|
+ int new_fd, err;
|
|
|
+ char *new_name;
|
|
|
+
|
|
|
+ err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ new_name = strdup(info.name);
|
|
|
+ if (!new_name)
|
|
|
+ return -errno;
|
|
|
+
|
|
|
+ new_fd = open("/", O_RDONLY | O_CLOEXEC);
|
|
|
+ if (new_fd < 0)
|
|
|
+ goto err_free_new_name;
|
|
|
+
|
|
|
+ new_fd = dup3(fd, new_fd, O_CLOEXEC);
|
|
|
+ if (new_fd < 0)
|
|
|
+ goto err_close_new_fd;
|
|
|
+
|
|
|
+ err = zclose(map->fd);
|
|
|
+ if (err)
|
|
|
+ goto err_close_new_fd;
|
|
|
+ free(map->name);
|
|
|
+
|
|
|
+ map->fd = new_fd;
|
|
|
+ map->name = new_name;
|
|
|
+ map->def.type = info.type;
|
|
|
+ map->def.key_size = info.key_size;
|
|
|
+ map->def.value_size = info.value_size;
|
|
|
+ map->def.max_entries = info.max_entries;
|
|
|
+ map->def.map_flags = info.map_flags;
|
|
|
+ map->btf_key_type_id = info.btf_key_type_id;
|
|
|
+ map->btf_value_type_id = info.btf_value_type_id;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err_close_new_fd:
|
|
|
+ close(new_fd);
|
|
|
+err_free_new_name:
|
|
|
+ free(new_name);
|
|
|
+ return -errno;
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
bpf_object__create_maps(struct bpf_object *obj)
|
|
|
{
|
|
@@ -1093,6 +1094,12 @@ bpf_object__create_maps(struct bpf_object *obj)
|
|
|
struct bpf_map_def *def = &map->def;
|
|
|
int *pfd = &map->fd;
|
|
|
|
|
|
+ if (map->fd >= 0) {
|
|
|
+ pr_debug("skip map create (preset) %s: fd=%d\n",
|
|
|
+ map->name, map->fd);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
create_attr.name = map->name;
|
|
|
create_attr.map_ifindex = map->map_ifindex;
|
|
|
create_attr.map_type = def->type;
|
|
@@ -1163,7 +1170,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
|
|
|
return -LIBBPF_ERRNO__RELOC;
|
|
|
}
|
|
|
new_cnt = prog->insns_cnt + text->insns_cnt;
|
|
|
- new_insn = realloc(prog->insns, new_cnt * sizeof(*insn));
|
|
|
+ new_insn = reallocarray(prog->insns, new_cnt, sizeof(*insn));
|
|
|
if (!new_insn) {
|
|
|
pr_warning("oom in prog realloc\n");
|
|
|
return -ENOMEM;
|
|
@@ -1520,15 +1527,26 @@ out:
|
|
|
return ERR_PTR(err);
|
|
|
}
|
|
|
|
|
|
-struct bpf_object *bpf_object__open(const char *path)
|
|
|
+struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
|
|
|
{
|
|
|
/* param validation */
|
|
|
- if (!path)
|
|
|
+ if (!attr->file)
|
|
|
return NULL;
|
|
|
|
|
|
- pr_debug("loading %s\n", path);
|
|
|
+ pr_debug("loading %s\n", attr->file);
|
|
|
+
|
|
|
+ return __bpf_object__open(attr->file, NULL, 0,
|
|
|
+ bpf_prog_type__needs_kver(attr->prog_type));
|
|
|
+}
|
|
|
+
|
|
|
+struct bpf_object *bpf_object__open(const char *path)
|
|
|
+{
|
|
|
+ struct bpf_object_open_attr attr = {
|
|
|
+ .file = path,
|
|
|
+ .prog_type = BPF_PROG_TYPE_UNSPEC,
|
|
|
+ };
|
|
|
|
|
|
- return __bpf_object__open(path, NULL, 0, true);
|
|
|
+ return bpf_object__open_xattr(&attr);
|
|
|
}
|
|
|
|
|
|
struct bpf_object *bpf_object__open_buffer(void *obj_buf,
|
|
@@ -2081,23 +2099,31 @@ static const struct {
|
|
|
#undef BPF_S_PROG_SEC
|
|
|
#undef BPF_SA_PROG_SEC
|
|
|
|
|
|
-static int bpf_program__identify_section(struct bpf_program *prog)
|
|
|
+int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
|
|
|
+ enum bpf_attach_type *expected_attach_type)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
|
- if (!prog->section_name)
|
|
|
- goto err;
|
|
|
-
|
|
|
- for (i = 0; i < ARRAY_SIZE(section_names); i++)
|
|
|
- if (strncmp(prog->section_name, section_names[i].sec,
|
|
|
- section_names[i].len) == 0)
|
|
|
- return i;
|
|
|
+ if (!name)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
-err:
|
|
|
- pr_warning("failed to guess program type based on section name %s\n",
|
|
|
- prog->section_name);
|
|
|
+ for (i = 0; i < ARRAY_SIZE(section_names); i++) {
|
|
|
+ if (strncmp(name, section_names[i].sec, section_names[i].len))
|
|
|
+ continue;
|
|
|
+ *prog_type = section_names[i].prog_type;
|
|
|
+ *expected_attach_type = section_names[i].expected_attach_type;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
|
|
|
- return -1;
|
|
|
+static int
|
|
|
+bpf_program__identify_section(struct bpf_program *prog,
|
|
|
+ enum bpf_prog_type *prog_type,
|
|
|
+ enum bpf_attach_type *expected_attach_type)
|
|
|
+{
|
|
|
+ return libbpf_prog_type_by_name(prog->section_name, prog_type,
|
|
|
+ expected_attach_type);
|
|
|
}
|
|
|
|
|
|
int bpf_map__fd(struct bpf_map *map)
|
|
@@ -2146,6 +2172,11 @@ void *bpf_map__priv(struct bpf_map *map)
|
|
|
return map ? map->priv : ERR_PTR(-EINVAL);
|
|
|
}
|
|
|
|
|
|
+bool bpf_map__is_offload_neutral(struct bpf_map *map)
|
|
|
+{
|
|
|
+ return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY;
|
|
|
+}
|
|
|
+
|
|
|
void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
|
|
|
{
|
|
|
map->map_ifindex = ifindex;
|
|
@@ -2225,12 +2256,15 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,
|
|
|
int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
|
|
struct bpf_object **pobj, int *prog_fd)
|
|
|
{
|
|
|
+ struct bpf_object_open_attr open_attr = {
|
|
|
+ .file = attr->file,
|
|
|
+ .prog_type = attr->prog_type,
|
|
|
+ };
|
|
|
struct bpf_program *prog, *first_prog = NULL;
|
|
|
enum bpf_attach_type expected_attach_type;
|
|
|
enum bpf_prog_type prog_type;
|
|
|
struct bpf_object *obj;
|
|
|
struct bpf_map *map;
|
|
|
- int section_idx;
|
|
|
int err;
|
|
|
|
|
|
if (!attr)
|
|
@@ -2238,8 +2272,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
|
|
if (!attr->file)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- obj = __bpf_object__open(attr->file, NULL, 0,
|
|
|
- bpf_prog_type__needs_kver(attr->prog_type));
|
|
|
+ obj = bpf_object__open_xattr(&open_attr);
|
|
|
if (IS_ERR_OR_NULL(obj))
|
|
|
return -ENOENT;
|
|
|
|
|
@@ -2252,14 +2285,14 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
|
|
prog->prog_ifindex = attr->ifindex;
|
|
|
expected_attach_type = attr->expected_attach_type;
|
|
|
if (prog_type == BPF_PROG_TYPE_UNSPEC) {
|
|
|
- section_idx = bpf_program__identify_section(prog);
|
|
|
- if (section_idx < 0) {
|
|
|
+ err = bpf_program__identify_section(prog, &prog_type,
|
|
|
+ &expected_attach_type);
|
|
|
+ if (err < 0) {
|
|
|
+ pr_warning("failed to guess program type based on section name %s\n",
|
|
|
+ prog->section_name);
|
|
|
bpf_object__close(obj);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- prog_type = section_names[section_idx].prog_type;
|
|
|
- expected_attach_type =
|
|
|
- section_names[section_idx].expected_attach_type;
|
|
|
}
|
|
|
|
|
|
bpf_program__set_type(prog, prog_type);
|
|
@@ -2271,7 +2304,8 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
|
|
}
|
|
|
|
|
|
bpf_map__for_each(map, obj) {
|
|
|
- map->map_ifindex = attr->ifindex;
|
|
|
+ if (!bpf_map__is_offload_neutral(map))
|
|
|
+ map->map_ifindex = attr->ifindex;
|
|
|
}
|
|
|
|
|
|
if (!first_prog) {
|