Skip to content

Commit 2ce8450

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
libbpf: add bpf_object__open_{file, mem} w/ extensible opts
Add new set of bpf_object__open APIs using new approach to optional parameters extensibility allowing simpler ABI compatibility approach. This patch demonstrates an approach to implementing libbpf APIs that makes it easy to extend existing APIs with extra optional parameters in such a way, that ABI compatibility is preserved without having to do symbol versioning and generating lots of boilerplate code to handle it. To facilitate succinct code for working with options, add OPTS_VALID, OPTS_HAS, and OPTS_GET macros that hide all the NULL, size, and zero checks. Additionally, newly added libbpf APIs are encouraged to follow similar pattern of having all mandatory parameters as formal function parameters and always have optional (NULL-able) xxx_opts struct, which should always have real struct size as a first field and the rest would be optional parameters added over time, which tune the behavior of existing API, if specified by user. Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 5e61f27 commit 2ce8450

File tree

4 files changed

+146
-22
lines changed

4 files changed

+146
-22
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,8 @@ static __u32 get_kernel_version(void)
505505

506506
static struct bpf_object *bpf_object__new(const char *path,
507507
const void *obj_buf,
508-
size_t obj_buf_sz)
508+
size_t obj_buf_sz,
509+
const char *obj_name)
509510
{
510511
struct bpf_object *obj;
511512
char *end;
@@ -517,11 +518,17 @@ static struct bpf_object *bpf_object__new(const char *path,
517518
}
518519

519520
strcpy(obj->path, path);
520-
/* Using basename() GNU version which doesn't modify arg. */
521-
strncpy(obj->name, basename((void *)path), sizeof(obj->name) - 1);
522-
end = strchr(obj->name, '.');
523-
if (end)
524-
*end = 0;
521+
if (obj_name) {
522+
strncpy(obj->name, obj_name, sizeof(obj->name) - 1);
523+
obj->name[sizeof(obj->name) - 1] = 0;
524+
} else {
525+
/* Using basename() GNU version which doesn't modify arg. */
526+
strncpy(obj->name, basename((void *)path),
527+
sizeof(obj->name) - 1);
528+
end = strchr(obj->name, '.');
529+
if (end)
530+
*end = 0;
531+
}
525532

526533
obj->efile.fd = -1;
527534
/*
@@ -3547,7 +3554,7 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level)
35473554

35483555
static struct bpf_object *
35493556
__bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
3550-
int flags)
3557+
const char *obj_name, int flags)
35513558
{
35523559
struct bpf_object *obj;
35533560
int err;
@@ -3557,7 +3564,7 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
35573564
return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
35583565
}
35593566

3560-
obj = bpf_object__new(path, obj_buf, obj_buf_sz);
3567+
obj = bpf_object__new(path, obj_buf, obj_buf_sz, obj_name);
35613568
if (IS_ERR(obj))
35623569
return obj;
35633570

@@ -3583,7 +3590,7 @@ __bpf_object__open_xattr(struct bpf_object_open_attr *attr, int flags)
35833590

35843591
pr_debug("loading %s\n", attr->file);
35853592

3586-
return __bpf_object__open(attr->file, NULL, 0, flags);
3593+
return __bpf_object__open(attr->file, NULL, 0, NULL, flags);
35873594
}
35883595

35893596
struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
@@ -3601,25 +3608,67 @@ struct bpf_object *bpf_object__open(const char *path)
36013608
return bpf_object__open_xattr(&attr);
36023609
}
36033610

3604-
struct bpf_object *bpf_object__open_buffer(void *obj_buf,
3605-
size_t obj_buf_sz,
3606-
const char *name)
3611+
struct bpf_object *
3612+
bpf_object__open_file(const char *path, struct bpf_object_open_opts *opts)
3613+
{
3614+
const char *obj_name;
3615+
bool relaxed_maps;
3616+
3617+
if (!OPTS_VALID(opts, bpf_object_open_opts))
3618+
return ERR_PTR(-EINVAL);
3619+
if (!path)
3620+
return ERR_PTR(-EINVAL);
3621+
3622+
pr_debug("loading %s\n", path);
3623+
3624+
obj_name = OPTS_GET(opts, object_name, path);
3625+
relaxed_maps = OPTS_GET(opts, relaxed_maps, false);
3626+
return __bpf_object__open(path, NULL, 0, obj_name,
3627+
relaxed_maps ? MAPS_RELAX_COMPAT : 0);
3628+
}
3629+
3630+
struct bpf_object *
3631+
bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz,
3632+
struct bpf_object_open_opts *opts)
36073633
{
36083634
char tmp_name[64];
3635+
const char *obj_name;
3636+
bool relaxed_maps;
36093637

3610-
/* param validation */
3611-
if (!obj_buf || obj_buf_sz <= 0)
3612-
return NULL;
3638+
if (!OPTS_VALID(opts, bpf_object_open_opts))
3639+
return ERR_PTR(-EINVAL);
3640+
if (!obj_buf || obj_buf_sz == 0)
3641+
return ERR_PTR(-EINVAL);
36133642

3614-
if (!name) {
3643+
obj_name = OPTS_GET(opts, object_name, NULL);
3644+
if (!obj_name) {
36153645
snprintf(tmp_name, sizeof(tmp_name), "%lx-%lx",
36163646
(unsigned long)obj_buf,
36173647
(unsigned long)obj_buf_sz);
3618-
name = tmp_name;
3648+
obj_name = tmp_name;
36193649
}
3620-
pr_debug("loading object '%s' from buffer\n", name);
3650+
pr_debug("loading object '%s' from buffer\n", obj_name);
3651+
3652+
relaxed_maps = OPTS_GET(opts, relaxed_maps, false);
3653+
return __bpf_object__open(obj_name, obj_buf, obj_buf_sz, obj_name,
3654+
relaxed_maps ? MAPS_RELAX_COMPAT : 0);
3655+
}
3656+
3657+
struct bpf_object *
3658+
bpf_object__open_buffer(const void *obj_buf, size_t obj_buf_sz,
3659+
const char *name)
3660+
{
3661+
LIBBPF_OPTS(bpf_object_open_opts, opts,
3662+
.object_name = name,
3663+
/* wrong default, but backwards-compatible */
3664+
.relaxed_maps = true,
3665+
);
3666+
3667+
/* returning NULL is wrong, but backwards-compatible */
3668+
if (!obj_buf || obj_buf_sz == 0)
3669+
return NULL;
36213670

3622-
return __bpf_object__open(name, obj_buf, obj_buf_sz, true);
3671+
return bpf_object__open_mem(obj_buf, obj_buf_sz, &opts);
36233672
}
36243673

36253674
int bpf_object__unload(struct bpf_object *obj)

tools/lib/bpf/libbpf.h

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,52 @@ struct bpf_object_open_attr {
6767
enum bpf_prog_type prog_type;
6868
};
6969

70+
/* Helper macro to declare and initialize libbpf options struct
71+
*
72+
* This dance with uninitialized declaration, followed by memset to zero,
73+
* followed by assignment using compound literal syntax is done to preserve
74+
* ability to use a nice struct field initialization syntax and **hopefully**
75+
* have all the padding bytes initialized to zero. It's not guaranteed though,
76+
* when copying literal, that compiler won't copy garbage in literal's padding
77+
* bytes, but that's the best way I've found and it seems to work in practice.
78+
*/
79+
#define LIBBPF_OPTS(TYPE, NAME, ...) \
80+
struct TYPE NAME; \
81+
memset(&NAME, 0, sizeof(struct TYPE)); \
82+
NAME = (struct TYPE) { \
83+
.sz = sizeof(struct TYPE), \
84+
__VA_ARGS__ \
85+
}
86+
87+
struct bpf_object_open_opts {
88+
/* size of this struct, for forward/backward compatiblity */
89+
size_t sz;
90+
/* object name override, if provided:
91+
* - for object open from file, this will override setting object
92+
* name from file path's base name;
93+
* - for object open from memory buffer, this will specify an object
94+
* name and will override default "<addr>-<buf-size>" name;
95+
*/
96+
const char *object_name;
97+
/* parse map definitions non-strictly, allowing extra attributes/data */
98+
bool relaxed_maps;
99+
};
100+
#define bpf_object_open_opts__last_field relaxed_maps
101+
70102
LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
71103
LIBBPF_API struct bpf_object *
104+
bpf_object__open_file(const char *path, struct bpf_object_open_opts *opts);
105+
LIBBPF_API struct bpf_object *
106+
bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz,
107+
struct bpf_object_open_opts *opts);
108+
109+
/* deprecated bpf_object__open variants */
110+
LIBBPF_API struct bpf_object *
111+
bpf_object__open_buffer(const void *obj_buf, size_t obj_buf_sz,
112+
const char *name);
113+
LIBBPF_API struct bpf_object *
72114
bpf_object__open_xattr(struct bpf_object_open_attr *attr);
73-
LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf,
74-
size_t obj_buf_sz,
75-
const char *name);
115+
76116
int bpf_object__section_size(const struct bpf_object *obj, const char *name,
77117
__u32 *size);
78118
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,

tools/lib/bpf/libbpf.map

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,4 +192,7 @@ LIBBPF_0.0.5 {
192192
} LIBBPF_0.0.4;
193193

194194
LIBBPF_0.0.6 {
195+
global:
196+
bpf_object__open_file;
197+
bpf_object__open_mem;
195198
} LIBBPF_0.0.5;

tools/lib/bpf/libbpf_internal.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,38 @@ do { \
4747
#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)
4848
#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)
4949

50+
static inline bool libbpf_validate_opts(const char *opts,
51+
size_t opts_sz, size_t user_sz,
52+
const char *type_name)
53+
{
54+
if (user_sz < sizeof(size_t)) {
55+
pr_warning("%s size (%zu) is too small\n", type_name, user_sz);
56+
return false;
57+
}
58+
if (user_sz > opts_sz) {
59+
size_t i;
60+
61+
for (i = opts_sz; i < user_sz; i++) {
62+
if (opts[i]) {
63+
pr_warning("%s has non-zero extra bytes",
64+
type_name);
65+
return false;
66+
}
67+
}
68+
}
69+
return true;
70+
}
71+
72+
#define OPTS_VALID(opts, type) \
73+
(!(opts) || libbpf_validate_opts((const char *)opts, \
74+
offsetofend(struct type, \
75+
type##__last_field), \
76+
(opts)->sz, #type))
77+
#define OPTS_HAS(opts, field) \
78+
((opts) && opts->sz >= offsetofend(typeof(*(opts)), field))
79+
#define OPTS_GET(opts, field, fallback_value) \
80+
(OPTS_HAS(opts, field) ? (opts)->field : fallback_value)
81+
5082
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
5183
const char *str_sec, size_t str_len);
5284

0 commit comments

Comments
 (0)