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