[RFC PATCH 2/7] perf tools: Add API to apply config to BPF map

From: Wang Nan
Date: Sat Oct 17 2015 - 06:51:18 EST


bpf__apply_config() is introduced as the core API to apply config
options to all BPF objects. This patch also does the real work for
setting values for BPF_MAP_TYPE_PERF_ARRAY maps by inserting value
stored in map's private field into the BPF map.

This patch is required because we are not always able to set all
BPF config during parsing. Further patch will set events created
by perf to BPF_MAP_TYPE_PERF_EVENT_ARRAY maps, which is not exist
until perf_evsel__open().

bpf_map_foreach_key() is introduced to iterate over each key
needs to be configured. This function would be extended to support
more map types and different key settings.

Signed-off-by: Wang Nan <wangnan0@xxxxxxxxxx>
Signed-off-by: He Kuang <hekuang@xxxxxxxxxx>
Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
Cc: Alexei Starovoitov <ast@xxxxxxxxxxxx>
Cc: Brendan Gregg <brendan.d.gregg@xxxxxxxxx>
Cc: Daniel Borkmann <daniel@xxxxxxxxxxxxx>
Cc: David Ahern <dsahern@xxxxxxxxx>
Cc: He Kuang <hekuang@xxxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Kaixu Xia <xiakaixu@xxxxxxxxxx>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@xxxxxxxxxxx>
Cc: Namhyung Kim <namhyung@xxxxxxxxxx>
Cc: Paul Mackerras <paulus@xxxxxxxxx>
Cc: Peter Zijlstra <a.p.zijlstra@xxxxxxxxx>
Cc: Zefan Li <lizefan@xxxxxxxxxx>
Cc: pi3orama@xxxxxxx
Link: http://lkml.kernel.org/n/ebpf-tmg65cm1zaf1zxs7zmvxmxp4@xxxxxxxxxxxxxx
---
tools/perf/util/bpf-loader.c | 163 +++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/bpf-loader.h | 15 ++++
2 files changed, 178 insertions(+)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index a5a1c36..15cf27a 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -7,6 +7,7 @@

#include <linux/bpf.h>
#include <bpf/libbpf.h>
+#include <bpf/bpf.h>
#include <linux/err.h>
#include "perf.h"
#include "debug.h"
@@ -666,6 +667,69 @@ bpf_map_priv__clear(struct bpf_map *map __maybe_unused,
}

static int
+bpf_map_config_foreach_key(struct bpf_map *map,
+ int (*func)(const char *name,
+ int map_fd,
+ struct bpf_map_def *pdef,
+ struct bpf_map_priv *priv,
+ void *pkey, void *arg),
+ void *arg)
+{
+ unsigned int i;
+ int err, map_fd;
+ const char *name;
+ struct bpf_map_def def;
+ struct bpf_map_priv *priv;
+
+ name = bpf_map__get_name(map);
+
+ err = bpf_map__get_private(map, (void **)&priv);
+ if (err) {
+ pr_debug("ERROR: failed to get private from map %s\n", name);
+ return -EINVAL;
+ }
+ if (!priv) {
+ pr_debug("INFO: nothing to config for map %s\n", name);
+ return 0;
+ }
+
+ err = bpf_map__get_def(map, &def);
+ if (err) {
+ pr_debug("ERROR: failed to get definition from map %s\n", name);
+ return -EINVAL;
+ }
+ map_fd = bpf_map__get_fd(map);
+ if (map_fd < 0) {
+ pr_debug("ERROR: failed to get fd from map %s\n", name);
+ return map_fd;
+ }
+
+ switch (def.type) {
+ case BPF_MAP_TYPE_ARRAY:
+ switch (priv->key.type) {
+ case BPF_MAP_PRIV_KEY_ALL:
+ for (i = 0; i < def.max_entries; i++) {
+ err = (*func)(name, map_fd, &def,
+ priv, &i, arg);
+ if (err) {
+ pr_debug("ERROR: failed to insert value to %s[%u]\n",
+ name, i);
+ return err;
+ }
+ }
+ return 0;
+ default:
+ pr_debug("ERROR: keytype for map '%s' invalid\n", name);
+ return -EINVAL;
+ }
+ default:
+ pr_debug("ERROR: type of '%s' incorrect\n", name);
+ return -EINVAL;
+ }
+}
+
+
+static int
bpf__config_obj_map_array_value(struct bpf_map *map,
struct parse_events_term *term)
{
@@ -799,6 +863,97 @@ int bpf__config_obj(struct bpf_object *obj,
return -ENODEV;
}

+static int
+bpf__apply_config_value_for_key(int map_fd, void *pkey,
+ size_t val_size, u64 val)
+{
+ int err = 0;
+
+ switch (val_size) {
+ case 1: {
+ u8 _val = (u8)(val);
+ err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
+ break;
+ }
+ case 2: {
+ u16 _val = (u16)(val);
+ err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
+ break;
+ }
+ case 4: {
+ u32 _val = (u32)(val);
+ err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
+ break;
+ }
+ case 8: {
+ err = bpf_map_update_elem(map_fd, pkey, &val, BPF_ANY);
+ break;
+ }
+ default:
+ pr_debug("ERROR: internal error: invalid value size\n");
+ return -EINVAL;
+ }
+ if (err && errno)
+ err = -errno;
+ return err;
+}
+
+static int
+bpf__apply_config_map_for_key(const char *name, int map_fd,
+ struct bpf_map_def *pdef __maybe_unused,
+ struct bpf_map_priv *priv,
+ void *pkey, void *arg __maybe_unused)
+{
+ int err;
+
+ switch (priv->value.type) {
+ case BPF_MAP_PRIV_VAL_VALUE:
+ err = bpf__apply_config_value_for_key(map_fd, pkey,
+ pdef->value_size,
+ priv->value.val);
+ break;
+ default:
+ pr_debug("ERROR: unknown value type for '%s'\n", name);
+ err = -EINVAL;
+ }
+ return err;
+}
+
+static int
+bpf__apply_config_map(struct bpf_map *map)
+{
+ return bpf_map_config_foreach_key(map, bpf__apply_config_map_for_key,
+ NULL);
+}
+
+static int
+bpf__apply_config_object(struct bpf_object *obj)
+{
+ struct bpf_map *map;
+ int err;
+
+ bpf_map__for_each(map, obj) {
+ err = bpf__apply_config_map(map);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+int bpf__apply_config(void)
+{
+ struct bpf_object *obj, *tmp;
+ int err;
+
+ bpf_object__for_each_safe(obj, tmp) {
+ err = bpf__apply_config_object(obj);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
#define bpf__strerror_head(err, buf, size) \
char sbuf[STRERR_BUFSIZE], *emsg;\
if (!size)\
@@ -855,3 +1010,11 @@ int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
bpf__strerror_end(buf, size);
return 0;
}
+
+int bpf__strerror_apply_config(int err, char *buf, size_t size)
+{
+ bpf__strerror_head(err, buf, size);
+ bpf__strerror_entry(EINVAL, "Invalid option for map, add -v to see detail");
+ bpf__strerror_end(buf, size);
+ return 0;
+}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index dfec9b8..c9c515e 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -43,6 +43,8 @@ int bpf__strerror_config_obj(struct bpf_object *obj,
struct parse_events_term *term,
struct perf_evlist *evlist,
int err, char *buf, size_t size);
+int bpf__apply_config(void);
+int bpf__strerror_apply_config(int err, char *buf, size_t size);
#else
static inline struct bpf_object *
bpf__prepare_load(const char *filename __maybe_unused,
@@ -82,6 +84,12 @@ bpf__config_obj(struct bpf_object *obj __maybe_unused,
}

static inline int
+bpf__apply_config(void)
+{
+ return 0;
+}
+
+static inline int
__bpf_strerror(char *buf, size_t size)
{
if (!size)
@@ -117,5 +125,12 @@ bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
{
return __bpf_strerror(buf, size);
}
+
+static inline int
+bpf__strerror_apply_config(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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/