diff options
author | Wang Nan <wangnan0@huawei.com> | 2015-11-27 03:47:35 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-11-27 19:57:09 -0500 |
commit | 9d759a9b4ac2690077d8b21258e6e95c3e34bfa9 (patch) | |
tree | 184e9f95a010e1a883e83962189b742173ffd30a /tools/lib | |
parent | 039050482573e168690d365b8ea1d4f599ebbbd8 (diff) |
tools lib bpf: Collect map definition in bpf_object
This patch collects more information from maps sections in BPF object
files into 'struct bpf_object', enables later patches access those
information (such as the type and size of the map).
In this patch, a new handler 'struct bpf_map' is extracted in parallel
with bpf_object and bpf_program. Its iterator and accessor is also
created.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1448614067-197576-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/lib')
-rw-r--r-- | tools/lib/bpf/libbpf.c | 187 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.h | 21 |
2 files changed, 148 insertions, 60 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index e3f4c3379f14..f50982579aa8 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -163,22 +163,24 @@ struct bpf_program { | |||
163 | bpf_program_clear_priv_t clear_priv; | 163 | bpf_program_clear_priv_t clear_priv; |
164 | }; | 164 | }; |
165 | 165 | ||
166 | struct bpf_map { | ||
167 | int fd; | ||
168 | struct bpf_map_def def; | ||
169 | void *priv; | ||
170 | bpf_map_clear_priv_t clear_priv; | ||
171 | }; | ||
172 | |||
166 | static LIST_HEAD(bpf_objects_list); | 173 | static LIST_HEAD(bpf_objects_list); |
167 | 174 | ||
168 | struct bpf_object { | 175 | struct bpf_object { |
169 | char license[64]; | 176 | char license[64]; |
170 | u32 kern_version; | 177 | u32 kern_version; |
171 | void *maps_buf; | ||
172 | size_t maps_buf_sz; | ||
173 | 178 | ||
174 | struct bpf_program *programs; | 179 | struct bpf_program *programs; |
175 | size_t nr_programs; | 180 | size_t nr_programs; |
176 | int *map_fds; | 181 | struct bpf_map *maps; |
177 | /* | 182 | size_t nr_maps; |
178 | * This field is required because maps_buf will be freed and | 183 | |
179 | * maps_buf_sz will be set to 0 after loaded. | ||
180 | */ | ||
181 | size_t nr_map_fds; | ||
182 | bool loaded; | 184 | bool loaded; |
183 | 185 | ||
184 | /* | 186 | /* |
@@ -489,21 +491,38 @@ static int | |||
489 | bpf_object__init_maps(struct bpf_object *obj, void *data, | 491 | bpf_object__init_maps(struct bpf_object *obj, void *data, |
490 | size_t size) | 492 | size_t size) |
491 | { | 493 | { |
492 | if (size == 0) { | 494 | size_t nr_maps; |
495 | int i; | ||
496 | |||
497 | nr_maps = size / sizeof(struct bpf_map_def); | ||
498 | if (!data || !nr_maps) { | ||
493 | pr_debug("%s doesn't need map definition\n", | 499 | pr_debug("%s doesn't need map definition\n", |
494 | obj->path); | 500 | obj->path); |
495 | return 0; | 501 | return 0; |
496 | } | 502 | } |
497 | 503 | ||
498 | obj->maps_buf = malloc(size); | 504 | pr_debug("maps in %s: %zd bytes\n", obj->path, size); |
499 | if (!obj->maps_buf) { | 505 | |
500 | pr_warning("malloc maps failed: %s\n", obj->path); | 506 | obj->maps = calloc(nr_maps, sizeof(obj->maps[0])); |
507 | if (!obj->maps) { | ||
508 | pr_warning("alloc maps for object failed\n"); | ||
501 | return -ENOMEM; | 509 | return -ENOMEM; |
502 | } | 510 | } |
511 | obj->nr_maps = nr_maps; | ||
512 | |||
513 | for (i = 0; i < nr_maps; i++) { | ||
514 | struct bpf_map_def *def = &obj->maps[i].def; | ||
503 | 515 | ||
504 | obj->maps_buf_sz = size; | 516 | /* |
505 | memcpy(obj->maps_buf, data, size); | 517 | * fill all fd with -1 so won't close incorrect |
506 | pr_debug("maps in %s: %ld bytes\n", obj->path, (long)size); | 518 | * fd (fd=0 is stdin) when failure (zclose won't close |
519 | * negative fd)). | ||
520 | */ | ||
521 | obj->maps[i].fd = -1; | ||
522 | |||
523 | /* Save map definition into obj->maps */ | ||
524 | *def = ((struct bpf_map_def *)data)[i]; | ||
525 | } | ||
507 | return 0; | 526 | return 0; |
508 | } | 527 | } |
509 | 528 | ||
@@ -688,37 +707,15 @@ static int | |||
688 | bpf_object__create_maps(struct bpf_object *obj) | 707 | bpf_object__create_maps(struct bpf_object *obj) |
689 | { | 708 | { |
690 | unsigned int i; | 709 | unsigned int i; |
691 | size_t nr_maps; | ||
692 | int *pfd; | ||
693 | |||
694 | nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def); | ||
695 | if (!obj->maps_buf || !nr_maps) { | ||
696 | pr_debug("don't need create maps for %s\n", | ||
697 | obj->path); | ||
698 | return 0; | ||
699 | } | ||
700 | 710 | ||
701 | obj->map_fds = malloc(sizeof(int) * nr_maps); | 711 | for (i = 0; i < obj->nr_maps; i++) { |
702 | if (!obj->map_fds) { | 712 | struct bpf_map_def *def = &obj->maps[i].def; |
703 | pr_warning("realloc perf_bpf_map_fds failed\n"); | 713 | int *pfd = &obj->maps[i].fd; |
704 | return -ENOMEM; | ||
705 | } | ||
706 | obj->nr_map_fds = nr_maps; | ||
707 | |||
708 | /* fill all fd with -1 */ | ||
709 | memset(obj->map_fds, -1, sizeof(int) * nr_maps); | ||
710 | 714 | ||
711 | pfd = obj->map_fds; | 715 | *pfd = bpf_create_map(def->type, |
712 | for (i = 0; i < nr_maps; i++) { | 716 | def->key_size, |
713 | struct bpf_map_def def; | 717 | def->value_size, |
714 | 718 | def->max_entries); | |
715 | def = *(struct bpf_map_def *)(obj->maps_buf + | ||
716 | i * sizeof(struct bpf_map_def)); | ||
717 | |||
718 | *pfd = bpf_create_map(def.type, | ||
719 | def.key_size, | ||
720 | def.value_size, | ||
721 | def.max_entries); | ||
722 | if (*pfd < 0) { | 719 | if (*pfd < 0) { |
723 | size_t j; | 720 | size_t j; |
724 | int err = *pfd; | 721 | int err = *pfd; |
@@ -726,22 +723,17 @@ bpf_object__create_maps(struct bpf_object *obj) | |||
726 | pr_warning("failed to create map: %s\n", | 723 | pr_warning("failed to create map: %s\n", |
727 | strerror(errno)); | 724 | strerror(errno)); |
728 | for (j = 0; j < i; j++) | 725 | for (j = 0; j < i; j++) |
729 | zclose(obj->map_fds[j]); | 726 | zclose(obj->maps[j].fd); |
730 | obj->nr_map_fds = 0; | ||
731 | zfree(&obj->map_fds); | ||
732 | return err; | 727 | return err; |
733 | } | 728 | } |
734 | pr_debug("create map: fd=%d\n", *pfd); | 729 | pr_debug("create map: fd=%d\n", *pfd); |
735 | pfd++; | ||
736 | } | 730 | } |
737 | 731 | ||
738 | zfree(&obj->maps_buf); | ||
739 | obj->maps_buf_sz = 0; | ||
740 | return 0; | 732 | return 0; |
741 | } | 733 | } |
742 | 734 | ||
743 | static int | 735 | static int |
744 | bpf_program__relocate(struct bpf_program *prog, int *map_fds) | 736 | bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) |
745 | { | 737 | { |
746 | int i; | 738 | int i; |
747 | 739 | ||
@@ -761,7 +753,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds) | |||
761 | return -LIBBPF_ERRNO__RELOC; | 753 | return -LIBBPF_ERRNO__RELOC; |
762 | } | 754 | } |
763 | insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; | 755 | insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; |
764 | insns[insn_idx].imm = map_fds[map_idx]; | 756 | insns[insn_idx].imm = obj->maps[map_idx].fd; |
765 | } | 757 | } |
766 | 758 | ||
767 | zfree(&prog->reloc_desc); | 759 | zfree(&prog->reloc_desc); |
@@ -780,7 +772,7 @@ bpf_object__relocate(struct bpf_object *obj) | |||
780 | for (i = 0; i < obj->nr_programs; i++) { | 772 | for (i = 0; i < obj->nr_programs; i++) { |
781 | prog = &obj->programs[i]; | 773 | prog = &obj->programs[i]; |
782 | 774 | ||
783 | err = bpf_program__relocate(prog, obj->map_fds); | 775 | err = bpf_program__relocate(prog, obj); |
784 | if (err) { | 776 | if (err) { |
785 | pr_warning("failed to relocate '%s'\n", | 777 | pr_warning("failed to relocate '%s'\n", |
786 | prog->section_name); | 778 | prog->section_name); |
@@ -804,8 +796,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) | |||
804 | Elf_Data *data = obj->efile.reloc[i].data; | 796 | Elf_Data *data = obj->efile.reloc[i].data; |
805 | int idx = shdr->sh_info; | 797 | int idx = shdr->sh_info; |
806 | struct bpf_program *prog; | 798 | struct bpf_program *prog; |
807 | size_t nr_maps = obj->maps_buf_sz / | 799 | size_t nr_maps = obj->nr_maps; |
808 | sizeof(struct bpf_map_def); | ||
809 | 800 | ||
810 | if (shdr->sh_type != SHT_REL) { | 801 | if (shdr->sh_type != SHT_REL) { |
811 | pr_warning("internal error at %d\n", __LINE__); | 802 | pr_warning("internal error at %d\n", __LINE__); |
@@ -1050,10 +1041,8 @@ int bpf_object__unload(struct bpf_object *obj) | |||
1050 | if (!obj) | 1041 | if (!obj) |
1051 | return -EINVAL; | 1042 | return -EINVAL; |
1052 | 1043 | ||
1053 | for (i = 0; i < obj->nr_map_fds; i++) | 1044 | for (i = 0; i < obj->nr_maps; i++) |
1054 | zclose(obj->map_fds[i]); | 1045 | zclose(obj->maps[i].fd); |
1055 | zfree(&obj->map_fds); | ||
1056 | obj->nr_map_fds = 0; | ||
1057 | 1046 | ||
1058 | for (i = 0; i < obj->nr_programs; i++) | 1047 | for (i = 0; i < obj->nr_programs; i++) |
1059 | bpf_program__unload(&obj->programs[i]); | 1048 | bpf_program__unload(&obj->programs[i]); |
@@ -1096,7 +1085,15 @@ void bpf_object__close(struct bpf_object *obj) | |||
1096 | bpf_object__elf_finish(obj); | 1085 | bpf_object__elf_finish(obj); |
1097 | bpf_object__unload(obj); | 1086 | bpf_object__unload(obj); |
1098 | 1087 | ||
1099 | zfree(&obj->maps_buf); | 1088 | for (i = 0; i < obj->nr_maps; i++) { |
1089 | if (obj->maps[i].clear_priv) | ||
1090 | obj->maps[i].clear_priv(&obj->maps[i], | ||
1091 | obj->maps[i].priv); | ||
1092 | obj->maps[i].priv = NULL; | ||
1093 | obj->maps[i].clear_priv = NULL; | ||
1094 | } | ||
1095 | zfree(&obj->maps); | ||
1096 | obj->nr_maps = 0; | ||
1100 | 1097 | ||
1101 | if (obj->programs && obj->nr_programs) { | 1098 | if (obj->programs && obj->nr_programs) { |
1102 | for (i = 0; i < obj->nr_programs; i++) | 1099 | for (i = 0; i < obj->nr_programs; i++) |
@@ -1251,3 +1248,73 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n) | |||
1251 | 1248 | ||
1252 | return fd; | 1249 | return fd; |
1253 | } | 1250 | } |
1251 | |||
1252 | int bpf_map__get_fd(struct bpf_map *map) | ||
1253 | { | ||
1254 | if (!map) | ||
1255 | return -EINVAL; | ||
1256 | |||
1257 | return map->fd; | ||
1258 | } | ||
1259 | |||
1260 | int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef) | ||
1261 | { | ||
1262 | if (!map || !pdef) | ||
1263 | return -EINVAL; | ||
1264 | |||
1265 | *pdef = map->def; | ||
1266 | return 0; | ||
1267 | } | ||
1268 | |||
1269 | int bpf_map__set_private(struct bpf_map *map, void *priv, | ||
1270 | bpf_map_clear_priv_t clear_priv) | ||
1271 | { | ||
1272 | if (!map) | ||
1273 | return -EINVAL; | ||
1274 | |||
1275 | if (map->priv) { | ||
1276 | if (map->clear_priv) | ||
1277 | map->clear_priv(map, map->priv); | ||
1278 | } | ||
1279 | |||
1280 | map->priv = priv; | ||
1281 | map->clear_priv = clear_priv; | ||
1282 | return 0; | ||
1283 | } | ||
1284 | |||
1285 | int bpf_map__get_private(struct bpf_map *map, void **ppriv) | ||
1286 | { | ||
1287 | if (!map) | ||
1288 | return -EINVAL; | ||
1289 | |||
1290 | if (ppriv) | ||
1291 | *ppriv = map->priv; | ||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | struct bpf_map * | ||
1296 | bpf_map__next(struct bpf_map *prev, struct bpf_object *obj) | ||
1297 | { | ||
1298 | size_t idx; | ||
1299 | struct bpf_map *s, *e; | ||
1300 | |||
1301 | if (!obj || !obj->maps) | ||
1302 | return NULL; | ||
1303 | |||
1304 | s = obj->maps; | ||
1305 | e = obj->maps + obj->nr_maps; | ||
1306 | |||
1307 | if (prev == NULL) | ||
1308 | return s; | ||
1309 | |||
1310 | if ((prev < s) || (prev >= e)) { | ||
1311 | pr_warning("error in %s: map handler doesn't belong to object\n", | ||
1312 | __func__); | ||
1313 | return NULL; | ||
1314 | } | ||
1315 | |||
1316 | idx = (prev - obj->maps) + 1; | ||
1317 | if (idx >= obj->nr_maps) | ||
1318 | return NULL; | ||
1319 | return &obj->maps[idx]; | ||
1320 | } | ||
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 949df4b346cf..ef631255dfaa 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h | |||
@@ -165,4 +165,25 @@ struct bpf_map_def { | |||
165 | unsigned int max_entries; | 165 | unsigned int max_entries; |
166 | }; | 166 | }; |
167 | 167 | ||
168 | /* | ||
169 | * There is another 'struct bpf_map' in include/linux/map.h. However, | ||
170 | * it is not a uapi header so no need to consider name clash. | ||
171 | */ | ||
172 | struct bpf_map; | ||
173 | |||
174 | struct bpf_map * | ||
175 | bpf_map__next(struct bpf_map *map, struct bpf_object *obj); | ||
176 | #define bpf_map__for_each(pos, obj) \ | ||
177 | for ((pos) = bpf_map__next(NULL, (obj)); \ | ||
178 | (pos) != NULL; \ | ||
179 | (pos) = bpf_map__next((pos), (obj))) | ||
180 | |||
181 | int bpf_map__get_fd(struct bpf_map *map); | ||
182 | int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef); | ||
183 | |||
184 | typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); | ||
185 | int bpf_map__set_private(struct bpf_map *map, void *priv, | ||
186 | bpf_map_clear_priv_t clear_priv); | ||
187 | int bpf_map__get_private(struct bpf_map *map, void **ppriv); | ||
188 | |||
168 | #endif | 189 | #endif |