bpf__config_obj() is introduced as a core API to config BPF object
after loading. One configuration option of maps is introduced. After
this patch BPF object can accept configuration like:

 maps.my_pmy.event=evt

Where evt is a predefined event with alias "evt".

Signed-off-by: Wang Nan <wangn...@huawei.com>
Signed-off-by: He Kuang <heku...@huawei.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Alexei Starovoitov <a...@plumgrid.com>
Cc: Brendan Gregg <brendan.d.gr...@gmail.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David Ahern <dsah...@gmail.com>
Cc: He Kuang <heku...@huawei.com>
Cc: Jiri Olsa <jo...@kernel.org>
Cc: Kaixu Xia <xiaka...@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu...@hitachi.com>
Cc: Namhyung Kim <namhy...@kernel.org>
Cc: Paul Mackerras <pau...@samba.org>
Cc: Peter Zijlstra <a.p.zijls...@chello.nl>
Cc: Zefan Li <lize...@huawei.com>
Cc: pi3or...@163.com
Link: http://lkml.kernel.org/n/ebpf-36xcrahy9n0ayc05mu7aa...@git.kernel.org
---
 tools/perf/util/bpf-loader.c | 147 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h |  39 ++++++++++++
 2 files changed, 186 insertions(+)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 73ff9a9..b92c2f7 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -10,6 +10,7 @@
 #include <linux/err.h>
 #include "perf.h"
 #include "debug.h"
+#include "util.h"
 #include "bpf-loader.h"
 #include "bpf-prologue.h"
 #include "llvm-utils.h"
@@ -633,6 +634,139 @@ int bpf__foreach_tev(struct bpf_object *obj,
        return 0;
 }
 
+struct bpf_map_priv {
+       struct perf_evsel *evsel;
+};
+
+static void
+bpf_map_priv__clear(struct bpf_map *map __maybe_unused,
+                   void *_priv)
+{
+       struct bpf_map_priv *priv = _priv;
+
+       free(priv);
+}
+
+static int
+bpf__config_obj_map_event(struct bpf_map *map, const char *val,
+                         struct perf_evlist *evlist)
+{
+       struct bpf_map_priv *priv;
+       struct perf_evsel *evsel;
+       struct bpf_map_def def;
+       const char *map_name;
+       int err;
+
+       map_name = bpf_map__get_name(map);
+
+       evsel = perf_evlist__find_evsel_by_alias(evlist, val);
+       if (!evsel) {
+               pr_debug("Event '%s' doesn't exist\n", val);
+               return -EINVAL;
+       }
+
+       err = bpf_map__get_def(map, &def);
+       if (err) {
+               pr_debug("Unable to get map definition from '%s'\n",
+                        map_name);
+               return -EINVAL;
+       }
+
+       if (def.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
+               pr_debug("Map %s type is not BPF_MAP_TYPE_PERF_EVENT_ARRAY\n",
+                        map_name);
+               return -EINVAL;
+       }
+
+       priv = calloc(sizeof(*priv), 1);
+       if (!priv) {
+               pr_debug("No enough memory to alloc map private\n");
+               return -ENOMEM;
+       }
+
+       priv->evsel = evsel;
+       return bpf_map__set_private(map, priv, bpf_map_priv__clear);
+}
+
+struct bpf_config_map_func {
+       const char *config_opt;
+       int (*config_func)(struct bpf_map *, const char *,
+                          struct perf_evlist *);
+};
+
+struct bpf_config_map_func bpf_config_map_funcs[] = {
+       {"event", bpf__config_obj_map_event},
+};
+
+static int
+bpf__config_obj_map(struct bpf_object *obj,
+                   const char *key,
+                   const char *val,
+                   struct perf_evlist *evlist)
+{
+       /* key is "maps.<mapname>.<config opt>" */
+       char *map_name = strdup(key + sizeof("maps.") - 1);
+       struct bpf_map *map;
+       int err = -ENOENT;
+       char *map_opt;
+       size_t i;
+
+       if (!map_name)
+               return -ENOMEM;
+
+       map_opt = strchr(map_name, '.');
+       if (!map_opt) {
+               pr_debug("ERROR: Invalid map config: %s\n", map_name);
+               goto out;
+       }
+
+       *map_opt++ = '\0';
+       if (*map_opt == '\0') {
+               pr_debug("ERROR: Invalid map option: %s\n", key);
+               goto out;
+       }
+
+       map = bpf_object__get_map_by_name(obj, map_name);
+       if (!map) {
+               pr_debug("ERROR: Map %s doesn't exist\n", map_name);
+               goto out;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(bpf_config_map_funcs); i++) {
+               struct bpf_config_map_func *func = &bpf_config_map_funcs[i];
+
+               if (strcmp(map_opt, func->config_opt) == 0) {
+                       err = func->config_func(map, val, evlist);
+                       goto out;
+               }
+       }
+
+       pr_debug("ERROR: invalid config option '%s' for maps\n",
+                map_opt);
+       err = -ENOENT;
+out:
+       free(map_name);
+       return err;
+}
+
+int bpf__config_obj(struct bpf_object *obj,
+                   const char *key,
+                   struct bpf_config_val *val,
+                   struct perf_evlist *evlist)
+{
+       if (!obj || !key || !val)
+               return -ENODEV;
+
+       if (!prefixcmp(key, "maps.")) {
+               if (val->type != BPF_CONFIG_VAL_STRING) {
+                       pr_debug("ERROR: incorrect value type\n");
+                       return -EINVAL;
+               }
+               return bpf__config_obj_map(obj, key, val->string, evlist);
+       }
+       return -ENODEV;
+}
+
 #define bpf__strerror_head(err, buf, size) \
        char sbuf[STRERR_BUFSIZE], *emsg;\
        if (!size)\
@@ -675,3 +809,16 @@ int bpf__strerror_load(struct bpf_object *obj 
__maybe_unused,
        bpf__strerror_end(buf, size);
        return 0;
 }
+
+int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
+                            const char *key, struct bpf_config_val *val,
+                            struct perf_evlist *evlist __maybe_unused,
+                            int err, char *buf, size_t size)
+{
+       bpf__strerror_head(err, buf, size);
+       bpf__strerror_entry(ENODEV, "Invalid config option: '%s'", key)
+       bpf__strerror_entry(ENOENT, "Config target in '%s' is invalid", key)
+       bpf__strerror_entry(EINVAL, "Invalid config value %s", val)
+       bpf__strerror_end(buf, size);
+       return 0;
+}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index d8f1945..4c99b21 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -9,6 +9,7 @@
 #include <linux/err.h>
 #include <string.h>
 #include "probe-event.h"
+#include "evlist.h"
 #include "debug.h"
 
 struct bpf_object;
@@ -17,6 +18,17 @@ struct bpf_object;
 typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
                                        int fd, void *arg);
 
+struct bpf_config_val {
+       enum {
+               BPF_CONFIG_VAL_STRING,
+               BPF_CONFIG_VAL_NUM,
+       } type;
+       union {
+               const char *string;
+               unsigned long long num;
+       };
+};
+
 #ifdef HAVE_LIBBPF_SUPPORT
 struct bpf_object *bpf__prepare_load(const char *filename, bool source);
 struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
@@ -34,6 +46,13 @@ int bpf__strerror_load(struct bpf_object *obj, int err,
                       char *buf, size_t size);
 int bpf__foreach_tev(struct bpf_object *obj,
                     bpf_prog_iter_callback_t func, void *arg);
+
+int bpf__config_obj(struct bpf_object *obj, const char *key,
+                   struct bpf_config_val *val, struct perf_evlist *evlist);
+int bpf__strerror_config_obj(struct bpf_object *obj,
+                            const char *key, struct bpf_config_val *val,
+                            struct perf_evlist *evlist,
+                            int err, char *buf, size_t size);
 #else
 static inline struct bpf_object *
 bpf__prepare_load(const char *filename __maybe_unused,
@@ -65,6 +84,15 @@ bpf__foreach_tev(struct bpf_object *obj __maybe_unused,
 }
 
 static inline int
+bpf__config_obj(struct bpf_object *obj __maybe_unused,
+               const char *key __maybe_unused,
+               struct bpf_config_val *val __maybe_unused,
+               struct perf_evlist *evlist __maybe_unused)
+{
+       return 0;
+}
+
+static inline int
 __bpf_strerror(char *buf, size_t size)
 {
        if (!size)
@@ -90,5 +118,16 @@ static inline int bpf__strerror_load(struct bpf_object *obj 
__maybe_unused,
 {
        return __bpf_strerror(buf, size);
 }
+
+static inline int
+bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
+                        const char *key __maybe_unused,
+                        struct bpf_config_val *val __maybe_unused,
+                        struct perf_evlist *evlist __maybe_unused,
+                        int err __maybe_unused,
+                        char *buf, size_t size)
+{
+       return __bpf_strerror(buf, size);
+}
 #endif
 #endif
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to