пт, 5 июл. 2019 г. в 17:44, Daniel Borkmann <daniel@xxxxxxxxxxxxx>: > > On 07/05/2019 10:44 PM, Anton Protopopov wrote: > > Add a new API bpf_object__reuse_maps() which can be used to replace all maps in > > an object by maps pinned to a directory provided in the path argument. Namely, > > each map M in the object will be replaced by a map pinned to path/M.name. > > > > Signed-off-by: Anton Protopopov <a.s.protopopov@xxxxxxxxx> > > --- > > tools/lib/bpf/libbpf.c | 34 ++++++++++++++++++++++++++++++++++ > > tools/lib/bpf/libbpf.h | 2 ++ > > tools/lib/bpf/libbpf.map | 1 + > > 3 files changed, 37 insertions(+) > > > > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c > > index 4907997289e9..84c9e8f7bfd3 100644 > > --- a/tools/lib/bpf/libbpf.c > > +++ b/tools/lib/bpf/libbpf.c > > @@ -3144,6 +3144,40 @@ int bpf_object__unpin_maps(struct bpf_object *obj, const char *path) > > return 0; > > } > > > > +int bpf_object__reuse_maps(struct bpf_object *obj, const char *path) > > +{ > > + struct bpf_map *map; > > + > > + if (!obj) > > + return -ENOENT; > > + > > + if (!path) > > + return -EINVAL; > > + > > + bpf_object__for_each_map(map, obj) { > > + int len, err; > > + int pinned_map_fd; > > + char buf[PATH_MAX]; > > We'd need to skip the case of bpf_map__is_internal(map) since they are always > recreated for the given object. > > > + len = snprintf(buf, PATH_MAX, "%s/%s", path, bpf_map__name(map)); > > + if (len < 0) { > > + return -EINVAL; > > + } else if (len >= PATH_MAX) { > > + return -ENAMETOOLONG; > > + } > > + > > + pinned_map_fd = bpf_obj_get(buf); > > + if (pinned_map_fd < 0) > > + return pinned_map_fd; > > Should we rather have a new map definition attribute that tells to reuse > the map if it's pinned in bpf fs, and if not, we create it and later on > pin it? This is what iproute2 is doing and which we're making use of heavily. What do you think about adding a new generic field, say load_flags, to the bpf_map_def structure and a particular flag, say LOAD_F_STICKY for this purpose? And it will be cleared for internal maps, so we will skip them as well. > In bpf_object__reuse_maps() bailing out if bpf_obj_get() fails is perhaps > too limiting for a generic API as new version of an object file may contain > new maps which are not yet present in bpf fs at that point. How permissive should it be? Is it ok to just print a warning on any bpf_obj_get() failure? Or does it make sense to skip some specific error (ENOENT) and reject on other errors? > > > + err = bpf_map__reuse_fd(map, pinned_map_fd); > > + if (err) > > + return err; > > + } > > + > > + return 0; > > +} > > + > > int bpf_object__pin_programs(struct bpf_object *obj, const char *path) > > { > > struct bpf_program *prog; > > diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h > > index d639f47e3110..7fe465a1be76 100644 > > --- a/tools/lib/bpf/libbpf.h > > +++ b/tools/lib/bpf/libbpf.h > > @@ -82,6 +82,8 @@ int bpf_object__variable_offset(const struct bpf_object *obj, const char *name, > > LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path); > > LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj, > > const char *path); > > +LIBBPF_API int bpf_object__reuse_maps(struct bpf_object *obj, > > + const char *path); > > LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj, > > const char *path); > > LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj, > > diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map > > index 2c6d835620d2..66a30be6696c 100644 > > --- a/tools/lib/bpf/libbpf.map > > +++ b/tools/lib/bpf/libbpf.map > > @@ -172,5 +172,6 @@ LIBBPF_0.0.4 { > > btf_dump__new; > > btf__parse_elf; > > bpf_object__load_xattr; > > + bpf_object__reuse_maps; > > libbpf_num_possible_cpus; > > } LIBBPF_0.0.3; > > >