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
9static 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
64static 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
85done:
86	close(fd);
87}
88
89static 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
104static 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
139delete_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
144done:
145	close(inner_map_fd);
146}
147
148static 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
193error:
194	bloom_filter_map__destroy(skel);
195	if (rand_vals)
196		free(rand_vals);
197	return err;
198}
199
200void test_bloom_filter_map(void)
201{
202	__u32 *rand_vals = NULL, nr_rand_vals = 0;
203	struct bloom_filter_map *skel = NULL;
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