summaryrefslogtreecommitdiffstats
path: root/tools/bpf
diff options
context:
space:
mode:
authorOkash Khawaja <osk@fb.com>2018-07-14 00:57:04 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-07-14 07:00:40 -0400
commit2d3feca8c44f315624b7c0f5b8361e2f54405c12 (patch)
treef1c1babdff4bf4d249818c588cb86afac4fc67f4 /tools/bpf
parentb12d6ec09730b2646e85c348e599b592348dd0e3 (diff)
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup commands to print data along side btf info, if the correspondin btf info is available. The outputs for each of map dump and map lookup commands are augmented in two ways: 1. when neither of -j and -p are supplied, btf-ful map data is printed whose aim is human readability. This means no commitments for json- or backward- compatibility. 2. when either -j or -p are supplied, a new json object named "formatted" is added for each key-value pair. This object contains the same data as the key-value pair, but with btf info. "formatted" object promises json- and backward- compatibility. Below is a sample output. $ bpftool map dump -p id 8 [{ "key": ["0x0f","0x00","0x00","0x00" ], "value": ["0x03", "0x00", "0x00", "0x00", ... ], "formatted": { "key": 15, "value": { "int_field": 3, ... } } } ] This patch calls btf_dumper introduced in previous patch to accomplish the above. Indeed, btf-ful info is only displayed if btf data for the given map is available. Otherwise existing output is displayed as-is. Signed-off-by: Okash Khawaja <osk@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'tools/bpf')
-rw-r--r--tools/bpf/bpftool/map.c217
1 files changed, 201 insertions, 16 deletions
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index e2baec1122fb..9c8191845585 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -34,6 +34,7 @@
34#include <assert.h> 34#include <assert.h>
35#include <errno.h> 35#include <errno.h>
36#include <fcntl.h> 36#include <fcntl.h>
37#include <linux/err.h>
37#include <stdbool.h> 38#include <stdbool.h>
38#include <stdio.h> 39#include <stdio.h>
39#include <stdlib.h> 40#include <stdlib.h>
@@ -44,6 +45,8 @@
44 45
45#include <bpf.h> 46#include <bpf.h>
46 47
48#include "btf.h"
49#include "json_writer.h"
47#include "main.h" 50#include "main.h"
48 51
49static const char * const map_type_name[] = { 52static const char * const map_type_name[] = {
@@ -148,8 +151,109 @@ int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
148 return fd; 151 return fd;
149} 152}
150 153
154static int do_dump_btf(const struct btf_dumper *d,
155 struct bpf_map_info *map_info, void *key,
156 void *value)
157{
158 int ret;
159
160 /* start of key-value pair */
161 jsonw_start_object(d->jw);
162
163 jsonw_name(d->jw, "key");
164
165 ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
166 if (ret)
167 goto err_end_obj;
168
169 jsonw_name(d->jw, "value");
170
171 ret = btf_dumper_type(d, map_info->btf_value_type_id, value);
172
173err_end_obj:
174 /* end of key-value pair */
175 jsonw_end_object(d->jw);
176
177 return ret;
178}
179
180static int get_btf(struct bpf_map_info *map_info, struct btf **btf)
181{
182 struct bpf_btf_info btf_info = { 0 };
183 __u32 len = sizeof(btf_info);
184 __u32 last_size;
185 int btf_fd;
186 void *ptr;
187 int err;
188
189 err = 0;
190 *btf = NULL;
191 btf_fd = bpf_btf_get_fd_by_id(map_info->btf_id);
192 if (btf_fd < 0)
193 return 0;
194
195 /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so
196 * let's start with a sane default - 4KiB here - and resize it only if
197 * bpf_obj_get_info_by_fd() needs a bigger buffer.
198 */
199 btf_info.btf_size = 4096;
200 last_size = btf_info.btf_size;
201 ptr = malloc(last_size);
202 if (!ptr) {
203 err = -ENOMEM;
204 goto exit_free;
205 }
206
207 bzero(ptr, last_size);
208 btf_info.btf = ptr_to_u64(ptr);
209 err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
210
211 if (!err && btf_info.btf_size > last_size) {
212 void *temp_ptr;
213
214 last_size = btf_info.btf_size;
215 temp_ptr = realloc(ptr, last_size);
216 if (!temp_ptr) {
217 err = -ENOMEM;
218 goto exit_free;
219 }
220 ptr = temp_ptr;
221 bzero(ptr, last_size);
222 btf_info.btf = ptr_to_u64(ptr);
223 err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
224 }
225
226 if (err || btf_info.btf_size > last_size) {
227 err = errno;
228 goto exit_free;
229 }
230
231 *btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL);
232 if (IS_ERR(*btf)) {
233 err = PTR_ERR(btf);
234 *btf = NULL;
235 }
236
237exit_free:
238 close(btf_fd);
239 free(ptr);
240
241 return err;
242}
243
244static json_writer_t *get_btf_writer(void)
245{
246 json_writer_t *jw = jsonw_new(stdout);
247
248 if (!jw)
249 return NULL;
250 jsonw_pretty(jw, true);
251
252 return jw;
253}
254
151static void print_entry_json(struct bpf_map_info *info, unsigned char *key, 255static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
152 unsigned char *value) 256 unsigned char *value, struct btf *btf)
153{ 257{
154 jsonw_start_object(json_wtr); 258 jsonw_start_object(json_wtr);
155 259
@@ -158,6 +262,16 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
158 print_hex_data_json(key, info->key_size); 262 print_hex_data_json(key, info->key_size);
159 jsonw_name(json_wtr, "value"); 263 jsonw_name(json_wtr, "value");
160 print_hex_data_json(value, info->value_size); 264 print_hex_data_json(value, info->value_size);
265 if (btf) {
266 struct btf_dumper d = {
267 .btf = btf,
268 .jw = json_wtr,
269 .is_plain_text = false,
270 };
271
272 jsonw_name(json_wtr, "formatted");
273 do_dump_btf(&d, info, key, value);
274 }
161 } else { 275 } else {
162 unsigned int i, n; 276 unsigned int i, n;
163 277
@@ -508,10 +622,12 @@ static int do_show(int argc, char **argv)
508 622
509static int do_dump(int argc, char **argv) 623static int do_dump(int argc, char **argv)
510{ 624{
625 struct bpf_map_info info = {};
511 void *key, *value, *prev_key; 626 void *key, *value, *prev_key;
512 unsigned int num_elems = 0; 627 unsigned int num_elems = 0;
513 struct bpf_map_info info = {};
514 __u32 len = sizeof(info); 628 __u32 len = sizeof(info);
629 json_writer_t *btf_wtr;
630 struct btf *btf = NULL;
515 int err; 631 int err;
516 int fd; 632 int fd;
517 633
@@ -537,8 +653,27 @@ static int do_dump(int argc, char **argv)
537 } 653 }
538 654
539 prev_key = NULL; 655 prev_key = NULL;
656
657 err = get_btf(&info, &btf);
658 if (err) {
659 p_err("failed to get btf");
660 goto exit_free;
661 }
662
540 if (json_output) 663 if (json_output)
541 jsonw_start_array(json_wtr); 664 jsonw_start_array(json_wtr);
665 else
666 if (btf) {
667 btf_wtr = get_btf_writer();
668 if (!btf_wtr) {
669 p_info("failed to create json writer for btf. falling back to plain output");
670 btf__free(btf);
671 btf = NULL;
672 } else {
673 jsonw_start_array(btf_wtr);
674 }
675 }
676
542 while (true) { 677 while (true) {
543 err = bpf_map_get_next_key(fd, prev_key, key); 678 err = bpf_map_get_next_key(fd, prev_key, key);
544 if (err) { 679 if (err) {
@@ -549,9 +684,19 @@ static int do_dump(int argc, char **argv)
549 684
550 if (!bpf_map_lookup_elem(fd, key, value)) { 685 if (!bpf_map_lookup_elem(fd, key, value)) {
551 if (json_output) 686 if (json_output)
552 print_entry_json(&info, key, value); 687 print_entry_json(&info, key, value, btf);
553 else 688 else
554 print_entry_plain(&info, key, value); 689 if (btf) {
690 struct btf_dumper d = {
691 .btf = btf,
692 .jw = btf_wtr,
693 .is_plain_text = true,
694 };
695
696 do_dump_btf(&d, &info, key, value);
697 } else {
698 print_entry_plain(&info, key, value);
699 }
555 } else { 700 } else {
556 if (json_output) { 701 if (json_output) {
557 jsonw_name(json_wtr, "key"); 702 jsonw_name(json_wtr, "key");
@@ -574,14 +719,19 @@ static int do_dump(int argc, char **argv)
574 719
575 if (json_output) 720 if (json_output)
576 jsonw_end_array(json_wtr); 721 jsonw_end_array(json_wtr);
577 else 722 else if (btf) {
723 jsonw_end_array(btf_wtr);
724 jsonw_destroy(&btf_wtr);
725 } else {
578 printf("Found %u element%s\n", num_elems, 726 printf("Found %u element%s\n", num_elems,
579 num_elems != 1 ? "s" : ""); 727 num_elems != 1 ? "s" : "");
728 }
580 729
581exit_free: 730exit_free:
582 free(key); 731 free(key);
583 free(value); 732 free(value);
584 close(fd); 733 close(fd);
734 btf__free(btf);
585 735
586 return err; 736 return err;
587} 737}
@@ -637,6 +787,8 @@ static int do_lookup(int argc, char **argv)
637{ 787{
638 struct bpf_map_info info = {}; 788 struct bpf_map_info info = {};
639 __u32 len = sizeof(info); 789 __u32 len = sizeof(info);
790 json_writer_t *btf_wtr;
791 struct btf *btf = NULL;
640 void *key, *value; 792 void *key, *value;
641 int err; 793 int err;
642 int fd; 794 int fd;
@@ -661,27 +813,60 @@ static int do_lookup(int argc, char **argv)
661 goto exit_free; 813 goto exit_free;
662 814
663 err = bpf_map_lookup_elem(fd, key, value); 815 err = bpf_map_lookup_elem(fd, key, value);
664 if (!err) { 816 if (err) {
665 if (json_output) 817 if (errno == ENOENT) {
666 print_entry_json(&info, key, value); 818 if (json_output) {
667 else 819 jsonw_null(json_wtr);
820 } else {
821 printf("key:\n");
822 fprint_hex(stdout, key, info.key_size, " ");
823 printf("\n\nNot found\n");
824 }
825 } else {
826 p_err("lookup failed: %s", strerror(errno));
827 }
828
829 goto exit_free;
830 }
831
832 /* here means bpf_map_lookup_elem() succeeded */
833 err = get_btf(&info, &btf);
834 if (err) {
835 p_err("failed to get btf");
836 goto exit_free;
837 }
838
839 if (json_output) {
840 print_entry_json(&info, key, value, btf);
841 } else if (btf) {
842 /* if here json_wtr wouldn't have been initialised,
843 * so let's create separate writer for btf
844 */
845 btf_wtr = get_btf_writer();
846 if (!btf_wtr) {
847 p_info("failed to create json writer for btf. falling back to plain output");
848 btf__free(btf);
849 btf = NULL;
668 print_entry_plain(&info, key, value); 850 print_entry_plain(&info, key, value);
669 } else if (errno == ENOENT) {
670 if (json_output) {
671 jsonw_null(json_wtr);
672 } else { 851 } else {
673 printf("key:\n"); 852 struct btf_dumper d = {
674 fprint_hex(stdout, key, info.key_size, " "); 853 .btf = btf,
675 printf("\n\nNot found\n"); 854 .jw = btf_wtr,
855 .is_plain_text = true,
856 };
857
858 do_dump_btf(&d, &info, key, value);
859 jsonw_destroy(&btf_wtr);
676 } 860 }
677 } else { 861 } else {
678 p_err("lookup failed: %s", strerror(errno)); 862 print_entry_plain(&info, key, value);
679 } 863 }
680 864
681exit_free: 865exit_free:
682 free(key); 866 free(key);
683 free(value); 867 free(value);
684 close(fd); 868 close(fd);
869 btf__free(btf);
685 870
686 return err; 871 return err;
687} 872}