mirror of https://gitee.com/openkylin/linux.git
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> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20210323025058.315763-3-pctammela@gmail.com
This commit is contained in:
parent
f56387c534
commit
e9bd8cbd97
|
@ -0,0 +1,158 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
|
||||
#include <test_maps.h>
|
||||
|
||||
struct test_lpm_key {
|
||||
__u32 prefix;
|
||||
struct in_addr ipv4;
|
||||
};
|
||||
|
||||
static void map_batch_update(int map_fd, __u32 max_entries,
|
||||
struct test_lpm_key *keys, int *values)
|
||||
{
|
||||
__u32 i;
|
||||
int err;
|
||||
char buff[16] = { 0 };
|
||||
DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,
|
||||
.elem_flags = 0,
|
||||
.flags = 0,
|
||||
);
|
||||
|
||||
for (i = 0; i < max_entries; i++) {
|
||||
keys[i].prefix = 32;
|
||||
snprintf(buff, 16, "192.168.1.%d", i + 1);
|
||||
inet_pton(AF_INET, buff, &keys[i].ipv4);
|
||||
values[i] = i + 1;
|
||||
}
|
||||
|
||||
err = bpf_map_update_batch(map_fd, keys, values, &max_entries, &opts);
|
||||
CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno));
|
||||
}
|
||||
|
||||
static void map_batch_verify(int *visited, __u32 max_entries,
|
||||
struct test_lpm_key *keys, int *values)
|
||||
{
|
||||
char buff[16] = { 0 };
|
||||
int lower_byte = 0;
|
||||
__u32 i;
|
||||
|
||||
memset(visited, 0, max_entries * sizeof(*visited));
|
||||
for (i = 0; i < max_entries; i++) {
|
||||
inet_ntop(AF_INET, &keys[i].ipv4, buff, 32);
|
||||
CHECK(sscanf(buff, "192.168.1.%d", &lower_byte) == EOF,
|
||||
"sscanf()", "error: i %d\n", i);
|
||||
CHECK(lower_byte != values[i], "key/value checking",
|
||||
"error: i %d key %s value %d\n", i, buff, values[i]);
|
||||
visited[i] = 1;
|
||||
}
|
||||
for (i = 0; i < max_entries; i++) {
|
||||
CHECK(visited[i] != 1, "visited checking",
|
||||
"error: keys array at index %d missing\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
void test_lpm_trie_map_batch_ops(void)
|
||||
{
|
||||
struct bpf_create_map_attr xattr = {
|
||||
.name = "lpm_trie_map",
|
||||
.map_type = BPF_MAP_TYPE_LPM_TRIE,
|
||||
.key_size = sizeof(struct test_lpm_key),
|
||||
.value_size = sizeof(int),
|
||||
.map_flags = BPF_F_NO_PREALLOC,
|
||||
};
|
||||
struct test_lpm_key *keys, key;
|
||||
int map_fd, *values, *visited;
|
||||
__u32 step, count, total, total_success;
|
||||
const __u32 max_entries = 10;
|
||||
__u64 batch = 0;
|
||||
int err;
|
||||
DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,
|
||||
.elem_flags = 0,
|
||||
.flags = 0,
|
||||
);
|
||||
|
||||
xattr.max_entries = max_entries;
|
||||
map_fd = bpf_create_map_xattr(&xattr);
|
||||
CHECK(map_fd == -1, "bpf_create_map_xattr()", "error:%s\n",
|
||||
strerror(errno));
|
||||
|
||||
keys = malloc(max_entries * sizeof(struct test_lpm_key));
|
||||
values = malloc(max_entries * sizeof(int));
|
||||
visited = malloc(max_entries * sizeof(int));
|
||||
CHECK(!keys || !values || !visited, "malloc()", "error:%s\n",
|
||||
strerror(errno));
|
||||
|
||||
total_success = 0;
|
||||
for (step = 1; step < max_entries; step++) {
|
||||
map_batch_update(map_fd, max_entries, keys, values);
|
||||
map_batch_verify(visited, max_entries, keys, values);
|
||||
memset(keys, 0, max_entries * sizeof(*keys));
|
||||
memset(values, 0, max_entries * sizeof(*values));
|
||||
batch = 0;
|
||||
total = 0;
|
||||
/* iteratively lookup/delete elements with 'step'
|
||||
* elements each.
|
||||
*/
|
||||
count = step;
|
||||
while (true) {
|
||||
err = bpf_map_lookup_batch(map_fd,
|
||||
total ? &batch : NULL, &batch,
|
||||
keys + total, values + total, &count, &opts);
|
||||
|
||||
CHECK((err && errno != ENOENT), "lookup with steps",
|
||||
"error: %s\n", strerror(errno));
|
||||
|
||||
total += count;
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK(total != max_entries, "lookup with steps",
|
||||
"total = %u, max_entries = %u\n", total, max_entries);
|
||||
|
||||
map_batch_verify(visited, max_entries, keys, values);
|
||||
|
||||
total = 0;
|
||||
count = step;
|
||||
while (total < max_entries) {
|
||||
if (max_entries - total < step)
|
||||
count = max_entries - total;
|
||||
err = bpf_map_delete_batch(map_fd, keys + total, &count,
|
||||
&opts);
|
||||
CHECK((err && errno != ENOENT), "delete batch",
|
||||
"error: %s\n", strerror(errno));
|
||||
total += count;
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
CHECK(total != max_entries, "delete with steps",
|
||||
"total = %u, max_entries = %u\n", total, max_entries);
|
||||
|
||||
/* check map is empty, errono == ENOENT */
|
||||
err = bpf_map_get_next_key(map_fd, NULL, &key);
|
||||
CHECK(!err || errno != ENOENT, "bpf_map_get_next_key()",
|
||||
"error: %s\n", strerror(errno));
|
||||
|
||||
total_success++;
|
||||
}
|
||||
|
||||
CHECK(total_success == 0, "check total_success",
|
||||
"unexpected failure\n");
|
||||
|
||||
printf("%s:PASS\n", __func__);
|
||||
|
||||
free(keys);
|
||||
free(values);
|
||||
free(visited);
|
||||
}
|
Loading…
Reference in New Issue