From 81bfdd087bf31a87c5ff25cc7004d5308954a35c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 18 Dec 2019 16:28:34 -0800 Subject: libbpf: Put Kconfig externs into .kconfig section Move Kconfig-provided externs into custom .kconfig section. Add __kconfig into bpf_helpers.h for user convenience. Update selftests accordingly. Suggested-by: Daniel Borkmann Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191219002837.3074619-2-andriin@fb.com --- tools/bpf/bpftool/gen.c | 8 +-- tools/lib/bpf/bpf_helpers.h | 2 + tools/lib/bpf/libbpf.c | 58 +++++++++++++--------- tools/testing/selftests/bpf/prog_tests/skeleton.c | 16 +++--- .../testing/selftests/bpf/progs/test_core_extern.c | 20 ++++---- tools/testing/selftests/bpf/progs/test_skeleton.c | 4 +- 6 files changed, 60 insertions(+), 48 deletions(-) diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index 851c465f99dc..a14d8bc5d31d 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -83,8 +83,8 @@ static const char *get_map_ident(const struct bpf_map *map) return "rodata"; else if (str_has_suffix(name, ".bss")) return "bss"; - else if (str_has_suffix(name, ".extern")) - return "externs"; /* extern is a C keyword */ + else if (str_has_suffix(name, ".kconfig")) + return "kconfig"; else return NULL; } @@ -112,8 +112,8 @@ static int codegen_datasec_def(struct bpf_object *obj, sec_ident = "bss"; else if (strcmp(sec_name, ".rodata") == 0) sec_ident = "rodata"; - else if (strcmp(sec_name, ".extern") == 0) - sec_ident = "externs"; /* extern is a C keyword */ + else if (strcmp(sec_name, ".kconfig") == 0) + sec_ident = "kconfig"; else return 0; diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index aa46700075e1..f69cc208778a 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -53,4 +53,6 @@ enum libbpf_tristate { TRI_MODULE = 2, }; +#define __kconfig __attribute__((section(".kconfig"))) + #endif diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 2a341a5b9f63..0772eb3254e2 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -231,21 +231,21 @@ struct bpf_program { #define DATA_SEC ".data" #define BSS_SEC ".bss" #define RODATA_SEC ".rodata" -#define EXTERN_SEC ".extern" +#define KCONFIG_SEC ".kconfig" enum libbpf_map_type { LIBBPF_MAP_UNSPEC, LIBBPF_MAP_DATA, LIBBPF_MAP_BSS, LIBBPF_MAP_RODATA, - LIBBPF_MAP_EXTERN, + LIBBPF_MAP_KCONFIG, }; static const char * const libbpf_type_to_btf_name[] = { [LIBBPF_MAP_DATA] = DATA_SEC, [LIBBPF_MAP_BSS] = BSS_SEC, [LIBBPF_MAP_RODATA] = RODATA_SEC, - [LIBBPF_MAP_EXTERN] = EXTERN_SEC, + [LIBBPF_MAP_KCONFIG] = KCONFIG_SEC, }; struct bpf_map { @@ -305,7 +305,7 @@ struct bpf_object { char *kconfig_path; struct extern_desc *externs; int nr_extern; - int extern_map_idx; + int kconfig_map_idx; bool loaded; bool has_pseudo_calls; @@ -606,7 +606,7 @@ static struct bpf_object *bpf_object__new(const char *path, obj->efile.data_shndx = -1; obj->efile.rodata_shndx = -1; obj->efile.bss_shndx = -1; - obj->extern_map_idx = -1; + obj->kconfig_map_idx = -1; obj->kern_version = get_kernel_version(); obj->loaded = false; @@ -902,11 +902,25 @@ static size_t bpf_map_mmap_sz(const struct bpf_map *map) return map_sz; } +static char *internal_map_name(struct bpf_object *obj, + enum libbpf_map_type type) +{ + char map_name[BPF_OBJ_NAME_LEN]; + const char *sfx = libbpf_type_to_btf_name[type]; + int sfx_len = max((size_t)7, strlen(sfx)); + int pfx_len = min((size_t)BPF_OBJ_NAME_LEN - sfx_len - 1, + strlen(obj->name)); + + snprintf(map_name, sizeof(map_name), "%.*s%.*s", pfx_len, obj->name, + sfx_len, libbpf_type_to_btf_name[type]); + + return strdup(map_name); +} + static int bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, int sec_idx, void *data, size_t data_sz) { - char map_name[BPF_OBJ_NAME_LEN]; struct bpf_map_def *def; struct bpf_map *map; int err; @@ -918,9 +932,7 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, map->libbpf_type = type; map->sec_idx = sec_idx; map->sec_offset = 0; - snprintf(map_name, sizeof(map_name), "%.8s%.7s", obj->name, - libbpf_type_to_btf_name[type]); - map->name = strdup(map_name); + map->name = internal_map_name(obj, type); if (!map->name) { pr_warn("failed to alloc map name\n"); return -ENOMEM; @@ -931,12 +943,12 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, def->key_size = sizeof(int); def->value_size = data_sz; def->max_entries = 1; - def->map_flags = type == LIBBPF_MAP_RODATA || type == LIBBPF_MAP_EXTERN + def->map_flags = type == LIBBPF_MAP_RODATA || type == LIBBPF_MAP_KCONFIG ? BPF_F_RDONLY_PROG : 0; def->map_flags |= BPF_F_MMAPABLE; pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n", - map_name, map->sec_idx, map->sec_offset, def->map_flags); + map->name, map->sec_idx, map->sec_offset, def->map_flags); map->mmaped = mmap(NULL, bpf_map_mmap_sz(map), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); @@ -1232,7 +1244,7 @@ out: return err; } -static int bpf_object__init_extern_map(struct bpf_object *obj) +static int bpf_object__init_kconfig_map(struct bpf_object *obj) { struct extern_desc *last_ext; size_t map_sz; @@ -1244,13 +1256,13 @@ static int bpf_object__init_extern_map(struct bpf_object *obj) last_ext = &obj->externs[obj->nr_extern - 1]; map_sz = last_ext->data_off + last_ext->sz; - err = bpf_object__init_internal_map(obj, LIBBPF_MAP_EXTERN, + err = bpf_object__init_internal_map(obj, LIBBPF_MAP_KCONFIG, obj->efile.symbols_shndx, NULL, map_sz); if (err) return err; - obj->extern_map_idx = obj->nr_maps - 1; + obj->kconfig_map_idx = obj->nr_maps - 1; return 0; } @@ -1742,7 +1754,7 @@ static int bpf_object__init_maps(struct bpf_object *obj, err = bpf_object__init_user_maps(obj, strict); err = err ?: bpf_object__init_user_btf_maps(obj, strict, pin_root_path); err = err ?: bpf_object__init_global_data_maps(obj); - err = err ?: bpf_object__init_extern_map(obj); + err = err ?: bpf_object__init_kconfig_map(obj); if (err) return err; @@ -2269,9 +2281,9 @@ static int bpf_object__collect_externs(struct bpf_object *obj) i, ext->sym_idx, ext->data_off, ext->name); } - btf_id = btf__find_by_name(obj->btf, EXTERN_SEC); + btf_id = btf__find_by_name(obj->btf, KCONFIG_SEC); if (btf_id <= 0) { - pr_warn("no BTF info found for '%s' datasec\n", EXTERN_SEC); + pr_warn("no BTF info found for '%s' datasec\n", KCONFIG_SEC); return -ESRCH; } @@ -2361,7 +2373,7 @@ bpf_object__section_to_libbpf_map_type(const struct bpf_object *obj, int shndx) else if (shndx == obj->efile.rodata_shndx) return LIBBPF_MAP_RODATA; else if (shndx == obj->efile.symbols_shndx) - return LIBBPF_MAP_EXTERN; + return LIBBPF_MAP_KCONFIG; else return LIBBPF_MAP_UNSPEC; } @@ -2908,8 +2920,8 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) return err; } - /* Freeze .rodata and .extern map as read-only from syscall side. */ - if (map_type == LIBBPF_MAP_RODATA || map_type == LIBBPF_MAP_EXTERN) { + /* Freeze .rodata and .kconfig map as read-only from syscall side. */ + if (map_type == LIBBPF_MAP_RODATA || map_type == LIBBPF_MAP_KCONFIG) { err = bpf_map_freeze(map->fd); if (err) { err = -errno; @@ -4264,7 +4276,7 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) break; case RELO_EXTERN: insn[0].src_reg = BPF_PSEUDO_MAP_VALUE; - insn[0].imm = obj->maps[obj->extern_map_idx].fd; + insn[0].imm = obj->maps[obj->kconfig_map_idx].fd; insn[1].imm = relo->sym_off; break; case RELO_CALL: @@ -4743,7 +4755,7 @@ static int bpf_object__resolve_externs(struct bpf_object *obj, if (obj->nr_extern == 0) return 0; - data = obj->maps[obj->extern_map_idx].mmaped; + data = obj->maps[obj->kconfig_map_idx].mmaped; for (i = 0; i < obj->nr_extern; i++) { ext = &obj->externs[i]; @@ -7546,7 +7558,7 @@ int bpf_object__open_skeleton(struct bpf_object_skeleton *s, } /* externs shouldn't be pre-setup from user code */ - if (mmaped && (*map)->libbpf_type != LIBBPF_MAP_EXTERN) + if (mmaped && (*map)->libbpf_type != LIBBPF_MAP_KCONFIG) *mmaped = (*map)->mmaped; } diff --git a/tools/testing/selftests/bpf/prog_tests/skeleton.c b/tools/testing/selftests/bpf/prog_tests/skeleton.c index ec6f2aec3853..9264a2736018 100644 --- a/tools/testing/selftests/bpf/prog_tests/skeleton.c +++ b/tools/testing/selftests/bpf/prog_tests/skeleton.c @@ -15,20 +15,18 @@ void test_skeleton(void) int duration = 0, err; struct test_skeleton* skel; struct test_skeleton__bss *bss; - struct test_skeleton__externs *exts; + struct test_skeleton__kconfig *kcfg; skel = test_skeleton__open(); if (CHECK(!skel, "skel_open", "failed to open skeleton\n")) return; - printf("EXTERNS BEFORE: %p\n", skel->externs); - if (CHECK(skel->externs, "skel_externs", "externs are mmaped()!\n")) + if (CHECK(skel->kconfig, "skel_kconfig", "kconfig is mmaped()!\n")) goto cleanup; err = test_skeleton__load(skel); if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err)) goto cleanup; - printf("EXTERNS AFTER: %p\n", skel->externs); bss = skel->bss; bss->in1 = 1; @@ -37,7 +35,7 @@ void test_skeleton(void) bss->in4 = 4; bss->in5.a = 5; bss->in5.b = 6; - exts = skel->externs; + kcfg = skel->kconfig; err = test_skeleton__attach(skel); if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err)) @@ -55,10 +53,10 @@ void test_skeleton(void) CHECK(bss->handler_out5.b != 6, "res6", "got %lld != exp %d\n", bss->handler_out5.b, 6); - CHECK(bss->bpf_syscall != exts->CONFIG_BPF_SYSCALL, "ext1", - "got %d != exp %d\n", bss->bpf_syscall, exts->CONFIG_BPF_SYSCALL); - CHECK(bss->kern_ver != exts->LINUX_KERNEL_VERSION, "ext2", - "got %d != exp %d\n", bss->kern_ver, exts->LINUX_KERNEL_VERSION); + CHECK(bss->bpf_syscall != kcfg->CONFIG_BPF_SYSCALL, "ext1", + "got %d != exp %d\n", bss->bpf_syscall, kcfg->CONFIG_BPF_SYSCALL); + CHECK(bss->kern_ver != kcfg->LINUX_KERNEL_VERSION, "ext2", + "got %d != exp %d\n", bss->kern_ver, kcfg->LINUX_KERNEL_VERSION); cleanup: test_skeleton__destroy(skel); diff --git a/tools/testing/selftests/bpf/progs/test_core_extern.c b/tools/testing/selftests/bpf/progs/test_core_extern.c index e12f09f9e881..9bfc91d9d004 100644 --- a/tools/testing/selftests/bpf/progs/test_core_extern.c +++ b/tools/testing/selftests/bpf/progs/test_core_extern.c @@ -10,16 +10,16 @@ /* non-existing BPF helper, to test dead code elimination */ static int (*bpf_missing_helper)(const void *arg1, int arg2) = (void *) 999; -extern int LINUX_KERNEL_VERSION; -extern bool CONFIG_BPF_SYSCALL; /* strong */ -extern enum libbpf_tristate CONFIG_TRISTATE __weak; -extern bool CONFIG_BOOL __weak; -extern char CONFIG_CHAR __weak; -extern uint16_t CONFIG_USHORT __weak; -extern int CONFIG_INT __weak; -extern uint64_t CONFIG_ULONG __weak; -extern const char CONFIG_STR[8] __weak; -extern uint64_t CONFIG_MISSING __weak; +extern int LINUX_KERNEL_VERSION __kconfig; +extern bool CONFIG_BPF_SYSCALL __kconfig; /* strong */ +extern enum libbpf_tristate CONFIG_TRISTATE __kconfig __weak; +extern bool CONFIG_BOOL __kconfig __weak; +extern char CONFIG_CHAR __kconfig __weak; +extern uint16_t CONFIG_USHORT __kconfig __weak; +extern int CONFIG_INT __kconfig __weak; +extern uint64_t CONFIG_ULONG __kconfig __weak; +extern const char CONFIG_STR[8] __kconfig __weak; +extern uint64_t CONFIG_MISSING __kconfig __weak; uint64_t kern_ver = -1; uint64_t bpf_syscall = -1; diff --git a/tools/testing/selftests/bpf/progs/test_skeleton.c b/tools/testing/selftests/bpf/progs/test_skeleton.c index 9caa44758ea2..4f69aac5635f 100644 --- a/tools/testing/selftests/bpf/progs/test_skeleton.c +++ b/tools/testing/selftests/bpf/progs/test_skeleton.c @@ -21,8 +21,8 @@ char out3 = 0; long long out4 = 0; int out1 = 0; -extern bool CONFIG_BPF_SYSCALL; -extern int LINUX_KERNEL_VERSION; +extern bool CONFIG_BPF_SYSCALL __kconfig; +extern int LINUX_KERNEL_VERSION __kconfig; bool bpf_syscall = 0; int kern_ver = 0; -- cgit v1.2.3 From 8601fd422148a8f7ff5f7eaf75b6703d5166332c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 18 Dec 2019 16:28:35 -0800 Subject: libbpf: Allow to augment system Kconfig through extra optional config Instead of all or nothing approach of overriding Kconfig file location, allow to extend it with extra values and override chosen subset of values though optional user-provided extra config, passed as a string through open options' .kconfig option. If same config key is present in both user-supplied config and Kconfig, user-supplied one wins. This allows applications to more easily test various conditions despite host kernel's real configuration. If all of BPF object's __kconfig externs are satisfied from user-supplied config, system Kconfig won't be read at all. Simplify selftests by not needing to create temporary Kconfig files. Suggested-by: Alexei Starovoitov Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191219002837.3074619-3-andriin@fb.com --- tools/lib/bpf/libbpf.c | 204 +++++++++++++-------- tools/lib/bpf/libbpf.h | 8 +- .../testing/selftests/bpf/prog_tests/core_extern.c | 32 +--- 3 files changed, 132 insertions(+), 112 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 0772eb3254e2..7b74382c7977 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -302,7 +302,7 @@ struct bpf_object { size_t nr_maps; size_t maps_cap; - char *kconfig_path; + char *kconfig; struct extern_desc *externs; int nr_extern; int kconfig_map_idx; @@ -1149,98 +1149,129 @@ static int set_ext_value_num(struct extern_desc *ext, void *ext_val, return 0; } -static int bpf_object__read_kernel_config(struct bpf_object *obj, - const char *config_path, - void *data) +static int bpf_object__process_kconfig_line(struct bpf_object *obj, + char *buf, void *data) { - char buf[PATH_MAX], *sep, *value; struct extern_desc *ext; + char *sep, *value; int len, err = 0; void *ext_val; __u64 num; - gzFile file; - if (config_path) { - file = gzopen(config_path, "r"); - } else { - struct utsname uts; + if (strncmp(buf, "CONFIG_", 7)) + return 0; - uname(&uts); - len = snprintf(buf, PATH_MAX, "/boot/config-%s", uts.release); - if (len < 0) - return -EINVAL; - else if (len >= PATH_MAX) - return -ENAMETOOLONG; - /* gzopen also accepts uncompressed files. */ - file = gzopen(buf, "r"); - if (!file) - file = gzopen("/proc/config.gz", "r"); + sep = strchr(buf, '='); + if (!sep) { + pr_warn("failed to parse '%s': no separator\n", buf); + return -EINVAL; + } + + /* Trim ending '\n' */ + len = strlen(buf); + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + /* Split on '=' and ensure that a value is present. */ + *sep = '\0'; + if (!sep[1]) { + *sep = '='; + pr_warn("failed to parse '%s': no value\n", buf); + return -EINVAL; + } + + ext = find_extern_by_name(obj, buf); + if (!ext || ext->is_set) + return 0; + + ext_val = data + ext->data_off; + value = sep + 1; + + switch (*value) { + case 'y': case 'n': case 'm': + err = set_ext_value_tri(ext, ext_val, *value); + break; + case '"': + err = set_ext_value_str(ext, ext_val, value); + break; + default: + /* assume integer */ + err = parse_u64(value, &num); + if (err) { + pr_warn("extern %s=%s should be integer\n", + ext->name, value); + return err; + } + err = set_ext_value_num(ext, ext_val, num); + break; } + if (err) + return err; + pr_debug("extern %s=%s\n", ext->name, value); + return 0; +} + +static int bpf_object__read_kconfig_file(struct bpf_object *obj, void *data) +{ + char buf[PATH_MAX]; + struct utsname uts; + int len, err = 0; + gzFile file; + + uname(&uts); + len = snprintf(buf, PATH_MAX, "/boot/config-%s", uts.release); + if (len < 0) + return -EINVAL; + else if (len >= PATH_MAX) + return -ENAMETOOLONG; + + /* gzopen also accepts uncompressed files. */ + file = gzopen(buf, "r"); + if (!file) + file = gzopen("/proc/config.gz", "r"); + if (!file) { - pr_warn("failed to read kernel config at '%s'\n", config_path); + pr_warn("failed to open system Kconfig\n"); return -ENOENT; } while (gzgets(file, buf, sizeof(buf))) { - if (strncmp(buf, "CONFIG_", 7)) - continue; - - sep = strchr(buf, '='); - if (!sep) { - err = -EINVAL; - pr_warn("failed to parse '%s': no separator\n", buf); - goto out; - } - /* Trim ending '\n' */ - len = strlen(buf); - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - /* Split on '=' and ensure that a value is present. */ - *sep = '\0'; - if (!sep[1]) { - err = -EINVAL; - *sep = '='; - pr_warn("failed to parse '%s': no value\n", buf); + err = bpf_object__process_kconfig_line(obj, buf, data); + if (err) { + pr_warn("error parsing system Kconfig line '%s': %d\n", + buf, err); goto out; } + } - ext = find_extern_by_name(obj, buf); - if (!ext) - continue; - if (ext->is_set) { - err = -EINVAL; - pr_warn("re-defining extern '%s' not allowed\n", buf); - goto out; - } +out: + gzclose(file); + return err; +} - ext_val = data + ext->data_off; - value = sep + 1; +static int bpf_object__read_kconfig_mem(struct bpf_object *obj, + const char *config, void *data) +{ + char buf[PATH_MAX]; + int err = 0; + FILE *file; - switch (*value) { - case 'y': case 'n': case 'm': - err = set_ext_value_tri(ext, ext_val, *value); - break; - case '"': - err = set_ext_value_str(ext, ext_val, value); - break; - default: - /* assume integer */ - err = parse_u64(value, &num); - if (err) { - pr_warn("extern %s=%s should be integer\n", - ext->name, value); - goto out; - } - err = set_ext_value_num(ext, ext_val, num); + file = fmemopen((void *)config, strlen(config), "r"); + if (!file) { + err = -errno; + pr_warn("failed to open in-memory Kconfig: %d\n", err); + return err; + } + + while (fgets(buf, sizeof(buf), file)) { + err = bpf_object__process_kconfig_line(obj, buf, data); + if (err) { + pr_warn("error parsing in-memory Kconfig line '%s': %d\n", + buf, err); break; } - if (err) - goto out; - pr_debug("extern %s=%s\n", ext->name, value); } -out: - gzclose(file); + fclose(file); return err; } @@ -4567,7 +4598,7 @@ static struct bpf_object * __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, const struct bpf_object_open_opts *opts) { - const char *obj_name, *kconfig_path; + const char *obj_name, *kconfig; struct bpf_program *prog; struct bpf_object *obj; char tmp_name[64]; @@ -4599,10 +4630,10 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, return obj; obj->relaxed_core_relocs = OPTS_GET(opts, relaxed_core_relocs, false); - kconfig_path = OPTS_GET(opts, kconfig_path, NULL); - if (kconfig_path) { - obj->kconfig_path = strdup(kconfig_path); - if (!obj->kconfig_path) + kconfig = OPTS_GET(opts, kconfig, NULL); + if (kconfig) { + obj->kconfig = strdup(kconfig); + if (!obj->kconfig) return ERR_PTR(-ENOMEM); } @@ -4745,7 +4776,7 @@ static int bpf_object__sanitize_maps(struct bpf_object *obj) } static int bpf_object__resolve_externs(struct bpf_object *obj, - const char *config_path) + const char *extra_kconfig) { bool need_config = false; struct extern_desc *ext; @@ -4779,8 +4810,21 @@ static int bpf_object__resolve_externs(struct bpf_object *obj, return -EINVAL; } } + if (need_config && extra_kconfig) { + err = bpf_object__read_kconfig_mem(obj, extra_kconfig, data); + if (err) + return -EINVAL; + need_config = false; + for (i = 0; i < obj->nr_extern; i++) { + ext = &obj->externs[i]; + if (!ext->is_set) { + need_config = true; + break; + } + } + } if (need_config) { - err = bpf_object__read_kernel_config(obj, config_path, data); + err = bpf_object__read_kconfig_file(obj, data); if (err) return -EINVAL; } @@ -4818,7 +4862,7 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr) obj->loaded = true; err = bpf_object__probe_caps(obj); - err = err ? : bpf_object__resolve_externs(obj, obj->kconfig_path); + err = err ? : bpf_object__resolve_externs(obj, obj->kconfig); err = err ? : bpf_object__sanitize_and_load_btf(obj); err = err ? : bpf_object__sanitize_maps(obj); err = err ? : bpf_object__create_maps(obj); @@ -5412,7 +5456,7 @@ void bpf_object__close(struct bpf_object *obj) zfree(&map->pin_path); } - zfree(&obj->kconfig_path); + zfree(&obj->kconfig); zfree(&obj->externs); obj->nr_extern = 0; diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index ad8c1c127933..fe592ef48f1b 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -85,12 +85,12 @@ struct bpf_object_open_opts { */ const char *pin_root_path; __u32 attach_prog_fd; - /* kernel config file path override (for CONFIG_ externs); can point - * to either uncompressed text file or .gz file + /* Additional kernel config content that augments and overrides + * system Kconfig for CONFIG_xxx externs. */ - const char *kconfig_path; + const char *kconfig; }; -#define bpf_object_open_opts__last_field kconfig_path +#define bpf_object_open_opts__last_field kconfig LIBBPF_API struct bpf_object *bpf_object__open(const char *path); LIBBPF_API struct bpf_object * diff --git a/tools/testing/selftests/bpf/prog_tests/core_extern.c b/tools/testing/selftests/bpf/prog_tests/core_extern.c index 5f03dc1de29e..b093787e9448 100644 --- a/tools/testing/selftests/bpf/prog_tests/core_extern.c +++ b/tools/testing/selftests/bpf/prog_tests/core_extern.c @@ -23,19 +23,13 @@ static uint32_t get_kernel_version(void) static struct test_case { const char *name; const char *cfg; - const char *cfg_path; bool fails; struct test_core_extern__data data; } test_cases[] = { - { .name = "default search path", .cfg_path = NULL, - .data = { .bpf_syscall = true } }, - { .name = "/proc/config.gz", .cfg_path = "/proc/config.gz", - .data = { .bpf_syscall = true } }, - { .name = "missing config", .fails = true, - .cfg_path = "/proc/invalid-config.gz" }, + { .name = "default search path", .data = { .bpf_syscall = true } }, { .name = "custom values", - .cfg = "CONFIG_BPF_SYSCALL=y\n" + .cfg = "CONFIG_BPF_SYSCALL=n\n" "CONFIG_TRISTATE=m\n" "CONFIG_BOOL=y\n" "CONFIG_CHAR=100\n" @@ -45,7 +39,7 @@ static struct test_case { "CONFIG_STR=\"abracad\"\n" "CONFIG_MISSING=0", .data = { - .bpf_syscall = true, + .bpf_syscall = false, .tristate_val = TRI_MODULE, .bool_val = true, .char_val = 100, @@ -133,30 +127,14 @@ void test_core_extern(void) int n = sizeof(*skel->data) / sizeof(uint64_t); for (i = 0; i < ARRAY_SIZE(test_cases); i++) { - char tmp_cfg_path[] = "/tmp/test_core_extern_cfg.XXXXXX"; struct test_case *t = &test_cases[i]; DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, - .kconfig_path = t->cfg_path, + .kconfig = t->cfg, ); if (!test__start_subtest(t->name)) continue; - if (t->cfg) { - size_t n = strlen(t->cfg) + 1; - int fd = mkstemp(tmp_cfg_path); - int written; - - if (CHECK(fd < 0, "mkstemp", "errno: %d\n", errno)) - continue; - printf("using '%s' as config file\n", tmp_cfg_path); - written = write(fd, t->cfg, n); - close(fd); - if (CHECK_FAIL(written != n)) - goto cleanup; - opts.kconfig_path = tmp_cfg_path; - } - skel = test_core_extern__open_opts(&opts); if (CHECK(!skel, "skel_open", "skeleton open failed\n")) goto cleanup; @@ -185,8 +163,6 @@ void test_core_extern(void) j, exp[j], got[j]); } cleanup: - if (t->cfg) - unlink(tmp_cfg_path); test_core_extern__destroy(skel); skel = NULL; } -- cgit v1.2.3 From 630628cb7dc39780660d8fcedc66e0298a82f9da Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 18 Dec 2019 16:28:36 -0800 Subject: libbpf: BTF is required when externs are present BTF is required to get type information about extern variables. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191219002837.3074619-4-andriin@fb.com --- tools/lib/bpf/libbpf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 7b74382c7977..6340b81b555b 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1887,7 +1887,8 @@ static void bpf_object__sanitize_btf_ext(struct bpf_object *obj) static bool bpf_object__is_btf_mandatory(const struct bpf_object *obj) { - return obj->efile.btf_maps_shndx >= 0; + return obj->efile.btf_maps_shndx >= 0 || + obj->nr_extern > 0; } static int bpf_object__init_btf(struct bpf_object *obj, -- cgit v1.2.3