Skip to content

Commit

Permalink
bpftool, selftests/bpf: Embed object file inside skeleton
Browse files Browse the repository at this point in the history
Embed contents of BPF object file used for BPF skeleton generation inside
skeleton itself. This allows to keep BPF object file and its skeleton in sync
at all times, and simpifies skeleton instantiation.

Also switch existing selftests to not require BPF_EMBED_OBJ anymore.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20191218052552.2915188-2-andriin@fb.com
  • Loading branch information
Andrii Nakryiko authored and Alexei Starovoitov committed Dec 18, 2019
1 parent 4a3d6c6 commit 5dc7a8b
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 119 deletions.
232 changes: 143 additions & 89 deletions tools/bpf/bpftool/gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <libbpf.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>

#include "btf.h"
Expand Down Expand Up @@ -261,14 +262,16 @@ static int codegen(const char *template, ...)
static int do_skeleton(int argc, char **argv)
{
char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
size_t i, map_cnt = 0, prog_cnt = 0;
char obj_name[MAX_OBJ_NAME_LEN];
size_t i, map_cnt = 0, prog_cnt = 0, file_sz, mmap_sz;
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
char obj_name[MAX_OBJ_NAME_LEN], *obj_data;
struct bpf_object *obj = NULL;
const char *file, *ident;
struct bpf_program *prog;
struct bpf_object *obj;
int fd, len, err = -1;
struct bpf_map *map;
struct btf *btf;
int err = -1;
struct stat st;

if (!REQ_ARGS(1)) {
usage();
Expand All @@ -281,14 +284,31 @@ static int do_skeleton(int argc, char **argv)
return -1;
}

obj = bpf_object__open_file(file, NULL);
if (IS_ERR(obj)) {
p_err("failed to open BPF object file: %ld", PTR_ERR(obj));
if (stat(file, &st)) {
p_err("failed to stat() %s: %s", file, strerror(errno));
return -1;
}

file_sz = st.st_size;
mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));
fd = open(file, O_RDONLY);
if (fd < 0) {
p_err("failed to open() %s: %s", file, strerror(errno));
return -1;
}
obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);
if (obj_data == MAP_FAILED) {
obj_data = NULL;
p_err("failed to mmap() %s: %s", file, strerror(errno));
goto out;
}
get_obj_name(obj_name, file);
get_header_guard(header_guard, obj_name);
opts.object_name = obj_name;
obj = bpf_object__open_mem(obj_data, file_sz, &opts);
if (IS_ERR(obj)) {
obj = NULL;
p_err("failed to open BPF object file: %ld", PTR_ERR(obj));
goto out;
}

bpf_object__for_each_map(map, obj) {
ident = get_map_ident(map);
Expand All @@ -303,8 +323,11 @@ static int do_skeleton(int argc, char **argv)
prog_cnt++;
}

get_header_guard(header_guard, obj_name);
codegen("\
\n\
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ \n\
\n\
/* THIS FILE IS AUTOGENERATED! */ \n\
#ifndef %2$s \n\
#define %2$s \n\
Expand Down Expand Up @@ -356,19 +379,95 @@ static int do_skeleton(int argc, char **argv)
\n\
}; \n\
\n\
static inline struct bpf_object_skeleton * \n\
%1$s__create_skeleton(struct %1$s *obj, struct bpf_embed_data *embed)\n\
static void \n\
%1$s__destroy(struct %1$s *obj) \n\
{ \n\
if (!obj) \n\
return; \n\
if (obj->skeleton) \n\
bpf_object__destroy_skeleton(obj->skeleton);\n\
free(obj); \n\
} \n\
\n\
static inline int \n\
%1$s__create_skeleton(struct %1$s *obj); \n\
\n\
static inline struct %1$s * \n\
%1$s__open_opts(const struct bpf_object_open_opts *opts) \n\
{ \n\
struct %1$s *obj; \n\
\n\
obj = calloc(1, sizeof(*obj)); \n\
if (!obj) \n\
return NULL; \n\
if (%1$s__create_skeleton(obj)) \n\
goto err; \n\
if (bpf_object__open_skeleton(obj->skeleton, opts)) \n\
goto err; \n\
\n\
return obj; \n\
err: \n\
%1$s__destroy(obj); \n\
return NULL; \n\
} \n\
\n\
static inline struct %1$s * \n\
%1$s__open(void) \n\
{ \n\
return %1$s__open_opts(NULL); \n\
} \n\
\n\
static inline int \n\
%1$s__load(struct %1$s *obj) \n\
{ \n\
return bpf_object__load_skeleton(obj->skeleton); \n\
} \n\
\n\
static inline struct %1$s * \n\
%1$s__open_and_load(void) \n\
{ \n\
struct %1$s *obj; \n\
\n\
obj = %1$s__open(); \n\
if (!obj) \n\
return NULL; \n\
if (%1$s__load(obj)) { \n\
%1$s__destroy(obj); \n\
return NULL; \n\
} \n\
return obj; \n\
} \n\
\n\
static inline int \n\
%1$s__attach(struct %1$s *obj) \n\
{ \n\
return bpf_object__attach_skeleton(obj->skeleton); \n\
} \n\
\n\
static inline void \n\
%1$s__detach(struct %1$s *obj) \n\
{ \n\
return bpf_object__detach_skeleton(obj->skeleton); \n\
} \n\
",
obj_name
);

codegen("\
\n\
\n\
static inline int \n\
%1$s__create_skeleton(struct %1$s *obj) \n\
{ \n\
struct bpf_object_skeleton *s; \n\
\n\
s = calloc(1, sizeof(*s)); \n\
if (!s) \n\
return NULL; \n\
return -1; \n\
obj->skeleton = s; \n\
\n\
s->sz = sizeof(*s); \n\
s->name = \"%1$s\"; \n\
s->data = embed->data; \n\
s->data_sz = embed->size; \n\
s->obj = &obj->obj; \n\
",
obj_name
Expand Down Expand Up @@ -438,90 +537,45 @@ static int do_skeleton(int argc, char **argv)
codegen("\
\n\
\n\
return s; \n\
err: \n\
bpf_object__destroy_skeleton(s); \n\
return NULL; \n\
} \n\
\n\
static void \n\
%1$s__destroy(struct %1$s *obj) \n\
{ \n\
if (!obj) \n\
return; \n\
if (obj->skeleton) \n\
bpf_object__destroy_skeleton(obj->skeleton);\n\
free(obj); \n\
} \n\
\n\
static inline struct %1$s * \n\
%1$s__open_opts(struct bpf_embed_data *embed, const struct bpf_object_open_opts *opts)\n\
{ \n\
struct %1$s *obj; \n\
\n\
obj = calloc(1, sizeof(*obj)); \n\
if (!obj) \n\
return NULL; \n\
\n\
obj->skeleton = %1$s__create_skeleton(obj, embed); \n\
if (!obj->skeleton) \n\
goto err; \n\
\n\
if (bpf_object__open_skeleton(obj->skeleton, opts)) \n\
goto err; \n\
s->data_sz = %d; \n\
s->data = \"\\ \n\
",
file_sz);

/* embed contents of BPF object file */
for (i = 0, len = 0; i < file_sz; i++) {
int w = obj_data[i] ? 4 : 2;

len += w;
if (len > 78) {
printf("\\\n");
len = w;
}
if (!obj_data[i])
printf("\\0");
else
printf("\\x%02x", (unsigned char)obj_data[i]);
}

codegen("\
\n\
\"; \n\
\n\
return obj; \n\
return 0; \n\
err: \n\
%1$s__destroy(obj); \n\
return NULL; \n\
} \n\
\n\
static inline struct %1$s * \n\
%1$s__open(struct bpf_embed_data *embed) \n\
{ \n\
return %1$s__open_opts(embed, NULL); \n\
} \n\
\n\
static inline int \n\
%1$s__load(struct %1$s *obj) \n\
{ \n\
return bpf_object__load_skeleton(obj->skeleton); \n\
} \n\
\n\
static inline struct %1$s * \n\
%1$s__open_and_load(struct bpf_embed_data *embed) \n\
{ \n\
struct %1$s *obj; \n\
\n\
obj = %1$s__open(embed); \n\
if (!obj) \n\
return NULL; \n\
if (%1$s__load(obj)) { \n\
%1$s__destroy(obj); \n\
return NULL; \n\
} \n\
return obj; \n\
} \n\
\n\
static inline int \n\
%1$s__attach(struct %1$s *obj) \n\
{ \n\
return bpf_object__attach_skeleton(obj->skeleton); \n\
} \n\
\n\
static inline void \n\
%1$s__detach(struct %1$s *obj) \n\
{ \n\
return bpf_object__detach_skeleton(obj->skeleton); \n\
bpf_object__destroy_skeleton(s); \n\
return -1; \n\
} \n\
\n\
#endif /* %2$s */ \n\
",
obj_name, header_guard
);
obj_name, header_guard);
err = 0;
out:
bpf_object__close(obj);
if (obj_data)
munmap(obj_data, mmap_sz);
close(fd);
return err;
}

Expand Down
4 changes: 1 addition & 3 deletions tools/testing/selftests/bpf/prog_tests/attach_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ ssize_t get_base_addr() {
return -EINVAL;
}

BPF_EMBED_OBJ(probe, "test_attach_probe.o");

void test_attach_probe(void)
{
int duration = 0;
Expand All @@ -39,7 +37,7 @@ void test_attach_probe(void)
return;
uprobe_offset = (size_t)&get_base_addr - base_addr;

skel = test_attach_probe__open_and_load(&probe_embed);
skel = test_attach_probe__open_and_load();
if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
return;
if (CHECK(!skel->bss, "check_bss", ".bss wasn't mmap()-ed\n"))
Expand Down
4 changes: 1 addition & 3 deletions tools/testing/selftests/bpf/prog_tests/core_extern.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,6 @@ static struct test_case {
{ .name = "u64 (max+1)", .fails = 1, .cfg = CFG"CONFIG_ULONG=0x10000000000000000" },
};

BPF_EMBED_OBJ(core_extern, "test_core_extern.o");

void test_core_extern(void)
{
const uint32_t kern_ver = get_kernel_version();
Expand Down Expand Up @@ -159,7 +157,7 @@ void test_core_extern(void)
opts.kconfig_path = tmp_cfg_path;
}

skel = test_core_extern__open_opts(&core_extern_embed, &opts);
skel = test_core_extern__open_opts(&opts);
if (CHECK(!skel, "skel_open", "skeleton open failed\n"))
goto cleanup;
err = test_core_extern__load(skel);
Expand Down
10 changes: 3 additions & 7 deletions tools/testing/selftests/bpf/prog_tests/fentry_fexit.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
#include "fentry_test.skel.h"
#include "fexit_test.skel.h"

BPF_EMBED_OBJ(pkt_access, "test_pkt_access.o");
BPF_EMBED_OBJ(fentry, "fentry_test.o");
BPF_EMBED_OBJ(fexit, "fexit_test.o");

void test_fentry_fexit(void)
{
struct test_pkt_access *pkt_skel = NULL;
Expand All @@ -18,13 +14,13 @@ void test_fentry_fexit(void)
__u32 duration = 0, retval;
int err, pkt_fd, i;

pkt_skel = test_pkt_access__open_and_load(&pkt_access_embed);
pkt_skel = test_pkt_access__open_and_load();
if (CHECK(!pkt_skel, "pkt_skel_load", "pkt_access skeleton failed\n"))
return;
fentry_skel = fentry_test__open_and_load(&fentry_embed);
fentry_skel = fentry_test__open_and_load();
if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n"))
goto close_prog;
fexit_skel = fexit_test__open_and_load(&fexit_embed);
fexit_skel = fexit_test__open_and_load();
if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n"))
goto close_prog;

Expand Down
7 changes: 2 additions & 5 deletions tools/testing/selftests/bpf/prog_tests/fentry_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
#include "test_pkt_access.skel.h"
#include "fentry_test.skel.h"

BPF_EMBED_OBJ_DECLARE(pkt_access);
BPF_EMBED_OBJ_DECLARE(fentry);

void test_fentry_test(void)
{
struct test_pkt_access *pkt_skel = NULL;
Expand All @@ -15,10 +12,10 @@ void test_fentry_test(void)
__u32 duration, retval;
__u64 *result;

pkt_skel = test_pkt_access__open_and_load(&pkt_access_embed);
pkt_skel = test_pkt_access__open_and_load();
if (CHECK(!pkt_skel, "pkt_skel_load", "pkt_access skeleton failed\n"))
return;
fentry_skel = fentry_test__open_and_load(&fentry_embed);
fentry_skel = fentry_test__open_and_load();
if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n"))
goto cleanup;

Expand Down
Loading

0 comments on commit 5dc7a8b

Please sign in to comment.