mirror of
https://github.com/torvalds/linux.git
synced 2024-12-13 22:53:20 +00:00
Merge branch 'libbpf-extern-followups'
Andrii Nakryiko says: ==================== Based on latest feedback and discussions, this patch set implements the following changes: - Kconfig-provided externs have to be in .kconfig section, for which bpf_helpers.h provides convenient __kconfig macro (Daniel); - instead of allowing to override Kconfig file path, switch this to ability to extend and override system Kconfig with user-provided custom values (Alexei); - BTF is required when externs are used. ==================== Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
a352a82496
@ -83,8 +83,8 @@ static const char *get_map_ident(const struct bpf_map *map)
|
|||||||
return "rodata";
|
return "rodata";
|
||||||
else if (str_has_suffix(name, ".bss"))
|
else if (str_has_suffix(name, ".bss"))
|
||||||
return "bss";
|
return "bss";
|
||||||
else if (str_has_suffix(name, ".extern"))
|
else if (str_has_suffix(name, ".kconfig"))
|
||||||
return "externs"; /* extern is a C keyword */
|
return "kconfig";
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -112,8 +112,8 @@ static int codegen_datasec_def(struct bpf_object *obj,
|
|||||||
sec_ident = "bss";
|
sec_ident = "bss";
|
||||||
else if (strcmp(sec_name, ".rodata") == 0)
|
else if (strcmp(sec_name, ".rodata") == 0)
|
||||||
sec_ident = "rodata";
|
sec_ident = "rodata";
|
||||||
else if (strcmp(sec_name, ".extern") == 0)
|
else if (strcmp(sec_name, ".kconfig") == 0)
|
||||||
sec_ident = "externs"; /* extern is a C keyword */
|
sec_ident = "kconfig";
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -53,4 +53,6 @@ enum libbpf_tristate {
|
|||||||
TRI_MODULE = 2,
|
TRI_MODULE = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define __kconfig __attribute__((section(".kconfig")))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -231,21 +231,21 @@ struct bpf_program {
|
|||||||
#define DATA_SEC ".data"
|
#define DATA_SEC ".data"
|
||||||
#define BSS_SEC ".bss"
|
#define BSS_SEC ".bss"
|
||||||
#define RODATA_SEC ".rodata"
|
#define RODATA_SEC ".rodata"
|
||||||
#define EXTERN_SEC ".extern"
|
#define KCONFIG_SEC ".kconfig"
|
||||||
|
|
||||||
enum libbpf_map_type {
|
enum libbpf_map_type {
|
||||||
LIBBPF_MAP_UNSPEC,
|
LIBBPF_MAP_UNSPEC,
|
||||||
LIBBPF_MAP_DATA,
|
LIBBPF_MAP_DATA,
|
||||||
LIBBPF_MAP_BSS,
|
LIBBPF_MAP_BSS,
|
||||||
LIBBPF_MAP_RODATA,
|
LIBBPF_MAP_RODATA,
|
||||||
LIBBPF_MAP_EXTERN,
|
LIBBPF_MAP_KCONFIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const libbpf_type_to_btf_name[] = {
|
static const char * const libbpf_type_to_btf_name[] = {
|
||||||
[LIBBPF_MAP_DATA] = DATA_SEC,
|
[LIBBPF_MAP_DATA] = DATA_SEC,
|
||||||
[LIBBPF_MAP_BSS] = BSS_SEC,
|
[LIBBPF_MAP_BSS] = BSS_SEC,
|
||||||
[LIBBPF_MAP_RODATA] = RODATA_SEC,
|
[LIBBPF_MAP_RODATA] = RODATA_SEC,
|
||||||
[LIBBPF_MAP_EXTERN] = EXTERN_SEC,
|
[LIBBPF_MAP_KCONFIG] = KCONFIG_SEC,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_map {
|
struct bpf_map {
|
||||||
@ -302,10 +302,10 @@ struct bpf_object {
|
|||||||
size_t nr_maps;
|
size_t nr_maps;
|
||||||
size_t maps_cap;
|
size_t maps_cap;
|
||||||
|
|
||||||
char *kconfig_path;
|
char *kconfig;
|
||||||
struct extern_desc *externs;
|
struct extern_desc *externs;
|
||||||
int nr_extern;
|
int nr_extern;
|
||||||
int extern_map_idx;
|
int kconfig_map_idx;
|
||||||
|
|
||||||
bool loaded;
|
bool loaded;
|
||||||
bool has_pseudo_calls;
|
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.data_shndx = -1;
|
||||||
obj->efile.rodata_shndx = -1;
|
obj->efile.rodata_shndx = -1;
|
||||||
obj->efile.bss_shndx = -1;
|
obj->efile.bss_shndx = -1;
|
||||||
obj->extern_map_idx = -1;
|
obj->kconfig_map_idx = -1;
|
||||||
|
|
||||||
obj->kern_version = get_kernel_version();
|
obj->kern_version = get_kernel_version();
|
||||||
obj->loaded = false;
|
obj->loaded = false;
|
||||||
@ -902,11 +902,25 @@ static size_t bpf_map_mmap_sz(const struct bpf_map *map)
|
|||||||
return map_sz;
|
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
|
static int
|
||||||
bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
|
bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
|
||||||
int sec_idx, void *data, size_t data_sz)
|
int sec_idx, void *data, size_t data_sz)
|
||||||
{
|
{
|
||||||
char map_name[BPF_OBJ_NAME_LEN];
|
|
||||||
struct bpf_map_def *def;
|
struct bpf_map_def *def;
|
||||||
struct bpf_map *map;
|
struct bpf_map *map;
|
||||||
int err;
|
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->libbpf_type = type;
|
||||||
map->sec_idx = sec_idx;
|
map->sec_idx = sec_idx;
|
||||||
map->sec_offset = 0;
|
map->sec_offset = 0;
|
||||||
snprintf(map_name, sizeof(map_name), "%.8s%.7s", obj->name,
|
map->name = internal_map_name(obj, type);
|
||||||
libbpf_type_to_btf_name[type]);
|
|
||||||
map->name = strdup(map_name);
|
|
||||||
if (!map->name) {
|
if (!map->name) {
|
||||||
pr_warn("failed to alloc map name\n");
|
pr_warn("failed to alloc map name\n");
|
||||||
return -ENOMEM;
|
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->key_size = sizeof(int);
|
||||||
def->value_size = data_sz;
|
def->value_size = data_sz;
|
||||||
def->max_entries = 1;
|
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;
|
? BPF_F_RDONLY_PROG : 0;
|
||||||
def->map_flags |= BPF_F_MMAPABLE;
|
def->map_flags |= BPF_F_MMAPABLE;
|
||||||
|
|
||||||
pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n",
|
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->mmaped = mmap(NULL, bpf_map_mmap_sz(map), PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||||
@ -1137,94 +1149,98 @@ static int set_ext_value_num(struct extern_desc *ext, void *ext_val,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_object__read_kernel_config(struct bpf_object *obj,
|
static int bpf_object__process_kconfig_line(struct bpf_object *obj,
|
||||||
const char *config_path,
|
char *buf, void *data)
|
||||||
void *data)
|
|
||||||
{
|
{
|
||||||
char buf[PATH_MAX], *sep, *value;
|
|
||||||
struct extern_desc *ext;
|
struct extern_desc *ext;
|
||||||
|
char *sep, *value;
|
||||||
int len, err = 0;
|
int len, err = 0;
|
||||||
void *ext_val;
|
void *ext_val;
|
||||||
__u64 num;
|
__u64 num;
|
||||||
|
|
||||||
|
if (strncmp(buf, "CONFIG_", 7))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
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;
|
gzFile file;
|
||||||
|
|
||||||
if (config_path) {
|
uname(&uts);
|
||||||
file = gzopen(config_path, "r");
|
len = snprintf(buf, PATH_MAX, "/boot/config-%s", uts.release);
|
||||||
} else {
|
if (len < 0)
|
||||||
struct utsname uts;
|
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");
|
||||||
|
|
||||||
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) {
|
if (!file) {
|
||||||
pr_warn("failed to read kernel config at '%s'\n", config_path);
|
pr_warn("failed to open system Kconfig\n");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (gzgets(file, buf, sizeof(buf))) {
|
while (gzgets(file, buf, sizeof(buf))) {
|
||||||
if (strncmp(buf, "CONFIG_", 7))
|
err = bpf_object__process_kconfig_line(obj, buf, data);
|
||||||
continue;
|
if (err) {
|
||||||
|
pr_warn("error parsing system Kconfig line '%s': %d\n",
|
||||||
sep = strchr(buf, '=');
|
buf, err);
|
||||||
if (!sep) {
|
|
||||||
err = -EINVAL;
|
|
||||||
pr_warn("failed to parse '%s': no separator\n", buf);
|
|
||||||
goto out;
|
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);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
err = set_ext_value_num(ext, ext_val, num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
pr_debug("extern %s=%s\n", ext->name, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -1232,7 +1248,34 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_object__init_extern_map(struct bpf_object *obj)
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bpf_object__init_kconfig_map(struct bpf_object *obj)
|
||||||
{
|
{
|
||||||
struct extern_desc *last_ext;
|
struct extern_desc *last_ext;
|
||||||
size_t map_sz;
|
size_t map_sz;
|
||||||
@ -1244,13 +1287,13 @@ static int bpf_object__init_extern_map(struct bpf_object *obj)
|
|||||||
last_ext = &obj->externs[obj->nr_extern - 1];
|
last_ext = &obj->externs[obj->nr_extern - 1];
|
||||||
map_sz = last_ext->data_off + last_ext->sz;
|
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,
|
obj->efile.symbols_shndx,
|
||||||
NULL, map_sz);
|
NULL, map_sz);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
obj->extern_map_idx = obj->nr_maps - 1;
|
obj->kconfig_map_idx = obj->nr_maps - 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1742,7 +1785,7 @@ static int bpf_object__init_maps(struct bpf_object *obj,
|
|||||||
err = bpf_object__init_user_maps(obj, strict);
|
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_user_btf_maps(obj, strict, pin_root_path);
|
||||||
err = err ?: bpf_object__init_global_data_maps(obj);
|
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)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -1844,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)
|
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,
|
static int bpf_object__init_btf(struct bpf_object *obj,
|
||||||
@ -2269,9 +2313,9 @@ static int bpf_object__collect_externs(struct bpf_object *obj)
|
|||||||
i, ext->sym_idx, ext->data_off, ext->name);
|
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) {
|
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;
|
return -ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2361,7 +2405,7 @@ bpf_object__section_to_libbpf_map_type(const struct bpf_object *obj, int shndx)
|
|||||||
else if (shndx == obj->efile.rodata_shndx)
|
else if (shndx == obj->efile.rodata_shndx)
|
||||||
return LIBBPF_MAP_RODATA;
|
return LIBBPF_MAP_RODATA;
|
||||||
else if (shndx == obj->efile.symbols_shndx)
|
else if (shndx == obj->efile.symbols_shndx)
|
||||||
return LIBBPF_MAP_EXTERN;
|
return LIBBPF_MAP_KCONFIG;
|
||||||
else
|
else
|
||||||
return LIBBPF_MAP_UNSPEC;
|
return LIBBPF_MAP_UNSPEC;
|
||||||
}
|
}
|
||||||
@ -2908,8 +2952,8 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Freeze .rodata and .extern map as read-only from syscall side. */
|
/* Freeze .rodata and .kconfig map as read-only from syscall side. */
|
||||||
if (map_type == LIBBPF_MAP_RODATA || map_type == LIBBPF_MAP_EXTERN) {
|
if (map_type == LIBBPF_MAP_RODATA || map_type == LIBBPF_MAP_KCONFIG) {
|
||||||
err = bpf_map_freeze(map->fd);
|
err = bpf_map_freeze(map->fd);
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
@ -4264,7 +4308,7 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
|
|||||||
break;
|
break;
|
||||||
case RELO_EXTERN:
|
case RELO_EXTERN:
|
||||||
insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;
|
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;
|
insn[1].imm = relo->sym_off;
|
||||||
break;
|
break;
|
||||||
case RELO_CALL:
|
case RELO_CALL:
|
||||||
@ -4555,7 +4599,7 @@ static struct bpf_object *
|
|||||||
__bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
|
__bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
|
||||||
const struct bpf_object_open_opts *opts)
|
const struct bpf_object_open_opts *opts)
|
||||||
{
|
{
|
||||||
const char *obj_name, *kconfig_path;
|
const char *obj_name, *kconfig;
|
||||||
struct bpf_program *prog;
|
struct bpf_program *prog;
|
||||||
struct bpf_object *obj;
|
struct bpf_object *obj;
|
||||||
char tmp_name[64];
|
char tmp_name[64];
|
||||||
@ -4587,10 +4631,10 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
|
|||||||
return obj;
|
return obj;
|
||||||
|
|
||||||
obj->relaxed_core_relocs = OPTS_GET(opts, relaxed_core_relocs, false);
|
obj->relaxed_core_relocs = OPTS_GET(opts, relaxed_core_relocs, false);
|
||||||
kconfig_path = OPTS_GET(opts, kconfig_path, NULL);
|
kconfig = OPTS_GET(opts, kconfig, NULL);
|
||||||
if (kconfig_path) {
|
if (kconfig) {
|
||||||
obj->kconfig_path = strdup(kconfig_path);
|
obj->kconfig = strdup(kconfig);
|
||||||
if (!obj->kconfig_path)
|
if (!obj->kconfig)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4733,7 +4777,7 @@ static int bpf_object__sanitize_maps(struct bpf_object *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_object__resolve_externs(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;
|
bool need_config = false;
|
||||||
struct extern_desc *ext;
|
struct extern_desc *ext;
|
||||||
@ -4743,7 +4787,7 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
|
|||||||
if (obj->nr_extern == 0)
|
if (obj->nr_extern == 0)
|
||||||
return 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++) {
|
for (i = 0; i < obj->nr_extern; i++) {
|
||||||
ext = &obj->externs[i];
|
ext = &obj->externs[i];
|
||||||
@ -4767,8 +4811,21 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
|
|||||||
return -EINVAL;
|
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) {
|
if (need_config) {
|
||||||
err = bpf_object__read_kernel_config(obj, config_path, data);
|
err = bpf_object__read_kconfig_file(obj, data);
|
||||||
if (err)
|
if (err)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -4806,7 +4863,7 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
|
|||||||
obj->loaded = true;
|
obj->loaded = true;
|
||||||
|
|
||||||
err = bpf_object__probe_caps(obj);
|
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_and_load_btf(obj);
|
||||||
err = err ? : bpf_object__sanitize_maps(obj);
|
err = err ? : bpf_object__sanitize_maps(obj);
|
||||||
err = err ? : bpf_object__create_maps(obj);
|
err = err ? : bpf_object__create_maps(obj);
|
||||||
@ -5400,7 +5457,7 @@ void bpf_object__close(struct bpf_object *obj)
|
|||||||
zfree(&map->pin_path);
|
zfree(&map->pin_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
zfree(&obj->kconfig_path);
|
zfree(&obj->kconfig);
|
||||||
zfree(&obj->externs);
|
zfree(&obj->externs);
|
||||||
obj->nr_extern = 0;
|
obj->nr_extern = 0;
|
||||||
|
|
||||||
@ -7546,7 +7603,7 @@ int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* externs shouldn't be pre-setup from user code */
|
/* 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;
|
*mmaped = (*map)->mmaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,12 +85,12 @@ struct bpf_object_open_opts {
|
|||||||
*/
|
*/
|
||||||
const char *pin_root_path;
|
const char *pin_root_path;
|
||||||
__u32 attach_prog_fd;
|
__u32 attach_prog_fd;
|
||||||
/* kernel config file path override (for CONFIG_ externs); can point
|
/* Additional kernel config content that augments and overrides
|
||||||
* to either uncompressed text file or .gz file
|
* 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 *bpf_object__open(const char *path);
|
||||||
LIBBPF_API struct bpf_object *
|
LIBBPF_API struct bpf_object *
|
||||||
|
@ -23,19 +23,13 @@ static uint32_t get_kernel_version(void)
|
|||||||
static struct test_case {
|
static struct test_case {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *cfg;
|
const char *cfg;
|
||||||
const char *cfg_path;
|
|
||||||
bool fails;
|
bool fails;
|
||||||
struct test_core_extern__data data;
|
struct test_core_extern__data data;
|
||||||
} test_cases[] = {
|
} test_cases[] = {
|
||||||
{ .name = "default search path", .cfg_path = NULL,
|
{ .name = "default search path", .data = { .bpf_syscall = true } },
|
||||||
.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 = "custom values",
|
.name = "custom values",
|
||||||
.cfg = "CONFIG_BPF_SYSCALL=y\n"
|
.cfg = "CONFIG_BPF_SYSCALL=n\n"
|
||||||
"CONFIG_TRISTATE=m\n"
|
"CONFIG_TRISTATE=m\n"
|
||||||
"CONFIG_BOOL=y\n"
|
"CONFIG_BOOL=y\n"
|
||||||
"CONFIG_CHAR=100\n"
|
"CONFIG_CHAR=100\n"
|
||||||
@ -45,7 +39,7 @@ static struct test_case {
|
|||||||
"CONFIG_STR=\"abracad\"\n"
|
"CONFIG_STR=\"abracad\"\n"
|
||||||
"CONFIG_MISSING=0",
|
"CONFIG_MISSING=0",
|
||||||
.data = {
|
.data = {
|
||||||
.bpf_syscall = true,
|
.bpf_syscall = false,
|
||||||
.tristate_val = TRI_MODULE,
|
.tristate_val = TRI_MODULE,
|
||||||
.bool_val = true,
|
.bool_val = true,
|
||||||
.char_val = 100,
|
.char_val = 100,
|
||||||
@ -133,30 +127,14 @@ void test_core_extern(void)
|
|||||||
int n = sizeof(*skel->data) / sizeof(uint64_t);
|
int n = sizeof(*skel->data) / sizeof(uint64_t);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
|
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];
|
struct test_case *t = &test_cases[i];
|
||||||
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
|
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
|
||||||
.kconfig_path = t->cfg_path,
|
.kconfig = t->cfg,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!test__start_subtest(t->name))
|
if (!test__start_subtest(t->name))
|
||||||
continue;
|
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);
|
skel = test_core_extern__open_opts(&opts);
|
||||||
if (CHECK(!skel, "skel_open", "skeleton open failed\n"))
|
if (CHECK(!skel, "skel_open", "skeleton open failed\n"))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -185,8 +163,6 @@ void test_core_extern(void)
|
|||||||
j, exp[j], got[j]);
|
j, exp[j], got[j]);
|
||||||
}
|
}
|
||||||
cleanup:
|
cleanup:
|
||||||
if (t->cfg)
|
|
||||||
unlink(tmp_cfg_path);
|
|
||||||
test_core_extern__destroy(skel);
|
test_core_extern__destroy(skel);
|
||||||
skel = NULL;
|
skel = NULL;
|
||||||
}
|
}
|
||||||
|
@ -15,20 +15,18 @@ void test_skeleton(void)
|
|||||||
int duration = 0, err;
|
int duration = 0, err;
|
||||||
struct test_skeleton* skel;
|
struct test_skeleton* skel;
|
||||||
struct test_skeleton__bss *bss;
|
struct test_skeleton__bss *bss;
|
||||||
struct test_skeleton__externs *exts;
|
struct test_skeleton__kconfig *kcfg;
|
||||||
|
|
||||||
skel = test_skeleton__open();
|
skel = test_skeleton__open();
|
||||||
if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
|
if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
printf("EXTERNS BEFORE: %p\n", skel->externs);
|
if (CHECK(skel->kconfig, "skel_kconfig", "kconfig is mmaped()!\n"))
|
||||||
if (CHECK(skel->externs, "skel_externs", "externs are mmaped()!\n"))
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
err = test_skeleton__load(skel);
|
err = test_skeleton__load(skel);
|
||||||
if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
|
if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
printf("EXTERNS AFTER: %p\n", skel->externs);
|
|
||||||
|
|
||||||
bss = skel->bss;
|
bss = skel->bss;
|
||||||
bss->in1 = 1;
|
bss->in1 = 1;
|
||||||
@ -37,7 +35,7 @@ void test_skeleton(void)
|
|||||||
bss->in4 = 4;
|
bss->in4 = 4;
|
||||||
bss->in5.a = 5;
|
bss->in5.a = 5;
|
||||||
bss->in5.b = 6;
|
bss->in5.b = 6;
|
||||||
exts = skel->externs;
|
kcfg = skel->kconfig;
|
||||||
|
|
||||||
err = test_skeleton__attach(skel);
|
err = test_skeleton__attach(skel);
|
||||||
if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
|
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",
|
CHECK(bss->handler_out5.b != 6, "res6", "got %lld != exp %d\n",
|
||||||
bss->handler_out5.b, 6);
|
bss->handler_out5.b, 6);
|
||||||
|
|
||||||
CHECK(bss->bpf_syscall != exts->CONFIG_BPF_SYSCALL, "ext1",
|
CHECK(bss->bpf_syscall != kcfg->CONFIG_BPF_SYSCALL, "ext1",
|
||||||
"got %d != exp %d\n", bss->bpf_syscall, exts->CONFIG_BPF_SYSCALL);
|
"got %d != exp %d\n", bss->bpf_syscall, kcfg->CONFIG_BPF_SYSCALL);
|
||||||
CHECK(bss->kern_ver != exts->LINUX_KERNEL_VERSION, "ext2",
|
CHECK(bss->kern_ver != kcfg->LINUX_KERNEL_VERSION, "ext2",
|
||||||
"got %d != exp %d\n", bss->kern_ver, exts->LINUX_KERNEL_VERSION);
|
"got %d != exp %d\n", bss->kern_ver, kcfg->LINUX_KERNEL_VERSION);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
test_skeleton__destroy(skel);
|
test_skeleton__destroy(skel);
|
||||||
|
@ -10,16 +10,16 @@
|
|||||||
/* non-existing BPF helper, to test dead code elimination */
|
/* non-existing BPF helper, to test dead code elimination */
|
||||||
static int (*bpf_missing_helper)(const void *arg1, int arg2) = (void *) 999;
|
static int (*bpf_missing_helper)(const void *arg1, int arg2) = (void *) 999;
|
||||||
|
|
||||||
extern int LINUX_KERNEL_VERSION;
|
extern int LINUX_KERNEL_VERSION __kconfig;
|
||||||
extern bool CONFIG_BPF_SYSCALL; /* strong */
|
extern bool CONFIG_BPF_SYSCALL __kconfig; /* strong */
|
||||||
extern enum libbpf_tristate CONFIG_TRISTATE __weak;
|
extern enum libbpf_tristate CONFIG_TRISTATE __kconfig __weak;
|
||||||
extern bool CONFIG_BOOL __weak;
|
extern bool CONFIG_BOOL __kconfig __weak;
|
||||||
extern char CONFIG_CHAR __weak;
|
extern char CONFIG_CHAR __kconfig __weak;
|
||||||
extern uint16_t CONFIG_USHORT __weak;
|
extern uint16_t CONFIG_USHORT __kconfig __weak;
|
||||||
extern int CONFIG_INT __weak;
|
extern int CONFIG_INT __kconfig __weak;
|
||||||
extern uint64_t CONFIG_ULONG __weak;
|
extern uint64_t CONFIG_ULONG __kconfig __weak;
|
||||||
extern const char CONFIG_STR[8] __weak;
|
extern const char CONFIG_STR[8] __kconfig __weak;
|
||||||
extern uint64_t CONFIG_MISSING __weak;
|
extern uint64_t CONFIG_MISSING __kconfig __weak;
|
||||||
|
|
||||||
uint64_t kern_ver = -1;
|
uint64_t kern_ver = -1;
|
||||||
uint64_t bpf_syscall = -1;
|
uint64_t bpf_syscall = -1;
|
||||||
|
@ -21,8 +21,8 @@ char out3 = 0;
|
|||||||
long long out4 = 0;
|
long long out4 = 0;
|
||||||
int out1 = 0;
|
int out1 = 0;
|
||||||
|
|
||||||
extern bool CONFIG_BPF_SYSCALL;
|
extern bool CONFIG_BPF_SYSCALL __kconfig;
|
||||||
extern int LINUX_KERNEL_VERSION;
|
extern int LINUX_KERNEL_VERSION __kconfig;
|
||||||
bool bpf_syscall = 0;
|
bool bpf_syscall = 0;
|
||||||
int kern_ver = 0;
|
int kern_ver = 0;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user