aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/testing/selftests/bpf/prog_tests/bloom_filter_map.c
blob: 053f4d6da77a48f84d86263358c5c329bb6f0beb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2021 Facebook */

#include <sys/syscall.h>
#include <test_progs.h>
#include "bloom_filter_map.skel.h"

static void test_fail_cases(void)
{
	LIBBPF_OPTS(bpf_map_create_opts, opts);
	__u32 value;
	int fd, err;

	/* Invalid key size */
	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 4, sizeof(value), 100, NULL);
	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid key size"))
		close(fd);

	/* Invalid value size */
	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, 0, 100, NULL);
	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid value size 0"))
		close(fd);

	/* Invalid max entries size */
	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(value), 0, NULL);
	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid max entries size"))
		close(fd);

	/* Bloom filter maps do not support BPF_F_NO_PREALLOC */
	opts.map_flags = BPF_F_NO_PREALLOC;
	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(value), 100, &opts);
	if (!ASSERT_LT(fd, 0, "bpf_map_create bloom filter invalid flags"))
		close(fd);

	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(value), 100, NULL);
	if (!ASSERT_GE(fd, 0, "bpf_map_create bloom filter"))
		return;

	/* Test invalid flags */
	err = bpf_map_update_elem(fd, NULL, &value, -1);
	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");

	err = bpf_map_update_elem(fd, NULL, &value, BPF_EXIST);
	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");

	err = bpf_map_update_elem(fd, NULL, &value, BPF_F_LOCK);
	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");

	err = bpf_map_update_elem(fd, NULL, &value, BPF_NOEXIST);
	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");

	err = bpf_map_update_elem(fd, NULL, &value, 10000);
	ASSERT_EQ(err, -EINVAL, "bpf_map_update_elem bloom filter invalid flags");

	close(fd);
}

static void test_success_cases(void)
{
	LIBBPF_OPTS(bpf_map_create_opts, opts);
	char value[11];
	int fd, err;

	/* Create a map */
	opts.map_flags = BPF_F_ZERO_SEED | BPF_F_NUMA_NODE;
	fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(value), 100, &opts);
	if (!ASSERT_GE(fd, 0, "bpf_map_create bloom filter success case"))
		return;

	/* Add a value to the bloom filter */
	err = bpf_map_update_elem(fd, NULL, &value, 0);
	if (!ASSERT_OK(err, "bpf_map_update_elem bloom filter success case"))
		goto done;

	 /* Lookup a value in the bloom filter */
	err = bpf_map_lookup_elem(fd, NULL, &value);
	ASSERT_OK(err, "bpf_map_update_elem bloom filter success case");

done:
	close(fd);
}

static void check_bloom(struct bloom_filter_map *skel)
{
	struct bpf_link *link;

	link = bpf_program__attach(skel->progs.check_bloom);
	if (!ASSERT_OK_PTR(link, "link"))
		return;

	syscall(SYS_getpgid);

	ASSERT_EQ(skel->bss->error, 0, "error");

	bpf_link__destroy(link);
}

static void test_inner_map(struct bloom_filter_map *skel, const __u32 *rand_vals,
			   __u32 nr_rand_vals)
{
	int outer_map_fd, inner_map_fd, err, i, key = 0;
	struct bpf_link *link;

	/* Create a bloom filter map that will be used as the inner map */
	inner_map_fd = bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, NULL, 0, sizeof(*rand_vals),
				      nr_rand_vals, NULL);
	if (!ASSERT_GE(inner_map_fd, 0, "bpf_map_create bloom filter inner map"))
		return;

	for (i = 0; i < nr_rand_vals; i++) {
		err = bpf_map_update_elem(inner_map_fd, NULL, rand_vals + i, BPF_ANY);
		if (!ASSERT_OK(err, "Add random value to inner_map_fd"))
			goto done;
	}

	/* Add the bloom filter map to the outer map */
	outer_map_fd = bpf_map__fd(skel->maps.outer_map);
	err = bpf_map_update_elem(outer_map_fd, &key, &inner_map_fd, BPF_ANY);
	if (!ASSERT_OK(err, "Add bloom filter map to outer map"))
		goto done;

	/* Attach the bloom_filter_inner_map prog */
	link = bpf_program__attach(skel->progs.inner_map);
	if (!ASSERT_OK_PTR(link, "link"))
		goto delete_inner_map;

	syscall(SYS_getpgid);

	ASSERT_EQ(skel->bss->error, 0, "error");

	bpf_link__destroy(link);

delete_inner_map:
	/* Ensure the inner bloom filter map can be deleted */
	err = bpf_map_delete_elem(outer_map_fd, &key);
	ASSERT_OK(err, "Delete inner bloom filter map");

done:
	close(inner_map_fd);
}

static int setup_progs(struct bloom_filter_map **out_skel, __u32 **out_rand_vals,
		       __u32 *out_nr_rand_vals)
{
	struct bloom_filter_map *skel;
	int random_data_fd, bloom_fd;
	__u32 *rand_vals = NULL;
	__u32 map_size, val;
	int err, i;

	/* Set up a bloom filter map skeleton */
	skel = bloom_filter_map__open_and_load();
	if (!ASSERT_OK_PTR(skel, "bloom_filter_map__open_and_load"))
		return -EINVAL;

	/* Set up rand_vals */
	map_size = bpf_map__max_entries(skel->maps.map_random_data);
	rand_vals = malloc(sizeof(*rand_vals) * map_size);
	if (!rand_vals) {
		err = -ENOMEM;
		goto error;
	}

	/* Generate random values and populate both skeletons */
	random_data_fd = bpf_map__fd(skel->maps.map_random_data);
	bloom_fd = bpf_map__fd(skel->maps.map_bloom);
	for (i = 0; i < map_size; i++) {
		val = rand();

		err = bpf_map_update_elem(random_data_fd, &i, &val, BPF_ANY);
		if (!ASSERT_OK(err, "Add random value to map_random_data"))
			goto error;

		err = bpf_map_update_elem(bloom_fd, NULL, &val, BPF_ANY);
		if (!ASSERT_OK(err, "Add random value to map_bloom"))
			goto error;

		rand_vals[i] = val;
	}

	*out_skel = skel;
	*out_rand_vals = rand_vals;
	*out_nr_rand_vals = map_size;

	return 0;

error:
	bloom_filter_map__destroy(skel);
	if (rand_vals)
		free(rand_vals);
	return err;
}

void test_bloom_filter_map(void)
{
	__u32 *rand_vals = NULL, nr_rand_vals = 0;
	struct bloom_filter_map *skel = NULL;
	int err;

	test_fail_cases();
	test_success_cases();

	err = setup_progs(&skel, &rand_vals, &nr_rand_vals);
	if (err)
		return;

	test_inner_map(skel, rand_vals, nr_rand_vals);
	free(rand_vals);

	check_bloom(skel);

	bloom_filter_map__destroy(skel);
}