1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2021 Facebook */
3 
4 #include <sys/syscall.h>
5 #include <limits.h>
6 #include <test_progs.h>
7 #include "bloom_filter_map.skel.h"
8 
test_fail_cases(void)9 static void test_fail_cases(void)
10 {
11 	LIBBPF_OPTS(bpf_map_create_opts, opts);
12 	__u32 value;
13 	int fd, err;
14 
15 	/* Invalid key size */
16 	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 4, sizeof(value), 100, NULL);
17 	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid key size"))
18 		close(fd);
19 
20 	/* Invalid value size */
21 	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, 0, 100, NULL);
22 	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid value size 0"))
23 		close(fd);
24 
25 	/* Invalid value size: too big */
26 	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, INT32_MAX, 100, NULL);
27 	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid value too large"))
28 		close(fd);
29 
30 	/* Invalid max entries size */
31 	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(value), 0, NULL);
32 	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid max entries size"))
33 		close(fd);
34 
35 	/* Bloom filter maps do not support BPF_F_NO_PREALLOC */
36 	opts.map_flags = BPF_F_NO_PREALLOC;
37 	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(value), 100, &opts);
38 	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid flags"))
39 		close(fd);
40 
41 	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(value), 100, NULL);
42 	if (!ASSERT_GE(fd, 0, "bpf_map_create bloom filter"))
43 		return;
44 
45 	/* Test invalid flags */
46 	err = bpf_map_update_elem(fd, NULL, &value, -1);
47 	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");
48 
49 	err = bpf_map_update_elem(fd, NULL, &value, BPF_EXIST);
50 	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");
51 
52 	err = bpf_map_update_elem(fd, NULL, &value, BPF_F_LOCK);
53 	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");
54 
55 	err = bpf_map_update_elem(fd, NULL, &value, BPF_NOEXIST);
56 	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");
57 
58 	err = bpf_map_update_elem(fd, NULL, &value, 10000);
59 	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");
60 
61 	close(fd);
62 }
63 
test_success_cases(void)64 static void test_success_cases(void)
65 {
66 	LIBBPF_OPTS(bpf_map_create_opts, opts);
67 	char value[11];
68 	int fd, err;
69 
70 	/* Create a map */
71 	opts.map_flags = BPF_F_ZERO_SEED | BPF_F_NUMA_NODE;
72 	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(value), 100, &opts);
73 	if (!ASSERT_GE(fd, 0, "bpf_map_create bloom filter success case"))
74 		return;
75 
76 	/* Add a value to the bloom filter */
77 	err = bpf_map_update_elem(fd, NULL, &value, 0);
78 	if (!ASSERT_OK(err, "bpf_map_update_elem bloom filter success case"))
79 		goto done;
80 
81 	 /* Lookup a value in the bloom filter */
82 	err = bpf_map_lookup_elem(fd, NULL, &value);
83 	ASSERT_OK(err, "bpf_map_update_elem bloom filter success case");
84 
85 done:
86 	close(fd);
87 }
88 
check_bloom(struct bloom_filter_map * skel)89 static void check_bloom(struct bloom_filter_map *skel)
90 {
91 	struct bpf_link *link;
92 
93 	link = bpf_program__attach(skel->progs.check_bloom);
94 	if (!ASSERT_OK_PTR(link, "link"))
95 		return;
96 
97 	syscall(SYS_getpgid);
98 
99 	ASSERT_EQ(skel->bss->error, 0, "error");
100 
101 	bpf_link__destroy(link);
102 }
103 
test_inner_map(struct bloom_filter_map * skel,const __u32 * rand_vals,__u32 nr_rand_vals)104 static void test_inner_map(struct bloom_filter_map *skel, const __u32 *rand_vals,
105 			   __u32 nr_rand_vals)
106 {
107 	int outer_map_fd, inner_map_fd, err, i, key = 0;
108 	struct bpf_link *link;
109 
110 	/* Create a bloom filter map that will be used as the inner map */
111 	inner_map_fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(*rand_vals),
112 				      nr_rand_vals, NULL);
113 	if (!ASSERT_GE(inner_map_fd, 0, "bpf_map_create bloom filter inner map"))
114 		return;
115 
116 	for (i = 0; i < nr_rand_vals; i++) {
117 		err = bpf_map_update_elem(inner_map_fd, NULL, rand_vals + i, BPF_ANY);
118 		if (!ASSERT_OK(err, "Add random value to inner_map_fd"))
119 			goto done;
120 	}
121 
122 	/* Add the bloom filter map to the outer map */
123 	outer_map_fd = bpf_map__fd(skel->maps.outer_map);
124 	err = bpf_map_update_elem(outer_map_fd, &key, &inner_map_fd, BPF_ANY);
125 	if (!ASSERT_OK(err, "Add bloom filter map to outer map"))
126 		goto done;
127 
128 	/* Attach the bloom_filter_inner_map prog */
129 	link = bpf_program__attach(skel->progs.inner_map);
130 	if (!ASSERT_OK_PTR(link, "link"))
131 		goto delete_inner_map;
132 
133 	syscall(SYS_getpgid);
134 
135 	ASSERT_EQ(skel->bss->error, 0, "error");
136 
137 	bpf_link__destroy(link);
138 
139 delete_inner_map:
140 	/* Ensure the inner bloom filter map can be deleted */
141 	err = bpf_map_delete_elem(outer_map_fd, &key);
142 	ASSERT_OK(err, "Delete inner bloom filter map");
143 
144 done:
145 	close(inner_map_fd);
146 }
147 
setup_progs(struct bloom_filter_map ** out_skel,__u32 ** out_rand_vals,__u32 * out_nr_rand_vals)148 static int setup_progs(struct bloom_filter_map **out_skel, __u32 **out_rand_vals,
149 		       __u32 *out_nr_rand_vals)
150 {
151 	struct bloom_filter_map *skel;
152 	int random_data_fd, bloom_fd;
153 	__u32 *rand_vals = NULL;
154 	__u32 map_size, val;
155 	int err, i;
156 
157 	/* Set up a bloom filter map skeleton */
158 	skel = bloom_filter_map__open_and_load();
159 	if (!ASSERT_OK_PTR(skel, "bloom_filter_map__open_and_load"))
160 		return -EINVAL;
161 
162 	/* Set up rand_vals */
163 	map_size = bpf_map__max_entries(skel->maps.map_random_data);
164 	rand_vals = malloc(sizeof(*rand_vals) * map_size);
165 	if (!rand_vals) {
166 		err = -ENOMEM;
167 		goto error;
168 	}
169 
170 	/* Generate random values and populate both skeletons */
171 	random_data_fd = bpf_map__fd(skel->maps.map_random_data);
172 	bloom_fd = bpf_map__fd(skel->maps.map_bloom);
173 	for (i = 0; i < map_size; i++) {
174 		val = rand();
175 
176 		err = bpf_map_update_elem(random_data_fd, &i, &val, BPF_ANY);
177 		if (!ASSERT_OK(err, "Add random value to map_random_data"))
178 			goto error;
179 
180 		err = bpf_map_update_elem(bloom_fd, NULL, &val, BPF_ANY);
181 		if (!ASSERT_OK(err, "Add random value to map_bloom"))
182 			goto error;
183 
184 		rand_vals[i] = val;
185 	}
186 
187 	*out_skel = skel;
188 	*out_rand_vals = rand_vals;
189 	*out_nr_rand_vals = map_size;
190 
191 	return 0;
192 
193 error:
194 	bloom_filter_map__destroy(skel);
195 	if (rand_vals)
196 		free(rand_vals);
197 	return err;
198 }
199 
test_bloom_filter_map(void)200 void test_bloom_filter_map(void)
201 {
202 	__u32 *rand_vals, nr_rand_vals;
203 	struct bloom_filter_map *skel;
204 	int err;
205 
206 	test_fail_cases();
207 	test_success_cases();
208 
209 	err = setup_progs(&skel, &rand_vals, &nr_rand_vals);
210 	if (err)
211 		return;
212 
213 	test_inner_map(skel, rand_vals, nr_rand_vals);
214 	free(rand_vals);
215 
216 	check_bloom(skel);
217 
218 	bloom_filter_map__destroy(skel);
219 }
220