Skip to content

Commit 2e12f3f

Browse files
tammelakernel-patches-bot
authored andcommitted
bpf: selftests: add tests for batched ops in LPM trie maps
Uses the already existing infrastructure for testing batched ops. The testing code is essentially the same, with minor tweaks for this use case. Suggested-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
1 parent 9ef8858 commit 2e12f3f

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <arpa/inet.h>
4+
#include <linux/bpf.h>
5+
#include <netinet/in.h>
6+
#include <stdio.h>
7+
#include <errno.h>
8+
#include <string.h>
9+
#include <stdlib.h>
10+
11+
#include <bpf/bpf.h>
12+
#include <bpf/libbpf.h>
13+
14+
#include <test_maps.h>
15+
16+
struct test_lpm_key {
17+
__u32 prefix;
18+
struct in_addr ipv4;
19+
};
20+
21+
static void map_batch_update(int map_fd, __u32 max_entries,
22+
struct test_lpm_key *keys, int *values)
23+
{
24+
__u32 i;
25+
int err;
26+
char buff[32] = { 0 };
27+
DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,
28+
.elem_flags = 0,
29+
.flags = 0,
30+
);
31+
32+
for (i = 0; i < max_entries; i++) {
33+
keys[i].prefix = 32;
34+
sprintf(buff, "192.168.1.%d", i + 1);
35+
inet_pton(AF_INET, buff, &keys[i].ipv4);
36+
values[i] = i + 1;
37+
}
38+
39+
err = bpf_map_update_batch(map_fd, keys, values, &max_entries, &opts);
40+
CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno));
41+
}
42+
43+
static void map_batch_verify(int *visited, __u32 max_entries,
44+
struct test_lpm_key *keys, int *values)
45+
{
46+
char buff[32] = { 0 };
47+
__u32 i;
48+
int lower_byte;
49+
50+
memset(visited, 0, max_entries * sizeof(*visited));
51+
for (i = 0; i < max_entries; i++) {
52+
inet_ntop(AF_INET, &keys[i].ipv4, buff, 32);
53+
sscanf(buff, "192.168.1.%d", &lower_byte);
54+
CHECK(lower_byte != values[i], "key/value checking",
55+
"error: i %d key %s value %d\n", i, buff, values[i]);
56+
visited[i] = 1;
57+
}
58+
for (i = 0; i < max_entries; i++) {
59+
CHECK(visited[i] != 1, "visited checking",
60+
"error: keys array at index %d missing\n", i);
61+
}
62+
}
63+
64+
void test_lpm_trie_map_batch_ops(void)
65+
{
66+
struct bpf_create_map_attr xattr = {
67+
.name = "lpm_trie_map",
68+
.map_type = BPF_MAP_TYPE_LPM_TRIE,
69+
.key_size = sizeof(struct test_lpm_key),
70+
.value_size = sizeof(int),
71+
.map_flags = BPF_F_NO_PREALLOC,
72+
};
73+
struct test_lpm_key *keys, key;
74+
int map_fd, *values, *visited;
75+
__u32 step, count, total, total_success;
76+
const __u32 max_entries = 10;
77+
__u64 batch = 0;
78+
int err;
79+
DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,
80+
.elem_flags = 0,
81+
.flags = 0,
82+
);
83+
84+
85+
xattr.max_entries = max_entries;
86+
map_fd = bpf_create_map_xattr(&xattr);
87+
CHECK(map_fd == -1, "bpf_create_map_xattr()", "error:%s\n",
88+
strerror(errno));
89+
90+
keys = malloc(max_entries * sizeof(struct test_lpm_key));
91+
values = malloc(max_entries * sizeof(int));
92+
visited = malloc(max_entries * sizeof(int));
93+
CHECK(!keys || !values || !visited, "malloc()", "error:%s\n",
94+
strerror(errno));
95+
96+
total_success = 0;
97+
for (step = 1; step < max_entries; step++) {
98+
map_batch_update(map_fd, max_entries, keys, values);
99+
map_batch_verify(visited, max_entries, keys, values);
100+
memset(keys, 0, max_entries * sizeof(*keys));
101+
memset(values, 0, max_entries * sizeof(*values));
102+
batch = 0;
103+
total = 0;
104+
/* iteratively lookup/delete elements with 'step'
105+
* elements each.
106+
*/
107+
count = step;
108+
while (true) {
109+
err = bpf_map_lookup_batch(
110+
map_fd, total ? &batch : NULL, &batch,
111+
keys + total, values + total, &count, &opts);
112+
113+
CHECK((err && errno != ENOENT), "lookup with steps",
114+
"error: %s\n", strerror(errno));
115+
116+
total += count;
117+
if (err)
118+
break;
119+
}
120+
121+
CHECK(total != max_entries, "lookup with steps",
122+
"total = %u, max_entries = %u\n", total, max_entries);
123+
124+
map_batch_verify(visited, max_entries, keys, values);
125+
126+
total = 0;
127+
count = step;
128+
while (total < max_entries) {
129+
if (max_entries - total < step)
130+
count = max_entries - total;
131+
err = bpf_map_delete_batch(map_fd, keys + total, &count,
132+
&opts);
133+
CHECK((err && errno != ENOENT), "delete batch",
134+
"error: %s\n", strerror(errno));
135+
total += count;
136+
if (err)
137+
break;
138+
}
139+
CHECK(total != max_entries, "delete with steps",
140+
"total = %u, max_entries = %u\n", total, max_entries);
141+
142+
/* check map is empty, errono == ENOENT */
143+
err = bpf_map_get_next_key(map_fd, NULL, &key);
144+
CHECK(!err || errno != ENOENT, "bpf_map_get_next_key()",
145+
"error: %s\n", strerror(errno));
146+
147+
total_success++;
148+
}
149+
150+
CHECK(total_success == 0, "check total_success",
151+
"unexpected failure\n");
152+
153+
printf("%s:PASS\n", __func__);
154+
155+
free(keys);
156+
free(values);
157+
free(visited);
158+
}

0 commit comments

Comments
 (0)