xref: /linux/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c (revision 06ed6aa56ffac9241e03a24649e8d048f8f1b10c)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <stdio.h>
4 #include <errno.h>
5 #include <string.h>
6 
7 #include <bpf/bpf.h>
8 #include <bpf/libbpf.h>
9 
10 #include <test_maps.h>
11 
12 static void map_batch_update(int map_fd, __u32 max_entries, int *keys,
13 			     int *values)
14 {
15 	int i, err;
16 	DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,
17 		.elem_flags = 0,
18 		.flags = 0,
19 	);
20 
21 	for (i = 0; i < max_entries; i++) {
22 		keys[i] = i;
23 		values[i] = i + 1;
24 	}
25 
26 	err = bpf_map_update_batch(map_fd, keys, values, &max_entries, &opts);
27 	CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno));
28 }
29 
30 static void map_batch_verify(int *visited, __u32 max_entries,
31 			     int *keys, int *values)
32 {
33 	int i;
34 
35 	memset(visited, 0, max_entries * sizeof(*visited));
36 	for (i = 0; i < max_entries; i++) {
37 		CHECK(keys[i] + 1 != values[i], "key/value checking",
38 		      "error: i %d key %d value %d\n", i, keys[i], values[i]);
39 		visited[i] = 1;
40 	}
41 	for (i = 0; i < max_entries; i++) {
42 		CHECK(visited[i] != 1, "visited checking",
43 		      "error: keys array at index %d missing\n", i);
44 	}
45 }
46 
47 void test_array_map_batch_ops(void)
48 {
49 	struct bpf_create_map_attr xattr = {
50 		.name = "array_map",
51 		.map_type = BPF_MAP_TYPE_ARRAY,
52 		.key_size = sizeof(int),
53 		.value_size = sizeof(int),
54 	};
55 	int map_fd, *keys, *values, *visited;
56 	__u32 count, total, total_success;
57 	const __u32 max_entries = 10;
58 	bool nospace_err;
59 	__u64 batch = 0;
60 	int err, step;
61 	DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,
62 		.elem_flags = 0,
63 		.flags = 0,
64 	);
65 
66 	xattr.max_entries = max_entries;
67 	map_fd = bpf_create_map_xattr(&xattr);
68 	CHECK(map_fd == -1,
69 	      "bpf_create_map_xattr()", "error:%s\n", strerror(errno));
70 
71 	keys = malloc(max_entries * sizeof(int));
72 	values = malloc(max_entries * sizeof(int));
73 	visited = malloc(max_entries * sizeof(int));
74 	CHECK(!keys || !values || !visited, "malloc()", "error:%s\n",
75 	      strerror(errno));
76 
77 	/* populate elements to the map */
78 	map_batch_update(map_fd, max_entries, keys, values);
79 
80 	/* test 1: lookup in a loop with various steps. */
81 	total_success = 0;
82 	for (step = 1; step < max_entries; step++) {
83 		map_batch_update(map_fd, max_entries, keys, values);
84 		map_batch_verify(visited, max_entries, keys, values);
85 		memset(keys, 0, max_entries * sizeof(*keys));
86 		memset(values, 0, max_entries * sizeof(*values));
87 		batch = 0;
88 		total = 0;
89 		/* iteratively lookup/delete elements with 'step'
90 		 * elements each.
91 		 */
92 		count = step;
93 		nospace_err = false;
94 		while (true) {
95 			err = bpf_map_lookup_batch(map_fd,
96 						total ? &batch : NULL, &batch,
97 						keys + total,
98 						values + total,
99 						&count, &opts);
100 
101 			CHECK((err && errno != ENOENT), "lookup with steps",
102 			      "error: %s\n", strerror(errno));
103 
104 			total += count;
105 			if (err)
106 				break;
107 
108 		}
109 
110 		if (nospace_err == true)
111 			continue;
112 
113 		CHECK(total != max_entries, "lookup with steps",
114 		      "total = %u, max_entries = %u\n", total, max_entries);
115 
116 		map_batch_verify(visited, max_entries, keys, values);
117 
118 		total_success++;
119 	}
120 
121 	CHECK(total_success == 0, "check total_success",
122 	      "unexpected failure\n");
123 
124 	printf("%s:PASS\n", __func__);
125 
126 	free(keys);
127 	free(values);
128 	free(visited);
129 }
130