xref: /linux/tools/testing/selftests/bpf/prog_tests/bpftool_map_dump.c (revision a8471eb0747f083ae5bde949e667d3d799d65cf7)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <sys/socket.h>
3 #include <unistd.h>
4 #include <bpf/btf.h>
5 #include <test_progs.h>
6 #include "bpftool_helpers.h"
7 
8 #define PIN_PATH	"/sys/fs/bpf/test_bpftool_map_dump_sk_storage"
9 #define QUEUE_PIN_PATH	"/sys/fs/bpf/test_bpftool_map_dump_queue"
10 #define JSON_ERROR	"{\"error\":\"can't dump sk_storage map"
11 
12 /* An empty socket storage map with an int value. */
13 static int create_sk_storage_map(void)
14 {
15 	LIBBPF_OPTS(bpf_map_create_opts, opts,
16 		    .map_flags = BPF_F_NO_PREALLOC);
17 	struct btf *btf;
18 	int int_id, fd = -1;
19 
20 	btf = btf__new_empty();
21 	if (!ASSERT_OK_PTR(btf, "btf__new_empty"))
22 		return -1;
23 
24 	int_id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
25 	if (!ASSERT_GT(int_id, 0, "btf__add_int"))
26 		goto out;
27 	if (!ASSERT_OK(btf__load_into_kernel(btf), "btf__load_into_kernel"))
28 		goto out;
29 
30 	opts.btf_fd = btf__fd(btf);
31 	opts.btf_key_type_id = int_id;
32 	opts.btf_value_type_id = int_id;
33 	fd = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "sk_storage", sizeof(int),
34 			    sizeof(int), 0, &opts);
35 	ASSERT_OK_FD(fd, "bpf_map_create");
36 out:
37 	btf__free(btf);
38 	return fd;
39 }
40 
41 static void test_sk_storage(void)
42 {
43 	int map_fd, sk_fd = -1, value = 42, ret;
44 	char output[1024] = {};
45 
46 	map_fd = create_sk_storage_map();
47 	if (map_fd < 0)
48 		return;
49 
50 	sk_fd = socket(AF_INET, SOCK_STREAM, 0);
51 	if (!ASSERT_OK_FD(sk_fd, "socket"))
52 		goto out;
53 	if (!ASSERT_OK(bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_NOEXIST),
54 		       "add socket storage"))
55 		goto out;
56 	if (!ASSERT_OK(bpf_obj_pin(map_fd, PIN_PATH), "pin map"))
57 		goto out;
58 
59 	/*
60 	 * Socket storage can't be iterated, so the dump must fail with an
61 	 * error and nothing else, rather than print an empty map that holds
62 	 * an element. The buffer is cleared before each run so that a run
63 	 * that fails to start can't match stale or uninitialised output.
64 	 */
65 	ret = get_bpftool_command_output("-j map dump pinned " PIN_PATH,
66 					 output, sizeof(output));
67 	ASSERT_NEQ(ret, 0, "json dump fails");
68 	ASSERT_STRNEQ(output, JSON_ERROR, strlen(JSON_ERROR),
69 		      "json dump is only the error");
70 
71 	memset(output, 0, sizeof(output));
72 	ret = get_bpftool_command_output("map dump pinned " PIN_PATH,
73 					 output, sizeof(output));
74 	ASSERT_NEQ(ret, 0, "plain dump fails");
75 	ASSERT_NULL(strchr(output, '['), "plain dump prints no elements");
76 
77 	memset(output, 0, sizeof(output));
78 	get_bpftool_command_output("map dump pinned " PIN_PATH " 2>&1 >/dev/null",
79 				   output, sizeof(output));
80 	ASSERT_HAS_SUBSTR(output,
81 			  "can't dump sk_storage map: Operation not supported",
82 			  "plain dump explains why on stderr");
83 
84 out:
85 	unlink(PIN_PATH);
86 	if (sk_fd >= 0)
87 		close(sk_fd);
88 	close(map_fd);
89 }
90 
91 /*
92  * A queue map has no BTF, so its plain dump prints an element count
93  * rather than JSON. A dump that ignored the error would print "Found 0
94  * elements" for a queue that holds one.
95  */
96 static void test_queue(void)
97 {
98 	char output[1024] = {};
99 	int map_fd, value = 42, ret;
100 
101 	map_fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, "queue", 0, sizeof(int), 1,
102 				NULL);
103 	if (!ASSERT_OK_FD(map_fd, "bpf_map_create"))
104 		return;
105 	if (!ASSERT_OK(bpf_map_update_elem(map_fd, NULL, &value, BPF_ANY),
106 		       "push to queue"))
107 		goto out;
108 	if (!ASSERT_OK(bpf_obj_pin(map_fd, QUEUE_PIN_PATH), "pin map"))
109 		goto out;
110 
111 	ret = get_bpftool_command_output("map dump pinned " QUEUE_PIN_PATH,
112 					 output, sizeof(output));
113 	ASSERT_NEQ(ret, 0, "plain dump fails");
114 	ASSERT_NULL(strstr(output, "Found"), "plain dump prints no count");
115 
116 	memset(output, 0, sizeof(output));
117 	get_bpftool_command_output("map dump pinned " QUEUE_PIN_PATH " 2>&1 >/dev/null",
118 				   output, sizeof(output));
119 	ASSERT_HAS_SUBSTR(output, "can't dump queue map",
120 			  "plain dump explains why on stderr");
121 
122 out:
123 	unlink(QUEUE_PIN_PATH);
124 	close(map_fd);
125 }
126 
127 void test_bpftool_map_dump(void)
128 {
129 	if (test__start_subtest("sk_storage"))
130 		test_sk_storage();
131 	if (test__start_subtest("queue"))
132 		test_queue();
133 }
134